ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
class.ilDB.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
9//pear MDB2 abstraction layer
10require_once('./Services/Database/lib/PEAR/MDB2.php');
11require_once 'Services/Database/classes/QueryUtils/class.ilMySQLQueryUtils.php';
12require_once 'Services/Database/interfaces/interface.ilDBInterface.php';
13
14//echo "-".ilDBConstants::FETCHMODE_ASSOC."-";
15//echo "+".ilDBConstants::FETCHMODE_OBJECT."+";
16
17
29abstract class ilDB extends PEAR implements ilDBInterface
30{
31 const LOCK_WRITE = 1;
32 const LOCK_READ = 2;
33
34
41
46 public $db;
47
52 public $result;
53
54
55 public $allowed_attributes = array(
56 "text" => array("length", "notnull", "default", "fixed"),
57 "integer" => array("length", "notnull", "default", "unsigned"),
58 "float" => array("notnull", "default"),
59 "date" => array("notnull", "default"),
60 "time" => array("notnull", "default"),
61 "timestamp" => array("notnull", "default"),
62 "clob" => array("notnull", "default"),
63 "blob" => array("notnull", "default")
64 );
65
66 public $sub_type;
67
73 public function setDBUser($a_user)
74 {
75 $this->db_user = $a_user;
76 }
77
83 public function getDBUser()
84 {
85 return $this->db_user;
86 }
87
93 public function setDBPort($a_port)
94 {
95 $this->db_port = $a_port;
96 }
97
103 public function getDBPort()
104 {
105 return $this->db_port;
106 }
107
113 public function setDBHost($a_host)
114 {
115 $this->db_host = $a_host;
116 }
117
123 public function getDBHost()
124 {
125 return $this->db_host;
126 }
127
133 public function setDBPassword($a_password)
134 {
135 $this->db_password = $a_password;
136 }
137
143 public function getDBPassword()
144 {
145 return $this->db_password;
146 }
147
153 public function setDBName($a_name)
154 {
155 $this->db_name = $a_name;
156 }
157
163 public function getDBName()
164 {
165 return $this->db_name;
166 }
167
171 abstract public function getDSN();
172
176 public function getDBVersion()
177 {
178 return "Unknown";
179 }
180
184 abstract public function getDBType();
185
192 public static function getReservedWords()
193 {
194 return array();
195 }
196
197
202 public function enableResultBuffering($a_status)
203 {
204 $this->db->setOption('result_buffering', $a_status);
205 }
206
211 public function initFromIniFile($tmpClientIniFile = null)
212 {
213 global $ilClientIniFile;
214
215 //overwrite global client ini file if local parameter is set
216 if (is_object($tmpClientIniFile)) {
217 $clientIniFile = $tmpClientIniFile;
218 } else {
219 $clientIniFile = $ilClientIniFile;
220 }
221
222 if (is_object($clientIniFile)) {
223 $this->setDBUser($clientIniFile ->readVariable("db", "user"));
224 $this->setDBHost($clientIniFile ->readVariable("db", "host"));
225 $this->setDBPort($clientIniFile ->readVariable("db", "port"));
226 $this->setDBPassword($clientIniFile ->readVariable("db", "pass"));
227 $this->setDBName($clientIniFile ->readVariable("db", "name"));
228 }
229 }
230
234 public function connect($a_return_false_for_error = false)
235 {
236 //set up error handling
237 $this->error_class = new ilErrorHandling();
238 $this->setErrorHandling(PEAR_ERROR_CALLBACK, array($this->error_class,'errorHandler'));
239 //echo $this->getDSN();
240 //check dsn
241 if ($this->getDSN() == "") {
242 $this->raisePearError("No DSN given");
243 }
244
245 //connect to database
246 $this->doConnect();
247
248 if ($a_return_false_for_error && MDB2::isError($this->db)) {
249 return false;
250 }
251
252 $this->loadMDB2Extensions();
253
254 // set empty value portability to PEAR::DB behaviour
255 if (!$this->isDbError($this->db)) {
256 $this->db->setOption('portability', MDB2_PORTABILITY_ALL);
257 }
258 //check error
259 $this->handleError($this->db);
260
261 // anything, that must be done to initialize the connection
262 $this->initConnection();
263
264 return true;
265 }
266
270 public function doConnect()
271 {
272 $this->db = MDB2::connect(
273 $this->getDSN(),
274 array("use_transactions" => true)
275 );
276 }
277
281 public function disconnect()
282 {
283 $this->db->disconnect();
284 }
285
286 //
287 // General and MDB2 related functions
288 //
289
293 protected function initConnection()
294 {
295 }
296
303 public function getHostDSN()
304 {
305 return false;
306 }
307
312 public function connectHost()
313 {
314 //set up error handling
315 $this->error_class = new ilErrorHandling();
316 $this->setErrorHandling(PEAR_ERROR_CALLBACK, array($this->error_class,'errorHandler'));
317
318 //check dsn
319 if ($this->getHostDSN() == "") {
320 $this->raisePearError("No Host DSN given");
321 }
322
323 //connect to database
324 $this->db = MDB2::connect(
325 $this->getHostDSN(),
326 array("use_transactions" => true)
327 );
328 if ($a_return_false_for_error && MDB2::isError($this->db)) {
329 return false;
330 }
331
332 $this->loadMDB2Extensions();
333
334 // set empty value portability to PEAR::DB behaviour
335 if (!$this->isDbError($this->db)) {
336 $cur = ($this->db->getOption("portability") & MDB2_PORTABILITY_EMPTY_TO_NULL);
337 $this->db->setOption("portability", $this->db->getOption("portability") - $cur);
338
339 $cur = ($this->db->getOption("portability") & MDB2_PORTABILITY_FIX_CASE);
340 $this->db->setOption("portability", $this->db->getOption("portability") - $cur);
341 }
342
343 //check error
344 $this->handleError($this->db);
345
346 // anything, that must be done to initialize the connection
347 $this->initHostConnection();
348
349 return true;
350 }
351
355 protected function initHostConnection()
356 {
357 }
358
359 public function supportsFulltext()
360 {
361 return false;
362 }
363
370 public function supportsSlave()
371 {
372 return false;
373 }
374
379 public function supports($feature)
380 {
381 switch ($feature) {
382 case 'transaction':
383 return $this->supportsTransactions();
384 case 'fulltext':
385 return $this->supportsFulltext();
386 case 'slave':
387 return $this->supportsSlave();
388 default:
389 return false;
390 }
391 }
392
393
397 public function supportsTransactions()
398 {
399 // we generally do not want ilDB to support transactions, only PDO-instances
400 return false;
401 }
402
409 public function useSlave($a_val = true)
410 {
411 if (!$this->supportsSlave()) {
412 return false;
413 }
414 $this->use_slave = $a_val;
415 }
416
423 public function handleError($a_res, $a_info = "", $a_level = "")
424 {
425 global $ilLog;
426
427 if (MDB2::isError($a_res)) {
428 if ($a_level == "") {
429 $a_level = $this->error_class->FATAL;
430 }
431
432 // :TODO: ADT (jluetzen)
433
434 // if(!$this->exception)
435 if (true) {
436 // Show stack
437 try {
438 throw new Exception();
439 } catch (Exception $e) {
440 $stack = $e->getTraceAsString();
441 }
442
443 if (is_object($ilLog)) {
444 $ilLog->logStack();
445 }
446 // $this->raisePearError("ilDB Error: " . $a_info . "<br />" . $a_res->getMessage() . "<br />" . $a_res->getUserInfo() . "<br />"
447 // . $stack, $a_level);
448
449 throw new ilDatabaseException("ilDB Error: " . $a_info . "<br />" . $a_res->getMessage() . "<br />" . $a_res->getUserInfo() . "<br />"
450 . $stack, $a_level);
451 }
452 }
453
454 return $a_res;
455 }
456
460 public function raisePearError($a_message, $a_level = "")
461 {
462 if ($a_level == "") {
463 $a_level = $this->error_class->FATAL;
464 }
465 //echo "<br>-ilDB:raising-$a_message-$a_level-";
466 $this->raiseError($a_message, $a_level);
467 }
468
474 protected function loadMDB2Extensions()
475 {
476 if (!$this->isDbError($this->db)) {
477 $this->db->loadModule('Extended');
478 define('DB_AUTOQUERY_SELECT', MDB2_AUTOQUERY_SELECT);
479 define('DB_AUTOQUERY_INSERT', MDB2_AUTOQUERY_INSERT);
480 define('DB_AUTOQUERY_UPDATE', MDB2_AUTOQUERY_UPDATE);
481 define('DB_AUTOQUERY_DELETE', MDB2_AUTOQUERY_DELETE);
482 }
483 }
484
488 public static function isDbError($a_res)
489 {
490 return MDB2::isError($a_res);
491 }
492
493 //
494 // Data Definition Methods
495 //
496
500 public function createDatabase($a_name, $a_charset = "utf8", $a_collation = "")
501 {
502 if ($a_collation != "") {
503 $sql = "CREATE DATABASE " . $a_name .
504 " CHARACTER SET " . $a_charset .
505 " COLLATE " . $a_collation;
506 } else {
507 $sql = "CREATE DATABASE " . $a_name .
508 " CHARACTER SET " . $a_charset;
509 }
510
511 return $this->query($sql, false);
512 }
513
514
522 public function createTable(
523 $a_name,
524 $a_definition_array,
525 $a_drop_table = false,
526 $a_ignore_erros = false
527 ) {
528 // check table name
529 if (!$this->checkTableName($a_name) && !$a_ignore_erros) {
530 $this->raisePearError("ilDB Error: createTable(" . $a_name . ")<br />" .
531 $this->error_str);
532 }
533
534 // check definition array
535 if (!$this->checkTableColumns($a_definition_array) && !$a_ignore_erros) {
536 $this->raisePearError("ilDB Error: createTable(" . $a_name . ")<br />" .
537 $this->error_str);
538 }
539
540 if ($a_drop_table) {
541 $this->dropTable($a_name, false);
542 }
543
545
546 $manager = $this->db->loadModule('Manager');
547 $r = $manager->createTable($a_name, $a_definition_array, $options);
548
549 return $this->handleError($r, "createTable(" . $a_name . ")");
550 }
551
557 protected function getCreateTableOptions()
558 {
559 return array();
560 }
561
568 public function dropTable($a_name, $a_error_if_not_existing = true)
569 {
570 if (!$a_error_if_not_existing) {
571 $tables = $this->listTables();
572 if (!in_array($a_name, $tables)) {
573 return;
574 }
575 }
576
577 $manager = $this->db->loadModule('Manager');
578
579 if ($this->getDBType() == "oracle") {
580 // drop table constraints
581 $constraints = $manager->listTableConstraints($a_name);
582 $this->handleError($constraints, "dropTable(" . $a_name . "), listTableConstraints");
583 foreach ($constraints as $c) {
584 if (substr($c, 0, 4) != "sys_") {
585 $r = $manager->dropConstraint($a_name, $c);
586 $this->handleError($r, "dropTable(" . $a_name . "), dropConstraint");
587 }
588 }
589
590 // drop table indexes
591 $indexes = $manager->listTableIndexes($a_name);
592 $this->handleError($indexes, "dropTable(" . $a_name . "), listTableIndexes");
593 foreach ($indexes as $i) {
594 $r = $manager->dropIndex($a_name, $i);
595 $this->handleError($r, "dropTable(" . $a_name . "), dropIndex");
596 }
597 }
598
599 // drop sequence
600 $seqs = $manager->listSequences();
601 if (in_array($a_name, $seqs)) {
602 $r = $manager->dropSequence($a_name);
603 $this->handleError($r, "dropTable(" . $a_name . "), dropSequence");
604 }
605
606 // drop table
607 $r = $manager->dropTable($a_name);
608
609 return $this->handleError($r, "dropTable(" . $a_name . ")");
610 }
611
617 public function alterTable($a_name, $a_changes)
618 {
619 if ($a_options == "") {
620 $a_options = array();
621 }
622
623 $manager = $this->db->loadModule('Manager');
624 $r = $manager->alterTable($a_name, $a_changes, false);
625
626 return $this->handleError($r, "alterTable(" . $a_name . ")");
627 }
628
637 public function addTableColumn($a_table, $a_column, $a_attributes)
638 {
639 $manager = $this->db->loadModule('Manager');
640
641 if (!$this->checkColumnName($a_column)) {
642 $this->raisePearError("ilDB Error: addTableColumn(" . $a_table . ", " . $a_column . ")<br />" .
643 $this->error_str);
644 }
645 if (!$this->checkColumnDefinition($a_attributes)) {
646 $this->raisePearError("ilDB Error: addTableColumn(" . $a_table . ", " . $a_column . ")<br />" .
647 $this->error_str);
648 }
649
650 $changes = array(
651 "add" => array(
652 $a_column => $a_attributes
653 )
654 );
655
656 $r = $manager->alterTable($a_table, $changes, false);
657
658 return $this->handleError($r, "addTableColumn(" . $a_table . ", " . $a_column . ")");
659 }
660
668 public function dropTableColumn($a_table, $a_column)
669 {
670 $manager = $this->db->loadModule('Manager');
671
672 $changes = array(
673 "remove" => array(
674 $a_column => array()
675 )
676 );
677
678 $r = $manager->alterTable($a_table, $changes, false);
679
680 return $this->handleError($r, "dropTableColumn(" . $a_table . ", " . $a_column . ")");
681 }
682
691 public function modifyTableColumn($a_table, $a_column, $a_attributes)
692 {
693 $manager = $this->db->loadModule('Manager');
694 $reverse = $this->db->loadModule('Reverse');
695 $def = $reverse->getTableFieldDefinition($a_table, $a_column);
696
697 $this->handleError($def, "modifyTableColumn(" . $a_table . ")");
698
699 if (is_file("./Services/Database/classes/class.ilDBAnalyzer.php")) {
700 include_once("./Services/Database/classes/class.ilDBAnalyzer.php");
701 } else {
702 include_once("../Services/Database/classes/class.ilDBAnalyzer.php");
703 }
704 $analyzer = new ilDBAnalyzer();
705 $best_alt = $analyzer->getBestDefinitionAlternative($def);
706 $def = $def[$best_alt];
707 unset($def["nativetype"]);
708 unset($def["mdb2type"]);
709
710 // check attributes
711 $type = ($a_attributes["type"] != "")
712 ? $a_attributes["type"]
713 : $def["type"];
714 foreach ($def as $k => $v) {
715 if ($k != "type" && !in_array($k, $this->allowed_attributes[$type])) {
716 unset($def[$k]);
717 }
718 }
719 $check_array = $def;
720 foreach ($a_attributes as $k => $v) {
721 $check_array[$k] = $v;
722 }
723 if (!$this->checkColumnDefinition($check_array, true)) {
724 $this->raisePearError("ilDB Error: modifyTableColumn(" . $a_table . ", " . $a_column . ")<br />" .
725 $this->error_str);
726 }
727
728 // oracle workaround: do not set null, if null already given
729 if ($this->getDbType() == "oracle") {
730 if ($def["notnull"] == true && ($a_attributes["notnull"] == true
731 || !isset($a_attributes["notnull"]))) {
732 unset($def["notnull"]);
733 unset($a_attributes["notnull"]);
734 }
735 if ($def["notnull"] == false && ($a_attributes["notnull"] == false
736 || !isset($a_attributes["notnull"]))) {
737 unset($def["notnull"]);
738 unset($a_attributes["notnull"]);
739 }
740 }
741 foreach ($a_attributes as $a => $v) {
742 $def[$a] = $v;
743 }
744
745 $a_attributes["definition"] = $def;
746
747 $changes = array(
748 "change" => array(
749 $a_column => $a_attributes
750 )
751 );
752
753 $r = $manager->alterTable($a_table, $changes, false);
754
755 return $this->handleError($r, "modifyTableColumn(" . $a_table . ")");
756 }
757
766 public function renameTableColumn($a_table, $a_column, $a_new_column)
767 {
768 // check table name
769 if (!$this->checkColumnName($a_new_column)) {
770 $this->raisePearError("ilDB Error: renameTableColumn(" . $a_table . "," . $a_column . "," . $a_new_column . ")<br />" .
771 $this->error_str);
772 }
773
774 $manager = $this->db->loadModule('Manager');
775 $reverse = $this->db->loadModule('Reverse');
776 $def = $reverse->getTableFieldDefinition($a_table, $a_column);
777
778 $this->handleError($def, "renameTableColumn(" . $a_table . "," . $a_column . "," . $a_new_column . ")");
779
780 if (is_file("./Services/Database/classes/class.ilDBAnalyzer.php")) {
781 include_once("./Services/Database/classes/class.ilDBAnalyzer.php");
782 } else {
783 include_once("../Services/Database/classes/class.ilDBAnalyzer.php");
784 }
785
786 $analyzer = new ilDBAnalyzer();
787 $best_alt = $analyzer->getBestDefinitionAlternative($def);
788 $def = $def[$best_alt];
789 unset($def["nativetype"]);
790 unset($def["mdb2type"]);
791
792 $f["definition"] = $def;
793 $f["name"] = $a_new_column;
794
795 $changes = array(
796 "rename" => array(
797 $a_column => $f
798 )
799 );
800
801 $r = $manager->alterTable($a_table, $changes, false);
802
803 return $this->handleError($r, "renameTableColumn(" . $a_table . "," . $a_column . "," . $a_new_column . ")");
804 }
805
812 public function renameTable($a_name, $a_new_name)
813 {
814 // check table name
815 if (!$this->checkTableName($a_new_name)) {
816 $this->raisePearError("ilDB Error: renameTable(" . $a_name . "," . $a_new_name . ")<br />" .
817 $this->error_str);
818 }
819
820 $manager = $this->db->loadModule('Manager');
821 $r = $manager->alterTable($a_name, array("name" => $a_new_name), false);
822
823 // The abstraction_progress is no longer used in ILIAS, see http://www.ilias.de/mantis/view.php?id=19513
824 // $query = "UPDATE abstraction_progress ".
825 // "SET table_name = ".$this->db->quote($a_new_name,'text')." ".
826 // "WHERE table_name = ".$this->db->quote($a_name,'text');
827 // $this->db->query($query);
828
829 return $this->handleError($r, "renameTable(" . $a_name . "," . $a_new_name . ")");
830 }
831
839 public function addPrimaryKey($a_table, $a_fields)
840 {
841 $manager = $this->db->loadModule('Manager');
842
843 $fields = array();
844 foreach ($a_fields as $f) {
845 $fields[$f] = array();
846 }
847 $definition = array(
848 'primary' => true,
849 'fields' => $fields
850 );
851 $r = $manager->createConstraint(
852 $a_table,
853 $this->constraintName($a_table, $this->getPrimaryKeyIdentifier()),
854 $definition
855 );
856
857 return $this->handleError($r, "addPrimaryKey(" . $a_table . ")");
858 }
859
863 public function getPrimaryKeyIdentifier()
864 {
865 return "PRIMARY";
866 }
867
874 public function dropPrimaryKey($a_table)
875 {
876 $manager = $this->db->loadModule('Manager');
877
878 $r = $manager->dropConstraint(
879 $a_table,
880 $this->constraintName($a_table, $this->getPrimaryKeyIdentifier()),
881 true
882 );
883
884 return $this->handleError($r, "dropPrimaryKey(" . $a_table . ")");
885 }
886
894 public function addIndex($a_table, $a_fields, $a_name = "in", $a_fulltext = false)
895 {
899 $manager = $this->db->loadModule('Manager');
900
901 // check index name
902 if (!$this->checkIndexName($a_name)) {
903 $this->raisePearError("ilDB Error: addIndex(" . $a_table . "," . $a_name . ")<br />" .
904 $this->error_str);
905 }
906
907 $fields = array();
908 foreach ($a_fields as $f) {
909 $fields[$f] = array();
910 }
911 $definition = array(
912 'fields' => $fields
913 );
914
915 if (!$a_fulltext) {
916 $r = $manager->createIndex($a_table, $this->constraintName($a_table, $a_name), $definition);
917 } else {
918 if ($this->supportsFulltext()) {
919 $this->addFulltextIndex($a_table, $a_fields, $a_name);
920 }
921 }
922
923 return $this->handleError($r, "addIndex(" . $a_table . ")");
924 }
925
929 public function addFulltextIndex($a_table, $a_fields, $a_name = "in")
930 {
931 return false;
932 }
933
937 public function isFulltextIndex($a_table, $a_name)
938 {
939 return false;
940 }
941
942
948 public function indexExistsByFields($a_table, $a_fields)
949 {
950 $manager = $this->db->loadModule('Manager');
951 $reverse = $this->db->loadModule('Reverse');
952 if ($manager) {
953 foreach ($manager->listTableIndexes($a_table) as $idx_name) {
954 $def = $reverse->getTableIndexDefinition($a_table, $idx_name);
955 $idx_fields = array_keys((array) $def['fields']);
956
957 if ($idx_fields === $a_fields) {
958 return true;
959 }
960 }
961 }
962 return false;
963 }
964
971 public function dropIndexByFields($a_table, $a_fields)
972 {
973 $manager = $this->db->loadModule('Manager');
974 $reverse = $this->db->loadModule('Reverse');
975 if ($manager) {
976 foreach ($manager->listTableIndexes($a_table) as $idx_name) {
977 $def = $reverse->getTableIndexDefinition($a_table, $idx_name);
978 $idx_fields = array_keys((array) $def['fields']);
979
980 if ($idx_fields === $a_fields) {
981 return $this->dropIndex($a_table, $idx_name);
982 }
983 }
984 }
985 return false;
986 }
987
995 public function dropIndex($a_table, $a_name = "in")
996 {
997 $manager = $this->db->loadModule('Manager');
998
999 if (!$this->isFulltextIndex($a_table, $a_name)) {
1000 $r = $manager->dropIndex($a_table, $this->constraintName($a_table, $a_name));
1001 } else {
1002 $this->dropFulltextIndex($a_table, $a_name);
1003 }
1004
1005 return $this->handleError($r, "dropIndex(" . $a_table . ")");
1006 }
1007
1015 public function addUniqueConstraint($a_table, $a_fields, $a_name = "con")
1016 {
1017 $manager = $this->db->loadModule('Manager');
1018
1019 // check index name
1020 if (!$this->checkIndexName($a_name)) {
1021 $this->raisePearError("ilDB Error: addUniqueConstraint(" . $a_table . "," . $a_name . ")<br />" .
1022 $this->error_str);
1023 }
1024
1025 $fields = array();
1026 foreach ($a_fields as $f) {
1027 $fields[$f] = array();
1028 }
1029 $definition = array(
1030 'unique' => true,
1031 'fields' => $fields
1032 );
1033
1034 $r = $manager->createConstraint($a_table, $this->constraintName($a_table, $a_name), $definition);
1035
1036 return $this->handleError($r, "addUniqueConstraint(" . $a_table . ")");
1037 }
1038
1046 public function dropUniqueConstraint($a_table, $a_name = "con")
1047 {
1048 $manager = $this->db->loadModule('Manager');
1049
1050 $r = $manager->dropConstraint(
1051 $a_table,
1052 $this->constraintName($a_table, $a_name),
1053 false
1054 );
1055
1056 return $this->handleError($r, "dropUniqueConstraint(" . $a_table . ")");
1057 }
1058
1065 public function dropUniqueConstraintByFields($a_table, $a_fields)
1066 {
1067 if (is_file("./Services/Database/classes/class.ilDBAnalyzer.php")) {
1068 include_once("./Services/Database/classes/class.ilDBAnalyzer.php");
1069 } else {
1070 include_once("../Services/Database/classes/class.ilDBAnalyzer.php");
1071 }
1072 $analyzer = new ilDBAnalyzer();
1073 $cons = $analyzer->getConstraintsInformation($a_table);
1074 foreach ($cons as $c) {
1075 if ($c["type"] == "unique" && count($a_fields) == count($c["fields"])) {
1076 $all_in = true;
1077 foreach ($a_fields as $f) {
1078 if (!isset($c["fields"][$f])) {
1079 $all_in = false;
1080 }
1081 }
1082 if ($all_in) {
1083 return $this->dropUniqueConstraint($a_table, $c['name']);
1084 }
1085 }
1086 }
1087 return false;
1088 }
1089
1093 public function createSequence($a_table_name, $a_start = 1)
1094 {
1095 $manager = $this->db->loadModule('Manager');
1096
1097 $r = $manager->createSequence($a_table_name, $a_start);
1098
1099 return $this->handleError($r, "createSequence(" . $a_table_name . ")");
1100 }
1101
1102
1106 public function dropSequence($a_table_name)
1107 {
1108 $manager = $this->db->loadModule('Manager');
1109
1110 $r = $manager->dropSequence($a_table_name);
1111
1112 return $this->handleError($r, "dropSequence(" . $a_table_name . ")");
1113 }
1114
1120 public function checkTableName($a_name)
1121 {
1122 if (!preg_match("/^[a-z]+[_a-z0-9]*$/", $a_name)) {
1123 $this->error_str = "Table name must only contain _a-z0-9 and must start with a-z.";
1124 return false;
1125 }
1126
1127 if ($this->isReservedWord($a_name)) {
1128 $this->error_str = "Invalid table name '" . $a_name . "' (Reserved Word).";
1129 return false;
1130 }
1131
1132 if (strtolower(substr($a_name, 0, 4)) == "sys_") {
1133 $this->error_str = "Invalid table name '" . $a_name . "'. Name must not start with 'sys_'.";
1134 return false;
1135 }
1136
1137 if (strlen($a_name) > 22) {
1138 $this->error_str = "Invalid table name '" . $a_name . "'. Maximum table identifer length is 22 bytes.";
1139 return false;
1140 }
1141
1142 return true;
1143 }
1144
1150 public function checkTableColumns($a_cols)
1151 {
1152 foreach ($a_cols as $col => $def) {
1153 if (!$this->checkColumn($col, $def)) {
1154 return false;
1155 }
1156 }
1157
1158 return true;
1159 }
1160
1164 public function checkColumn($a_col, $a_def)
1165 {
1166 if (!$this->checkColumnName($a_col)) {
1167 return false;
1168 }
1169
1170 if (!$this->checkColumnDefinition($a_def)) {
1171 return false;
1172 }
1173
1174 return true;
1175 }
1176
1182 public function checkColumnDefinition($a_def, $a_modify_mode = false)
1183 {
1184 // check valid type
1185 if (!in_array($a_def["type"], array("text", "integer", "float", "date", "time", "timestamp", "clob", "blob"))) {
1186 switch ($a_def["type"]) {
1187 case "boolean":
1188 $this->error_str = "Invalid column type '" . $a_def["type"] . "'. Use integer(1) instead.";
1189 break;
1190
1191 case "decimal":
1192 $this->error_str = "Invalid column type '" . $a_def["type"] . "'. Use float or integer instead.";
1193 break;
1194
1195 default:
1196 $this->error_str = "Invalid column type '" . $a_def["type"] . "'. Allowed types are: " .
1197 "text, integer, float, date, time, timestamp, clob and blob.";
1198 }
1199 }
1200
1201 // check used attributes
1203
1204 foreach ($a_def as $k => $v) {
1205 if ($k != "type" && !in_array($k, $allowed_attributes[$a_def["type"]])) {
1206 $this->error_str = "Attribute '" . $k . "' is not allowed for column type '" . $a_def["type"] . "'.";
1207 return false;
1208 }
1209 }
1210
1211 // type specific checks
1212 switch ($a_def["type"]) {
1213 case "text":
1214 if ($a_def["length"] < 1 || $a_def["length"] > 4000) {
1215 if (!$a_modify_mode || isset($a_def["length"])) {
1216 $this->error_str = "Invalid length '" . $a_def["length"] . "' for type text." .
1217 " Length must be >=1 and <= 4000.";
1218 return false;
1219 }
1220 }
1221 break;
1222
1223 case "integer":
1224 if (!in_array($a_def["length"], array(1, 2, 3, 4, 8))) {
1225 if (!$a_modify_mode || isset($a_def["length"])) {
1226 $this->error_str = "Invalid length '" . $a_def["length"] . "' for type integer." .
1227 " Length must be 1, 2, 3, 4 or 8 (bytes).";
1228 return false;
1229 }
1230 }
1231 if ($a_def["unsigned"]) {
1232 $this->error_str = "Unsigned attribut must not be true for type integer.";
1233 return false;
1234 }
1235 break;
1236 }
1237
1238 return true;
1239 }
1240
1246 public function checkColumnName($a_name)
1247 {
1248 if (!preg_match("/^[a-z]+[_a-z0-9]*$/", $a_name)) {
1249 $this->error_str = "Invalid column name '" . $a_name . "'. Column name must only contain _a-z0-9 and must start with a-z.";
1250 return false;
1251 }
1252
1253 if ($this->isReservedWord($a_name)) {
1254 $this->error_str = "Invalid column name '" . $a_name . "' (Reserved Word).";
1255 return false;
1256 }
1257
1258 if (strtolower(substr($a_name, 0, 4)) == "sys_") {
1259 $this->error_str = "Invalid column name '" . $a_name . "'. Name must not start with 'sys_'.";
1260 return false;
1261 }
1262
1263 if (strlen($a_name) > 30) {
1264 $this->error_str = "Invalid column name '" . $a_name . "'. Maximum column identifer length is 30 bytes.";
1265 return false;
1266 }
1267
1268 return true;
1269 }
1270
1276 public function checkIndexName($a_name)
1277 {
1278 if (!preg_match("/^[a-z]+[_a-z0-9]*$/", $a_name)) {
1279 $this->error_str = "Invalid column name '" . $a_name . "'. Column name must only contain _a-z0-9 and must start with a-z.";
1280 return false;
1281 }
1282
1283 if ($this->isReservedWord($a_name)) {
1284 $this->error_str = "Invalid column name '" . $a_name . "' (Reserved Word).";
1285 return false;
1286 }
1287
1288 if (strlen($a_name) > 3) {
1289 $this->error_str = "Invalid index name '" . $a_name . "'. Maximum index identifer length is 3 bytes.";
1290 return false;
1291 }
1292
1293 return true;
1294 }
1295
1296 public function getAllowedAttributes()
1297 {
1299 }
1300
1306 public function constraintName($a_table, $a_constraint)
1307 {
1308 return $a_constraint;
1309 }
1310
1315 public static function isReservedWord($a_word)
1316 {
1317 require_once('./Services/Database/classes/PDO/FieldDefinition/class.ilDBPdoMySQLFieldDefinition.php');
1318 global $DIC;
1319 $ilDBPdoMySQLFieldDefinition = new ilDBPdoMySQLFieldDefinition($DIC['ilDB']);
1320
1321 return $ilDBPdoMySQLFieldDefinition->isReserved($a_word);
1322 }
1323
1324 //
1325 // Data query and manupilation functions
1326 //
1327
1339 public function query($sql, $a_handle_error = true)
1340 {
1341 global $ilBench;
1342
1343 if (is_object($ilBench)) {
1344 $ilBench->startDbBench($sql);
1345 }
1346 $r = $this->db->query($sql);
1347 if (is_object($ilBench)) {
1348 $ilBench->stopDbBench();
1349 }
1350
1351 if ($a_handle_error) {
1352 return $this->handleError($r, "query(" . $sql . ")");
1353 }
1354
1355 return $r;
1356 }
1357
1365 public function queryF($a_query, $a_types, $a_values)
1366 {
1367 if (!is_array($a_types) || !is_array($a_values) ||
1368 count($a_types) != count($a_values)) {
1369 $this->raisePearError("ilDB::queryF: Types and values must be arrays of same size. ($a_query)");
1370 }
1371 $quoted_values = array();
1372 foreach ($a_types as $k => $t) {
1373 $quoted_values[] = $this->quote($a_values[$k], $t);
1374 }
1375 $query = vsprintf($a_query, $quoted_values);
1376
1377 return $this->query($query);
1378 }
1379
1387 public function manipulateF($a_query, $a_types, $a_values)
1388 {
1389 if (!is_array($a_types) || !is_array($a_values) ||
1390 count($a_types) != count($a_values)) {
1391 $this->raisePearError("ilDB::manipulateF: types and values must be arrays of same size. ($a_query)");
1392 }
1393 $quoted_values = array();
1394 foreach ($a_types as $k => $t) {
1395 $quoted_values[] = $this->quote($a_values[$k], $t);
1396 }
1397 $query = vsprintf($a_query, $quoted_values);
1398
1399 return $this->manipulate($query);
1400 }
1401
1405 public function logStatement($sql)
1406 {
1407 $pos1 = strpos(strtolower($sql), "from ");
1408 $table = "";
1409 if ($pos1 > 0) {
1410 $tablef = substr($sql, $pos1+5);
1411 $pos2 = strpos(strtolower($tablef), " ");
1412 if ($pos2 > 0) {
1413 $table =substr($tablef, 0, $pos2);
1414 } else {
1415 $table = $tablef;
1416 }
1417 }
1418 if (trim($table) != "") {
1419 if (!is_array($this->ttt) || !in_array($table, $this->ttt)) {
1420 echo "<br>" . $table;
1421 $this->ttt[] = $table;
1422 }
1423 } else {
1424 echo "<br><b>" . $sql . "</b>";
1425 }
1426 }
1427
1431 public function setLimit($a_limit, $a_offset = 0)
1432 {
1433 $this->db->setLimit($a_limit, $a_offset);
1434 }
1435
1439 public function nextId($a_table_name)
1440 {
1441 // we do not create missing sequences automatically here
1442 // otherwise misspelled statements result in additional tables
1443 // please create sequences explicitly in the db update script
1444 $r = $this->db->nextId($a_table_name, false);
1445
1446 return $this->handleError($r, "nextId(" . $a_table_name . ")");
1447 }
1448
1459 public function manipulate($sql)
1460 {
1461 global $ilBench;
1462
1463 if (is_object($ilBench)) {
1464 $ilBench->startDbBench($sql);
1465 }
1466 $r = $this->db->exec($sql);
1467 if (is_object($ilBench)) {
1468 $ilBench->stopDbBench();
1469 }
1470
1471 return $this->handleError($r, "manipulate(" . $sql . ")");
1472 }
1473
1482 public function prepare($a_query, $a_types = null, $a_result_types = null)
1483 {
1484 $res = $this->db->prepare($a_query, $a_types, $a_result_types);
1485
1486 return $this->handleError($res, "prepare(" . $a_query . ")");
1487 }
1488
1497 public function prepareManip($a_query, $a_types = null)
1498 {
1499 $res = $this->db->prepare($a_query, $a_types, MDB2_PREPARE_MANIP);
1500
1501 return $this->handleError($res, "prepareManip(" . $a_query . ")");
1502 }
1503
1512 public function execute($a_stmt, $a_data = null)
1513 {
1514 $res = $a_stmt->execute($a_data);
1515
1516 return $this->handleError($res, "execute(" . $a_stmt->query . ")");
1517 }
1518
1528 public function executeMultiple($a_stmt, $a_data)
1529 {
1530 $res = $this->db->extended->executeMultiple($a_stmt, $a_data);
1531
1532 return $this->handleError($res, "executeMultiple(" . $a_stmt->query . ")");
1533 }
1534
1541 public function insert($a_table, $a_columns)
1542 {
1543 $fields = array();
1544 $field_values = array();
1545 $placeholders = array();
1546 $types = array();
1547 $values = array();
1548 $lobs = false;
1549 $lob = array();
1550 foreach ($a_columns as $k => $col) {
1551 $fields[] = $k;
1552 $placeholders[] = "%s";
1553 $placeholders2[] = ":$k";
1554 $types[] = $col[0];
1555
1556 // integer auto-typecast (this casts bool values to integer)
1557 if ($col[0] == 'integer' && !is_null($col[1])) {
1558 $col[1] = (int) $col[1];
1559 }
1560
1561 $values[] = $col[1];
1562 $field_values[$k] = $col[1];
1563 if ($col[0] == "blob" || $col[0] == "clob") {
1564 $lobs = true;
1565 $lob[$k] = $k;
1566 }
1567 }
1568 if ($lobs) { // lobs -> use prepare execute (autoexecute broken in PEAR 2.4.1)
1569 $st = $this->db->prepare("INSERT INTO " . $a_table . " (" . implode($fields, ",") . ") VALUES (" .
1570 implode($placeholders2, ",") . ")", $types, MDB2_PREPARE_MANIP, $lob);
1571
1572 $this->handleError($st, "insert / prepare/execute(" . $a_table . ")");
1573
1574 $r = $st->execute($field_values);
1575
1576
1577 //$r = $this->db->extended->autoExecute($a_table, $field_values, MDB2_AUTOQUERY_INSERT, null, $types);
1578 $this->handleError($r, "insert / prepare/execute(" . $a_table . ")");
1579 $this->free($st);
1580 } else { // if no lobs are used, take simple manipulateF
1581 $q = "INSERT INTO " . $a_table . " (" . implode($fields, ",") . ") VALUES (" .
1582 implode($placeholders, ",") . ")";
1583 $r = $this->manipulateF($q, $types, $values);
1584 }
1585 return $r;
1586 }
1587
1596 public function update($a_table, $a_columns, $a_where)
1597 {
1598 $fields = array();
1599 $field_values = array();
1600 $placeholders = array();
1601 $types = array();
1602 $values = array();
1603 $lobs = false;
1604 $lob = array();
1605 foreach ($a_columns as $k => $col) {
1606 $fields[] = $k;
1607 $placeholders[] = "%s";
1608 $placeholders2[] = ":$k";
1609 $types[] = $col[0];
1610
1611 // integer auto-typecast (this casts bool values to integer)
1612 if ($col[0] == 'integer' && !is_null($col[1])) {
1613 $col[1] = (int) $col[1];
1614 }
1615
1616 $values[] = $col[1];
1617 $field_values[$k] = $col[1];
1618 if ($col[0] == "blob" || $col[0] == "clob") {
1619 $lobs = true;
1620 $lob[$k] = $k;
1621 }
1622 }
1623
1624 if ($lobs) {
1625 $q = "UPDATE " . $a_table . " SET ";
1626 $lim = "";
1627 foreach ($fields as $k => $field) {
1628 $q.= $lim . $field . " = " . $placeholders2[$k];
1629 $lim = ", ";
1630 }
1631 $q.= " WHERE ";
1632 $lim = "";
1633 foreach ($a_where as $k => $col) {
1634 $q.= $lim . $k . " = " . $this->quote($col[1], $col[0]);
1635 $lim = " AND ";
1636 }
1637 $st = $this->db->prepare($q, $types, MDB2_PREPARE_MANIP, $lob);
1638 $r = $st->execute($field_values);
1639
1640 //$r = $this->db->extended->autoExecute($a_table, $field_values, MDB2_AUTOQUERY_INSERT, null, $types);
1641 $this->handleError($r, "update / prepare/execute(" . $a_table . ")");
1642 $this->free($st);
1643 } else {
1644 foreach ($a_where as $k => $col) {
1645 $types[] = $col[0];
1646 $values[] = $col[1];
1647 $field_values[$k] = $col;
1648 }
1649 $q = "UPDATE " . $a_table . " SET ";
1650 $lim = "";
1651 foreach ($fields as $k => $field) {
1652 $q.= $lim . $field . " = " . $placeholders[$k];
1653 $lim = ", ";
1654 }
1655 $q.= " WHERE ";
1656 $lim = "";
1657 foreach ($a_where as $k => $col) {
1658 $q.= $lim . $k . " = %s";
1659 $lim = " AND ";
1660 }
1661
1662 $r = $this->manipulateF($q, $types, $values);
1663 }
1664 return $r;
1665 }
1666
1674 public function replace($a_table, $a_pk_columns, $a_other_columns)
1675 {
1676 // this is the mysql implementation
1677 $a_columns = array_merge($a_pk_columns, $a_other_columns);
1678 $fields = array();
1679 $field_values = array();
1680 $placeholders = array();
1681 $types = array();
1682 $values = array();
1683 $lobs = false;
1684 $lob = array();
1685 foreach ($a_columns as $k => $col) {
1686 $fields[] = $k;
1687 $placeholders[] = "%s";
1688 $placeholders2[] = ":$k";
1689 $types[] = $col[0];
1690
1691 // integer auto-typecast (this casts bool values to integer)
1692 if ($col[0] == 'integer' && !is_null($col[1])) {
1693 $col[1] = (int) $col[1];
1694 }
1695
1696 $values[] = $col[1];
1697 $field_values[$k] = $col[1];
1698 if ($col[0] == "blob" || $col[0] == "clob") {
1699 $lobs = true;
1700 $lob[$k] = $k;
1701 }
1702 }
1703 if ($lobs) { // lobs -> use prepare execute (autoexecute broken in PEAR 2.4.1)
1704 $st = $this->db->prepare("REPLACE INTO " . $a_table . " (" . implode($fields, ",") . ") VALUES (" .
1705 implode($placeholders2, ",") . ")", $types, MDB2_PREPARE_MANIP, $lob);
1706 $this->handleError($st, "insert / prepare/execute(" . $a_table . ")");
1707 $r = $st->execute($field_values);
1708 //$r = $this->db->extended->autoExecute($a_table, $field_values, MDB2_AUTOQUERY_INSERT, null, $types);
1709 $this->handleError($r, "insert / prepare/execute(" . $a_table . ")");
1710 $this->free($st);
1711 } else { // if no lobs are used, take simple manipulateF
1712 $q = "REPLACE INTO " . $a_table . " (" . implode($fields, ",") . ") VALUES (" .
1713 implode($placeholders, ",") . ")";
1714 $r = $this->manipulateF($q, $types, $values);
1715 }
1716 return $r;
1717 }
1718
1724 public function fetchAssoc($a_set)
1725 {
1726 return $a_set->fetchRow(ilDBConstants::FETCHMODE_ASSOC);
1727 }
1728
1732 public function free($a_st)
1733 {
1734 return $a_st->free();
1735 }
1736
1742 public function fetchObject($a_set)
1743 {
1744 return $a_set->fetchRow(ilDBConstants::FETCHMODE_OBJECT);
1745 }
1746
1752 public function numRows($a_set)
1753 {
1754 return $a_set->numRows();
1755 }
1756
1757 //
1758 // function and clauses abstraction
1759 //
1760
1772 public function in($a_field, $a_values, $negate = false, $a_type = "")
1773 {
1774 if (count($a_values) == 0) {
1775 // BEGIN fixed mantis #0014191:
1776 //return " 1=2 "; // return a false statement on empty array
1777 return $negate ? ' 1=1 ' : ' 1=2 ';
1778 // END fixed mantis #0014191:
1779 }
1780 if ($a_type == "") { // untyped: used ? for prepare/execute
1781 $str = $a_field . (($negate) ? " NOT" : "") . " IN (?" . str_repeat(",?", count($a_values) - 1) . ")";
1782 } else { // typed, use values for query/manipulate
1783 $str = $a_field . (($negate) ? " NOT" : "") . " IN (";
1784 $sep = "";
1785 foreach ($a_values as $v) {
1786 $str.= $sep . $this->quote($v, $a_type);
1787 $sep = ",";
1788 }
1789 $str.= ")";
1790 }
1791
1792 return $str;
1793 }
1794
1798 public function addTypesToArray($a_arr, $a_type, $a_cnt)
1799 {
1800 if (!is_array($a_arr)) {
1801 $a_arr = array();
1802 }
1803 if ($a_cnt > 0) {
1804 $type_arr = array_fill(0, $a_cnt, $a_type);
1805 } else {
1806 $type_arr = array();
1807 }
1808 return array_merge($a_arr, $type_arr);
1809 }
1810
1815 public function now()
1816 {
1817 return "now()";
1818 }
1819
1820
1830 public function concat(array $a_values, $a_allow_null = true)
1831 {
1832 if (!count($a_values)) {
1833 return ' ';
1834 }
1835
1836 $concat = ' CONCAT(';
1837 $first = true;
1838 foreach ($a_values as $field_info) {
1839 $val = $field_info[0];
1840
1841 if (!$first) {
1842 $concat .= ',';
1843 }
1844
1845 if ($a_allow_null) {
1846 $concat .= 'COALESCE(';
1847 }
1848 $concat .= $val;
1849
1850 if ($a_allow_null) {
1851 $concat .= ",''";
1852 $concat .= ')';
1853 }
1854
1855 $first = false;
1856 }
1857 $concat .= ') ';
1858 return $concat;
1859 }
1860
1867 public function substr($a_exp, $a_pos = 1, $a_len = -1)
1868 {
1869 $lenstr = "";
1870 if ($a_len > -1) {
1871 $lenstr = ", " . $a_len;
1872 }
1873 return " SUBSTR(" . $a_exp . ", " . $a_pos . $lenstr . ") ";
1874 }
1875
1882 public function upper($a_exp)
1883 {
1884 return " UPPER(" . $a_exp . ") ";
1885 }
1886
1893 public function lower($a_exp)
1894 {
1895 return " LOWER(" . $a_exp . ") ";
1896 }
1897
1905 public function locate($a_needle, $a_string, $a_start_pos = 1)
1906 {
1907 $locate = ' LOCATE( ';
1908 $locate .= $a_needle;
1909 $locate .= ',';
1910 $locate .= $a_string;
1911 $locate .= ',';
1912 $locate .= $a_start_pos;
1913 $locate .= ') ';
1914 return $locate;
1915 }
1916
1917
1923 public function like($a_col, $a_type, $a_value = "?", $case_insensitive = true)
1924 {
1925 if (!in_array($a_type, array("text", "clob", "blob"))) {
1926 $this->raisePearError("Like: Invalid column type '" . $a_type . "'.", $this->error_class->FATAL);
1927 }
1928 if ($a_value == "?") {
1929 if ($case_insensitive) {
1930 return "UPPER(" . $a_col . ") LIKE(UPPER(?))";
1931 } else {
1932 return $a_col . " LIKE(?)";
1933 }
1934 } else {
1935 if ($case_insensitive) {
1936 // Always quote as text
1937 return " UPPER(" . $a_col . ") LIKE(UPPER(" . $this->quote($a_value, 'text') . "))";
1938 } else {
1939 // Always quote as text
1940 return " " . $a_col . " LIKE(" . $this->quote($a_value, 'text') . ")";
1941 }
1942 }
1943 }
1944
1945
1949 public function equals($a_col, $a_value, $a_type, $a_empty_or_null = false)
1950 {
1951 if (!$a_empty_or_null || $a_value != "") {
1952 return $a_col . " = " . $this->quote($a_value, $a_type);
1953 } else {
1954 return "(" . $a_col . " = '' OR $a_col IS NULL)";
1955 }
1956 }
1957
1961 public function equalsNot($a_col, $a_value, $a_type, $a_empty_or_null = false)
1962 {
1963 if (!$a_empty_or_null) {
1964 return $a_col . " <> " . $this->quote($a_value, $a_type);
1965 }
1966 if ($a_value != "") {
1967 return "(" . $a_col . " <> " . $this->quote($a_value, $a_type) . " OR " .
1968 $a_col . " IS NULL)";
1969 } else {
1970 return "(" . $a_col . " <> '' AND $a_col IS NOT NULL)";
1971 }
1972 }
1973
1980 public function fromUnixtime($a_expr, $a_to_text = true)
1981 {
1982 return "FROM_UNIXTIME(" . $a_expr . ")";
1983 }
1984
1988 public function unixTimestamp()
1989 {
1990 return "UNIX_TIMESTAMP()";
1991 }
1992
1993
1994 //
1995 // Schema related functions
1996 //
1997
2004 public function tableExists($a_table)
2005 {
2006 $tables = $this->listTables();
2007
2008 if (is_array($tables)) {
2009 if (in_array($a_table, $tables)) {
2010 return true;
2011 }
2012 }
2013 return false;
2014 }
2015
2023 public function tableColumnExists($a_table, $a_column_name)
2024 {
2025 $column_visibility = false;
2026 $manager = $this->db->loadModule('Manager');
2027 $r = $manager->listTableFields($a_table);
2028
2029 if (!MDB2::isError($r)) {
2030 foreach ($r as $field) {
2031 if ($field == $a_column_name) {
2032 $column_visibility = true;
2033 }
2034 }
2035 }
2036
2037 return $column_visibility;
2038 }
2039
2047 public function uniqueConstraintExists($a_table, array $a_fields)
2048 {
2049 if (is_file("./Services/Database/classes/class.ilDBAnalyzer.php")) {
2050 include_once("./Services/Database/classes/class.ilDBAnalyzer.php");
2051 } else {
2052 include_once("../Services/Database/classes/class.ilDBAnalyzer.php");
2053 }
2054 $analyzer = new ilDBAnalyzer();
2055 $cons = $analyzer->getConstraintsInformation($a_table);
2056 foreach ($cons as $c) {
2057 if ($c["type"] == "unique" && count($a_fields) == count($c["fields"])) {
2058 $all_in = true;
2059 foreach ($a_fields as $f) {
2060 if (!isset($c["fields"][$f])) {
2061 $all_in = false;
2062 }
2063 }
2064 if ($all_in) {
2065 return true;
2066 }
2067 }
2068 }
2069 return false;
2070 }
2071
2072
2078 public function listTables()
2079 {
2080 $manager = $this->db->loadModule('Manager');
2081 $r = $manager->listTables();
2082
2083 if (!MDB2::isError($r)) {
2084 return $r;
2085 }
2086
2087 return false;
2088 }
2089
2096 public function sequenceExists($a_sequence)
2097 {
2098 $sequences = $this->listSequences();
2099
2100 if (is_array($sequences)) {
2101 if (in_array($a_sequence, $sequences)) {
2102 return true;
2103 }
2104 }
2105 return false;
2106 }
2107
2113 public function listSequences()
2114 {
2115 $manager = $this->db->loadModule('Manager');
2116 $r = $manager->listSequences();
2117
2118 if (!MDB2::isError($r)) {
2119 return $r;
2120 }
2121
2122 return false;
2123 }
2124
2125
2126 //
2127 // Quote Functions
2128 //
2129
2133 public function quote($a_query, $a_type = null)
2134 {
2135 if ($a_query == "" && is_null($a_type)) {
2136 $a_query = "";
2137 }
2138
2139 // Performance fix
2140 if ($a_type == 'integer' && !is_null($a_query)) {
2141 return (int) $a_query;
2142 }
2143
2144 if ($a_type == "blob" || $a_type == "clob") {
2145 $this->raisePearError("ilDB::quote: Quoting not allowed on type '" . $a_type . "'. Please use ilDB->insert and ilDB->update to write clobs.", $this->error_class->FATAL);
2146 }
2147
2148 return $this->db->quote($a_query, $a_type);
2149 }
2150
2158 public function quoteIdentifier($a_identifier, $check_option = false)
2159 {
2160 return $this->db->quoteIdentifier($a_identifier);
2161 }
2162
2163
2164 //
2165 // Transaction and Locking methods
2166 //
2167
2173 public function beginTransaction()
2174 {
2175 if (!$this->db->supports('transactions')) {
2176 $this->raisePearError("ilDB::beginTransaction: Transactions are not supported.", $this->error_class->FATAL);
2177 }
2178 $res = $this->db->beginTransaction();
2179
2180 return $this->handleError($res, "beginTransaction()");
2181 }
2182
2186 public function commit()
2187 {
2188 $res = $this->db->commit();
2189
2190 return $this->handleError($res, "commit()");
2191 }
2192
2196 public function rollback()
2197 {
2198 $res = $this->db->rollback();
2199
2200 return $this->handleError($res, "rollback()");
2201 }
2202
2209 abstract public function lockTables($a_tables);
2210
2216 abstract public function unlockTables();
2217
2218
2219//
2220//
2221 // Older functions. Must be checked.
2222//
2223//
2224
2233 public function autoExecute($a_tablename, $a_fields, $a_mode = MDB2_AUTOQUERY_INSERT, $a_where = false)
2234 {
2235 $res = $this->db->autoExecute($a_tablename, $a_fields, $a_mode, $a_where);
2236
2237 return $this->handleError($res, "autoExecute(" . $a_tablename . ")");
2238 }
2239
2240//
2241//
2242 // Deprecated functions.
2243//
2244//
2245
2249 public function getLastInsertId()
2250 {
2251 $res = $this->db->lastInsertId();
2252 if (MDB2::isError($res)) {
2253 return false;
2254 }
2255 return $res;
2256 }
2257
2267 public function getOne($sql)
2268 {
2269 //$r = $this->db->getOne($sql);
2270 $set = $this->db->query($sql);
2271
2272 $this->handleError($set, "getOne(" . $sql . ")");
2273
2274 if (!MDB2::isError($set)) {
2275 $r = $set->fetchRow(ilDBConstants::FETCHMODE_ASSOC);
2276
2277 return $r[0];
2278 }
2279 }
2280
2290 public function getRow($sql, $mode = ilDBConstants::FETCHMODE_OBJECT)
2291 {
2292 $set = $this->query($sql);
2293 $r = $set->fetchRow($mode);
2294 //$r = $this->db->getrow($sql,$mode);
2295
2296 $this->handleError($r, "getRow(" . $sql . ")");
2297
2298 return $r;
2299 } //end function
2300
2306 public function fetchAll($query_result, $fetch_mode = ilDBConstants::FETCHMODE_ASSOC)
2307 {
2311 $return = array();
2312 while ($data = $query_result->fetch($fetch_mode)) {
2313 $return[] = $data;
2314 }
2315
2316 return $return;
2317 }
2318
2324 public function setSubType($a_value)
2325 {
2326 $this->sub_type = (string) $a_value;
2327 }
2328
2334 public function getSubType()
2335 {
2336 return $this->sub_type;
2337 }
2338
2339
2346 {
2347 return array();
2348 }
2349
2350
2354 public function supportsEngineMigration()
2355 {
2356 return false;
2357 }
2358
2359
2364 public function getSequenceName($table_name)
2365 {
2366 return $this->db->getSequenceName($table_name);
2367 }
2368
2369
2373 public function buildAtomQuery()
2374 {
2375 require_once('./Services/Database/classes/Atom/class.ilAtomQueryLock.php');
2376
2377 return new ilAtomQueryLock($this);
2378 }
2379
2380
2385 {
2386 if (!$this->doesCollationSupportMB4Strings()) {
2387 $query_replaced = preg_replace(
2388 '/[\x{10000}-\x{10FFFF}]/u',
2390 $query
2391 );
2392 if (!empty($query_replaced)) {
2393 return $query_replaced;
2394 }
2395 }
2396
2397 return $query;
2398 }
2399
2400
2405 {
2406 return false;
2407 }
2408
2409
2413 public function cast($a_field_name, $a_dest_type)
2414 {
2415 $manager = $this->db->loadModule('Manager');
2416 return $manager->getQueryUtils()->cast($a_field_name, $a_dest_type);
2417 }
2418}
const MDB2_AUTOQUERY_UPDATE
Definition: Extended.php:57
const MDB2_AUTOQUERY_SELECT
Definition: Extended.php:59
const MDB2_AUTOQUERY_INSERT
Used by autoPrepare()
Definition: Extended.php:56
const MDB2_AUTOQUERY_DELETE
Definition: Extended.php:58
const MDB2_PORTABILITY_ALL
Portability: turn on all portability features.
Definition: MDB2.php:215
const MDB2_PORTABILITY_FIX_CASE
Portability: convert names of tables and fields to case defined in the "field_case" option when using...
Definition: MDB2.php:163
const MDB2_PREPARE_MANIP
These are just helper constants to more verbosely express parameters to prepare()
Definition: MDB2.php:114
const MDB2_PORTABILITY_EMPTY_TO_NULL
Portability: convert empty values to null strings in data output by query*() and fetch*().
Definition: MDB2.php:203
const PEAR_ERROR_CALLBACK
Definition: PEAR.php:35
if(!isset( $_REQUEST[ 'ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
An exception for terminatinating execution or to throw for unit testing.
isError($data, $code=null)
Tell whether a value is a MDB2 error.
Definition: MDB2.php:599
& connect($dsn, $options=false)
Create a new MDB2 connection object and connect to the specified database.
Definition: MDB2.php:436
static setErrorHandling($mode=null, $options=null)
Sets how errors generated by this object should be handled.
Definition: PEAR.php:337
& raiseError($message=null, $code=null, $mode=null, $options=null, $userinfo=null, $error_class=null, $skipmsg=false)
This method is a wrapper that returns an instance of the configured error class with this object's de...
Definition: PEAR.php:522
readVariable($a_group, $a_var_name)
reads a single variable from a group @access public
Class ilAtomQueryLock.
This class gives all kind of DB information using the MDB2 manager and reverse module.
Class ilDBPdoMySQLFieldDefinition.
Database Wrapper.
Definition: class.ilDB.php:30
replace($a_table, $a_pk_columns, $a_other_columns)
Replace into method.
lockTables($a_tables)
Abstraction of lock table.
listTables()
Get all tables.
lower($a_exp)
Upper.
const LOCK_WRITE
Definition: class.ilDB.php:31
supports($feature)
Definition: class.ilDB.php:379
tableColumnExists($a_table, $a_column_name)
Checks for the existence of a table column.
equals($a_col, $a_value, $a_type, $a_empty_or_null=false)
Use this only on text fields.
initFromIniFile($tmpClientIniFile=null)
Init db parameters from ini file.
Definition: class.ilDB.php:211
executeMultiple($a_stmt, $a_data)
Execute a query statement prepared by either prepare() or prepareManip() with multiple data arrays.
manipulate($sql)
Data manipulation.
fetchObject($a_set)
Fetch row as object from result set.
upper($a_exp)
Upper.
setSubType($a_value)
Set sub type.
checkTableColumns($a_cols)
Check table columns definition.
doesCollationSupportMB4Strings()
@inheritDoc
connectHost()
Sets up a host connection only (no specific database used).
Definition: class.ilDB.php:312
createSequence($a_table_name, $a_start=1)
Create a sequence for a table.
enableResultBuffering($a_status)
En/disable result buffering.
Definition: class.ilDB.php:202
$error_class
Definition: class.ilDB.php:40
supportsTransactions()
Definition: class.ilDB.php:397
getRow($sql, $mode=ilDBConstants::FETCHMODE_OBJECT)
getRow.
addTableColumn($a_table, $a_column, $a_attributes)
Add table column Use this only on aleady "abstracted" tables.
Definition: class.ilDB.php:637
getDBPort()
Get database port.
Definition: class.ilDB.php:103
update($a_table, $a_columns, $a_where)
Convenient method for standard update statements, example field array:
getPrimaryKeyIdentifier()
Primary key identifier.
Definition: class.ilDB.php:863
now()
now()
getLastInsertId()
Get last insert id.
$allowed_attributes
Definition: class.ilDB.php:55
disconnect()
Disconnect.
Definition: class.ilDB.php:281
rollback()
Rollback a transaction.
dropSequence($a_table_name)
Drop a sequence for a table.
connect($a_return_false_for_error=false)
Open the connection.
Definition: class.ilDB.php:234
renameTable($a_name, $a_new_name)
Rename a table.
Definition: class.ilDB.php:812
dropPrimaryKey($a_table)
Drop a primary key from a table.
Definition: class.ilDB.php:874
tableExists($a_table)
Check, whether a given table exists.
queryF($a_query, $a_types, $a_values)
Formatted query (for SELECTS).
in($a_field, $a_values, $negate=false, $a_type="")
Get abstract in-clause for given array.
getDSN()
Get DSN.
static isReservedWord($a_word)
Checks whether a word is a reserved word in one of the supported databases.
handleError($a_res, $a_info="", $a_level="")
Handle MDB2 Errors.
Definition: class.ilDB.php:423
nextId($a_table_name)
Get next ID for an index.
modifyTableColumn($a_table, $a_column, $a_attributes)
Modify a table column Use this only on aleady "abstracted" tables.
Definition: class.ilDB.php:691
getDBUser()
Get database user.
Definition: class.ilDB.php:83
unixTimestamp()
Unix timestamp.
getDBName()
Get database name.
Definition: class.ilDB.php:163
constraintName($a_table, $a_constraint)
Determine contraint name by table name and constraint name.
doConnect()
Standard way to connect to db.
Definition: class.ilDB.php:270
addTypesToArray($a_arr, $a_type, $a_cnt)
Adds a type x times to an array.
manipulateF($a_query, $a_types, $a_values)
Formatted manupulate (for DELETE, UPDATE, INSERT).
free($a_st)
Free a statement / result set.
getDBType()
Get DSN.
checkIndexName($a_name)
Check whether an index name is valid.
setDBUser($a_user)
Set database user.
Definition: class.ilDB.php:73
createTable( $a_name, $a_definition_array, $a_drop_table=false, $a_ignore_erros=false)
Create a new table in the database.
Definition: class.ilDB.php:522
supportsSlave()
Supports slave.
Definition: class.ilDB.php:370
sanitizeMB4StringIfNotSupported($query)
string sanitized query
getDBVersion()
Get DB version.
Definition: class.ilDB.php:176
checkTableName($a_name)
Check whether a table name is valid.
static getReservedWords()
Get reserved words.
Definition: class.ilDB.php:192
createDatabase($a_name, $a_charset="utf8", $a_collation="")
Create database.
Definition: class.ilDB.php:500
dropUniqueConstraint($a_table, $a_name="con")
Drop a constraint from a table.
renameTableColumn($a_table, $a_column, $a_new_column)
Rename a table column Use this only on aleady "abstracted" tables.
Definition: class.ilDB.php:766
like($a_col, $a_type, $a_value="?", $case_insensitive=true)
Like.
numRows($a_set)
Fetch row as associative array from result set.
equalsNot($a_col, $a_value, $a_type, $a_empty_or_null=false)
Use this only on text fields.
cast($a_field_name, $a_dest_type)
@inheritDoc
setLimit($a_limit, $a_offset=0)
Set limit and offset for a query.
checkColumnDefinition($a_def, $a_modify_mode=false)
Check whether a column definition is valid.
query($sql, $a_handle_error=true)
Query.
insert($a_table, $a_columns)
Convenient method for standard insert statements, example field array:
supportsEngineMigration()
isFulltextIndex($a_table, $a_name)
Is index a fulltext index?
Definition: class.ilDB.php:937
setDBPort($a_port)
Set database port.
Definition: class.ilDB.php:93
initHostConnection()
Initialize the host connection (no specific database)
Definition: class.ilDB.php:355
concat(array $a_values, $a_allow_null=true)
Abstraction of SQL function CONCAT.
dropUniqueConstraintByFields($a_table, $a_fields)
Drop constraint by field(s)
getCreateTableOptions()
Get options for the create table statement.
Definition: class.ilDB.php:557
addUniqueConstraint($a_table, $a_fields, $a_name="con")
Add a unique constraint to a table.
quoteIdentifier($a_identifier, $check_option=false)
Quote table and field names.
logStatement($sql)
Helper function, should usually not be called.
dropTable($a_name, $a_error_if_not_existing=true)
Drop a table.
Definition: class.ilDB.php:568
static isDbError($a_res)
Check error.
Definition: class.ilDB.php:488
alterTable($a_name, $a_changes)
Alter a table in the database This method is DEPRECATED, see http://www.ilias.de/docu/goto....
Definition: class.ilDB.php:617
getAllowedAttributes()
commit()
Commit a transaction.
getSequenceName($table_name)
checkColumnName($a_name)
Check whether a column name is valid.
const LOCK_READ
Definition: class.ilDB.php:32
setDBName($a_name)
Set database name.
Definition: class.ilDB.php:153
checkColumn($a_col, $a_def)
Check column definition.
uniqueConstraintExists($a_table, array $a_fields)
Checks if a unique constraint exists based on the fields of the unique constraint (not the name)
getSubType()
Get sub type.
dropIndex($a_table, $a_name="in")
Drop an index from a table.
Definition: class.ilDB.php:995
beginTransaction()
Begin Transaction.
migrateAllTablesToEngine($engine=ilDBConstants::MYSQL_ENGINE_INNODB)
raisePearError($a_message, $a_level="")
Raise an error.
Definition: class.ilDB.php:460
getOne($sql)
getOne.
prepare($a_query, $a_types=null, $a_result_types=null)
Prepare a query (SELECT) statement to be used with execute.
setDBHost($a_host)
Set database host.
Definition: class.ilDB.php:113
buildAtomQuery()
addPrimaryKey($a_table, $a_fields)
Add a primary key to a table.
Definition: class.ilDB.php:839
execute($a_stmt, $a_data=null)
Execute a query statement prepared by either prepare() or prepareManip()
fetchAssoc($a_set)
Fetch row as associative array from result set.
getDBPassword()
Get database password.
Definition: class.ilDB.php:143
substr($a_exp, $a_pos=1, $a_len=-1)
Substring.
indexExistsByFields($a_table, $a_fields)
Check if index exists.
Definition: class.ilDB.php:948
sequenceExists($a_sequence)
Check, whether a given sequence exists.
fromUnixtime($a_expr, $a_to_text=true)
fromUnixtime (makes timestamp out of unix timestamp)
dropIndexByFields($a_table, $a_fields)
Drop index by field(s)
Definition: class.ilDB.php:971
addFulltextIndex($a_table, $a_fields, $a_name="in")
Add fulltext index.
Definition: class.ilDB.php:929
useSlave($a_val=true)
Use slave.
Definition: class.ilDB.php:409
getHostDSN()
Should return a valid value, if host connections are possible (connectHost) to create a new database ...
Definition: class.ilDB.php:303
unlockTables()
Unlock tables locked by previous lock table calls.
getDBHost()
Get database host.
Definition: class.ilDB.php:123
autoExecute($a_tablename, $a_fields, $a_mode=MDB2_AUTOQUERY_INSERT, $a_where=false)
Wrapper for Pear autoExecute.
listSequences()
Get all sequences.
supportsFulltext()
Definition: class.ilDB.php:359
dropTableColumn($a_table, $a_column)
Drop table column Use this only on aleady "abstracted" tables.
Definition: class.ilDB.php:668
$sub_type
Definition: class.ilDB.php:66
locate($a_needle, $a_string, $a_start_pos=1)
Create locate string.
initConnection()
Initialize the database connection.
Definition: class.ilDB.php:293
setDBPassword($a_password)
Set database password.
Definition: class.ilDB.php:133
prepareManip($a_query, $a_types=null)
Prepare a data manipulation statement to be used with execute.
quote($a_query, $a_type=null)
Wrapper for quote method.
loadMDB2Extensions()
load additional mdb2 extensions and set their constants
Definition: class.ilDB.php:474
Class ilDatabaseException.
$def
Definition: croninfo.php:21
$i
Definition: disco.tpl.php:19
$r
Definition: example_031.php:79
global $ilBench
Definition: ilias.php:18
Interface ilDBInterface.
dropFulltextIndex($a_table, $a_name)
addIndex($table_name, $fields, $index_name='', $fulltext=false)
fetchAll($query_result, $fetch_mode=ilDBConstants::FETCHMODE_ASSOC)
$query
$type
if(empty($password)) $table
Definition: pwgen.php:24
global $DIC
Definition: saml.php:7
foreach($_POST as $key=> $value) $res
$engine
Definition: workflow.php:89
$a_type
Definition: workflow.php:92