ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
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 var $db;
47
53
54
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
67
73 function setDBUser($a_user)
74 {
75 $this->db_user = $a_user;
76 }
77
83 function getDBUser()
84 {
85 return $this->db_user;
86 }
87
93 function setDBPort($a_port)
94 {
95 $this->db_port = $a_port;
96 }
97
103 function getDBPort()
104 {
105 return $this->db_port;
106 }
107
113 function setDBHost($a_host)
114 {
115 $this->db_host = $a_host;
116 }
117
123 function getDBHost()
124 {
125 return $this->db_host;
126 }
127
133 function setDBPassword($a_password)
134 {
135 $this->db_password = $a_password;
136 }
137
143 function getDBPassword()
144 {
145 return $this->db_password;
146 }
147
153 function setDBName($a_name)
154 {
155 $this->db_name = $a_name;
156 }
157
163 function getDBName()
164 {
165 return $this->db_name;
166 }
167
171 abstract function getDSN();
172
176 function getDBVersion()
177 {
178 return "Unknown";
179 }
180
184 abstract function getDBType();
185
192 static function getReservedWords(){
193 return array();
194 }
195
196
201 public function enableResultBuffering($a_status)
202 {
203 $this->db->setOption('result_buffering',$a_status);
204 }
205
210 function initFromIniFile($tmpClientIniFile = null)
211 {
212 global $ilClientIniFile;
213
214 //overwrite global client ini file if local parameter is set
215 if (is_object($tmpClientIniFile))
216 $clientIniFile = $tmpClientIniFile;
217 else
218 $clientIniFile = $ilClientIniFile;
219
220 if (is_object($clientIniFile ))
221 {
222 $this->setDBUser($clientIniFile ->readVariable("db", "user"));
223 $this->setDBHost($clientIniFile ->readVariable("db", "host"));
224 $this->setDBPort($clientIniFile ->readVariable("db", "port"));
225 $this->setDBPassword($clientIniFile ->readVariable("db", "pass"));
226 $this->setDBName($clientIniFile ->readVariable("db", "name"));
227 }
228 }
229
233 function connect($a_return_false_for_error = false)
234 {
235 //set up error handling
236 $this->error_class = new ilErrorHandling();
237 $this->setErrorHandling(PEAR_ERROR_CALLBACK, array($this->error_class,'errorHandler'));
238//echo $this->getDSN();
239 //check dsn
240 if ($this->getDSN() == "")
241 {
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 {
250 return false;
251 }
252
253 $this->loadMDB2Extensions();
254
255 // set empty value portability to PEAR::DB behaviour
256 if (!$this->isDbError($this->db))
257 {
258 $this->db->setOption('portability', MDB2_PORTABILITY_ALL);
259 }
260 //check error
261 $this->handleError($this->db);
262
263 // anything, that must be done to initialize the connection
264 $this->initConnection();
265
266 return true;
267 }
268
272 function doConnect()
273 {
274 $this->db = MDB2::connect($this->getDSN(),
275 array("use_transactions" => true));
276 }
277
281 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 function getHostDSN()
304 {
305 return false;
306 }
307
312 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 {
321 $this->raisePearError("No Host DSN given");
322 }
323
324 //connect to database
325 $this->db = MDB2::connect($this->getHostDSN(),
326 array("use_transactions" => true));
327 if ($a_return_false_for_error && MDB2::isError($this->db))
328 {
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 {
337 $cur = ($this->db->getOption("portability") & MDB2_PORTABILITY_EMPTY_TO_NULL);
338 $this->db->setOption("portability", $this->db->getOption("portability") - $cur);
339
340 $cur = ($this->db->getOption("portability") & MDB2_PORTABILITY_FIX_CASE);
341 $this->db->setOption("portability", $this->db->getOption("portability") - $cur);
342 }
343
344 //check error
345 $this->handleError($this->db);
346
347 // anything, that must be done to initialize the connection
348 $this->initHostConnection();
349
350 return true;
351 }
352
356 protected function initHostConnection()
357 {
358 }
359
361 {
362 return false;
363 }
364
371 function supportsSlave()
372 {
373 return false;
374 }
375
380 public function supports($feature) {
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 // we generally do not want ilDB to support transactions, only PDO-instances
399 return false;
400 }
401
408 function useSlave($a_val = true)
409 {
410 if (!$this->supportsSlave())
411 {
412 return false;
413 }
414 $this->use_slave = $a_val;
415 }
416
423 function handleError($a_res, $a_info = "", $a_level = "") {
424 global $ilLog;
425
426 if (MDB2::isError($a_res)) {
427 if ($a_level == "") {
428 $a_level = $this->error_class->FATAL;
429 }
430
431 // :TODO: ADT (jluetzen)
432
433 // if(!$this->exception)
434 if (true) {
435 // Show stack
436 try {
437 throw new Exception();
438 } catch (Exception $e) {
439 $stack = $e->getTraceAsString();
440 }
441
442 if (is_object($ilLog)) {
443 $ilLog->logStack();
444 }
445// $this->raisePearError("ilDB Error: " . $a_info . "<br />" . $a_res->getMessage() . "<br />" . $a_res->getUserInfo() . "<br />"
446// . $stack, $a_level);
447
448 throw new ilDatabaseException("ilDB Error: " . $a_info . "<br />" . $a_res->getMessage() . "<br />" . $a_res->getUserInfo() . "<br />"
449 . $stack, $a_level);
450 }
451 }
452
453 return $a_res;
454 }
455
459 function raisePearError($a_message, $a_level = "")
460 {
461 if ($a_level == "")
462 {
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 {
478 $this->db->loadModule('Extended');
479 define('DB_AUTOQUERY_SELECT',MDB2_AUTOQUERY_SELECT);
480 define('DB_AUTOQUERY_INSERT',MDB2_AUTOQUERY_INSERT);
481 define('DB_AUTOQUERY_UPDATE',MDB2_AUTOQUERY_UPDATE);
482 define('DB_AUTOQUERY_DELETE',MDB2_AUTOQUERY_DELETE);
483 }
484 }
485
489 static function isDbError($a_res)
490 {
491 return MDB2::isError($a_res);
492 }
493
494 //
495 // Data Definition Methods
496 //
497
501 function createDatabase($a_name, $a_charset = "utf8", $a_collation = "")
502 {
503 if ($a_collation != "")
504 {
505 $sql = "CREATE DATABASE ".$a_name.
506 " CHARACTER SET ".$a_charset.
507 " COLLATE ".$a_collation;
508 }
509 else
510 {
511 $sql = "CREATE DATABASE ".$a_name.
512 " CHARACTER SET ".$a_charset;
513 }
514
515 return $this->query($sql, false);
516 }
517
518
526 function createTable($a_name, $a_definition_array, $a_drop_table = false,
527 $a_ignore_erros = false)
528 {
529 // check table name
530 if (!$this->checkTableName($a_name) && !$a_ignore_erros)
531 {
532 $this->raisePearError("ilDB Error: createTable(".$a_name.")<br />".
533 $this->error_str);
534 }
535
536 // check definition array
537 if (!$this->checkTableColumns($a_definition_array) && !$a_ignore_erros)
538 {
539 $this->raisePearError("ilDB Error: createTable(".$a_name.")<br />".
540 $this->error_str);
541 }
542
543 if ($a_drop_table)
544 {
545 $this->dropTable($a_name, false);
546 }
547
549
550 $manager = $this->db->loadModule('Manager');
551 $r = $manager->createTable($a_name, $a_definition_array, $options);
552
553 return $this->handleError($r, "createTable(".$a_name.")");
554 }
555
561 protected function getCreateTableOptions()
562 {
563 return array();
564 }
565
572 function dropTable($a_name, $a_error_if_not_existing = true)
573 {
574 if (!$a_error_if_not_existing)
575 {
576 $tables = $this->listTables();
577 if (!in_array($a_name, $tables))
578 {
579 return;
580 }
581 }
582
583 $manager = $this->db->loadModule('Manager');
584
585 if ($this->getDBType() == "oracle")
586 {
587 // drop table constraints
588 $constraints = $manager->listTableConstraints($a_name);
589 $this->handleError($constraints, "dropTable(".$a_name."), listTableConstraints");
590 foreach ($constraints as $c)
591 {
592 if (substr($c, 0, 4) != "sys_")
593 {
594 $r = $manager->dropConstraint($a_name, $c);
595 $this->handleError($r, "dropTable(".$a_name."), dropConstraint");
596 }
597 }
598
599 // drop table indexes
600 $indexes = $manager->listTableIndexes($a_name);
601 $this->handleError($indexes, "dropTable(".$a_name."), listTableIndexes");
602 foreach ($indexes as $i)
603 {
604 $r = $manager->dropIndex($a_name, $i);
605 $this->handleError($r, "dropTable(".$a_name."), dropIndex");
606 }
607 }
608
609 // drop sequence
610 $seqs = $manager->listSequences();
611 if (in_array($a_name, $seqs))
612 {
613 $r = $manager->dropSequence($a_name);
614 $this->handleError($r, "dropTable(".$a_name."), dropSequence");
615 }
616
617 // drop table
618 $r = $manager->dropTable($a_name);
619
620 return $this->handleError($r, "dropTable(".$a_name.")");
621 }
622
628 function alterTable($a_name, $a_changes)
629 {
630 if ($a_options == "")
631 {
632 $a_options = array();
633 }
634
635 $manager = $this->db->loadModule('Manager');
636 $r = $manager->alterTable($a_name, $a_changes, false);
637
638 return $this->handleError($r, "alterTable(".$a_name.")");
639 }
640
649 function addTableColumn($a_table, $a_column, $a_attributes)
650 {
651
652 $manager = $this->db->loadModule('Manager');
653
654 if (!$this->checkColumnName($a_column))
655 {
656 $this->raisePearError("ilDB Error: addTableColumn(".$a_table.", ".$a_column.")<br />".
657 $this->error_str);
658 }
659 if (!$this->checkColumnDefinition($a_attributes))
660 {
661 $this->raisePearError("ilDB Error: addTableColumn(".$a_table.", ".$a_column.")<br />".
662 $this->error_str);
663 }
664
665 $changes = array(
666 "add" => array(
667 $a_column => $a_attributes
668 )
669 );
670
671 $r = $manager->alterTable($a_table, $changes, false);
672
673 return $this->handleError($r, "addTableColumn(".$a_table.", ".$a_column.")");
674 }
675
683 function dropTableColumn($a_table, $a_column)
684 {
685
686 $manager = $this->db->loadModule('Manager');
687
688 $changes = array(
689 "remove" => array(
690 $a_column => array()
691 )
692 );
693
694 $r = $manager->alterTable($a_table, $changes, false);
695
696 return $this->handleError($r, "dropTableColumn(".$a_table.", ".$a_column.")");
697 }
698
707 function modifyTableColumn($a_table, $a_column, $a_attributes)
708 {
709 $manager = $this->db->loadModule('Manager');
710 $reverse = $this->db->loadModule('Reverse');
711 $def = $reverse->getTableFieldDefinition($a_table, $a_column);
712
713 $this->handleError($def, "modifyTableColumn(".$a_table.")");
714
715 if (is_file("./Services/Database/classes/class.ilDBAnalyzer.php"))
716 {
717 include_once("./Services/Database/classes/class.ilDBAnalyzer.php");
718 }
719 else
720 {
721 include_once("../Services/Database/classes/class.ilDBAnalyzer.php");
722 }
723 $analyzer = new ilDBAnalyzer();
724 $best_alt = $analyzer->getBestDefinitionAlternative($def);
725 $def = $def[$best_alt];
726 unset($def["nativetype"]);
727 unset($def["mdb2type"]);
728
729 // check attributes
730 $type = ($a_attributes["type"] != "")
731 ? $a_attributes["type"]
732 : $def["type"];
733 foreach ($def as $k => $v)
734 {
735 if ($k != "type" && !in_array($k, $this->allowed_attributes[$type]))
736 {
737 unset($def[$k]);
738 }
739 }
740 $check_array = $def;
741 foreach ($a_attributes as $k => $v)
742 {
743 $check_array[$k] = $v;
744 }
745 if (!$this->checkColumnDefinition($check_array, true))
746 {
747 $this->raisePearError("ilDB Error: modifyTableColumn(".$a_table.", ".$a_column.")<br />".
748 $this->error_str);
749 }
750
751 // oracle workaround: do not set null, if null already given
752 if ($this->getDbType() == "oracle")
753 {
754 if ($def["notnull"] == true && ($a_attributes["notnull"] == true
755 || !isset($a_attributes["notnull"])))
756 {
757 unset($def["notnull"]);
758 unset($a_attributes["notnull"]);
759 }
760 if ($def["notnull"] == false && ($a_attributes["notnull"] == false
761 || !isset($a_attributes["notnull"])))
762 {
763 unset($def["notnull"]);
764 unset($a_attributes["notnull"]);
765 }
766 }
767 foreach ($a_attributes as $a => $v)
768 {
769 $def[$a] = $v;
770 }
771
772 $a_attributes["definition"] = $def;
773
774 $changes = array(
775 "change" => array(
776 $a_column => $a_attributes
777 )
778 );
779
780 $r = $manager->alterTable($a_table, $changes, false);
781
782 return $this->handleError($r, "modifyTableColumn(".$a_table.")");
783 }
784
793 function renameTableColumn($a_table, $a_column, $a_new_column)
794 {
795 // check table name
796 if (!$this->checkColumnName($a_new_column))
797 {
798 $this->raisePearError("ilDB Error: renameTableColumn(".$a_table.",".$a_column.",".$a_new_column.")<br />".
799 $this->error_str);
800 }
801
802 $manager = $this->db->loadModule('Manager');
803 $reverse = $this->db->loadModule('Reverse');
804 $def = $reverse->getTableFieldDefinition($a_table, $a_column);
805
806 $this->handleError($def, "renameTableColumn(".$a_table.",".$a_column.",".$a_new_column.")");
807
808 if (is_file("./Services/Database/classes/class.ilDBAnalyzer.php"))
809 {
810 include_once("./Services/Database/classes/class.ilDBAnalyzer.php");
811 }
812 else
813 {
814 include_once("../Services/Database/classes/class.ilDBAnalyzer.php");
815 }
816
817 $analyzer = new ilDBAnalyzer();
818 $best_alt = $analyzer->getBestDefinitionAlternative($def);
819 $def = $def[$best_alt];
820 unset($def["nativetype"]);
821 unset($def["mdb2type"]);
822
823 $f["definition"] = $def;
824 $f["name"] = $a_new_column;
825
826 $changes = array(
827 "rename" => array(
828 $a_column => $f
829 )
830 );
831
832 $r = $manager->alterTable($a_table, $changes, false);
833
834 return $this->handleError($r, "renameTableColumn(".$a_table.",".$a_column.",".$a_new_column.")");
835 }
836
843 function renameTable($a_name, $a_new_name)
844 {
845 // check table name
846 if (!$this->checkTableName($a_new_name))
847 {
848 $this->raisePearError("ilDB Error: renameTable(".$a_name.",".$a_new_name.")<br />".
849 $this->error_str);
850 }
851
852 $manager = $this->db->loadModule('Manager');
853 $r = $manager->alterTable($a_name, array("name" => $a_new_name), false);
854
855 // The abstraction_progress is no longer used in ILIAS, see http://www.ilias.de/mantis/view.php?id=19513
856 // $query = "UPDATE abstraction_progress ".
857 // "SET table_name = ".$this->db->quote($a_new_name,'text')." ".
858 // "WHERE table_name = ".$this->db->quote($a_name,'text');
859 // $this->db->query($query);
860
861 return $this->handleError($r, "renameTable(".$a_name.",".$a_new_name.")");
862 }
863
871 function addPrimaryKey($a_table, $a_fields)
872 {
873 $manager = $this->db->loadModule('Manager');
874
875 $fields = array();
876 foreach ($a_fields as $f)
877 {
878 $fields[$f] = array();
879 }
880 $definition = array (
881 'primary' => true,
882 'fields' => $fields
883 );
884 $r = $manager->createConstraint($a_table,
885 $this->constraintName($a_table, $this->getPrimaryKeyIdentifier()), $definition);
886
887 return $this->handleError($r, "addPrimaryKey(".$a_table.")");
888 }
889
894 {
895 return "PRIMARY";
896 }
897
904 function dropPrimaryKey($a_table)
905 {
906 $manager = $this->db->loadModule('Manager');
907
908 $r = $manager->dropConstraint($a_table,
909 $this->constraintName($a_table, $this->getPrimaryKeyIdentifier()), true);
910
911 return $this->handleError($r, "dropPrimaryKey(".$a_table.")");
912 }
913
921 function addIndex($a_table, $a_fields, $a_name = "in", $a_fulltext = false)
922 {
926 $manager = $this->db->loadModule('Manager');
927
928 // check index name
929 if (!$this->checkIndexName($a_name))
930 {
931 $this->raisePearError("ilDB Error: addIndex(".$a_table.",".$a_name.")<br />".
932 $this->error_str);
933 }
934
935 $fields = array();
936 foreach ($a_fields as $f)
937 {
938 $fields[$f] = array();
939 }
940 $definition = array (
941 'fields' => $fields
942 );
943
944 if (!$a_fulltext)
945 {
946 $r = $manager->createIndex($a_table, $this->constraintName($a_table, $a_name), $definition);
947 }
948 else
949 {
950 if ($this->supportsFulltext())
951 {
952 $this->addFulltextIndex($a_table, $a_fields, $a_name);
953 }
954 }
955
956 return $this->handleError($r, "addIndex(".$a_table.")");
957 }
958
962 function addFulltextIndex($a_table, $a_fields, $a_name = "in")
963 {
964 return false;
965 }
966
970 function isFulltextIndex($a_table, $a_name)
971 {
972 return false;
973 }
974
975
981 public function indexExistsByFields($a_table, $a_fields)
982 {
983 $manager = $this->db->loadModule('Manager');
984 $reverse = $this->db->loadModule('Reverse');
985 if($manager)
986 {
987 foreach($manager->listTableIndexes($a_table) as $idx_name)
988 {
989 $def = $reverse->getTableIndexDefinition($a_table,$idx_name);
990 $idx_fields = array_keys((array) $def['fields']);
991
992 if($idx_fields === $a_fields)
993 {
994 return true;
995 }
996 }
997 }
998 return false;
999 }
1000
1007 public function dropIndexByFields($a_table, $a_fields)
1008 {
1009 $manager = $this->db->loadModule('Manager');
1010 $reverse = $this->db->loadModule('Reverse');
1011 if($manager)
1012 {
1013 foreach($manager->listTableIndexes($a_table) as $idx_name)
1014 {
1015 $def = $reverse->getTableIndexDefinition($a_table,$idx_name);
1016 $idx_fields = array_keys((array) $def['fields']);
1017
1018 if($idx_fields === $a_fields)
1019 {
1020 return $this->dropIndex($a_table, $idx_name);
1021 }
1022 }
1023 }
1024 return false;
1025
1026 }
1027
1035 function dropIndex($a_table, $a_name = "in")
1036 {
1037 $manager = $this->db->loadModule('Manager');
1038
1039 if (!$this->isFulltextIndex($a_table, $a_name))
1040 {
1041 $r = $manager->dropIndex($a_table, $this->constraintName($a_table, $a_name));
1042 }
1043 else
1044 {
1045 $this->dropFulltextIndex($a_table, $a_name);
1046 }
1047
1048 return $this->handleError($r, "dropIndex(".$a_table.")");
1049 }
1050
1058 function addUniqueConstraint($a_table, $a_fields, $a_name = "con")
1059 {
1060 $manager = $this->db->loadModule('Manager');
1061
1062 // check index name
1063 if (!$this->checkIndexName($a_name))
1064 {
1065 $this->raisePearError("ilDB Error: addUniqueConstraint(".$a_table.",".$a_name.")<br />".
1066 $this->error_str);
1067 }
1068
1069 $fields = array();
1070 foreach ($a_fields as $f)
1071 {
1072 $fields[$f] = array();
1073 }
1074 $definition = array (
1075 'unique' => true,
1076 'fields' => $fields
1077 );
1078
1079 $r = $manager->createConstraint($a_table, $this->constraintName($a_table, $a_name), $definition);
1080
1081 return $this->handleError($r, "addUniqueConstraint(".$a_table.")");
1082 }
1083
1091 public function dropUniqueConstraint($a_table, $a_name = "con")
1092 {
1093 $manager = $this->db->loadModule('Manager');
1094
1095 $r = $manager->dropConstraint(
1096 $a_table, $this->constraintName($a_table, $a_name), false
1097 );
1098
1099 return $this->handleError($r, "dropUniqueConstraint(".$a_table.")");
1100 }
1101
1108 public function dropUniqueConstraintByFields($a_table, $a_fields)
1109 {
1110 if (is_file("./Services/Database/classes/class.ilDBAnalyzer.php"))
1111 {
1112 include_once("./Services/Database/classes/class.ilDBAnalyzer.php");
1113 }
1114 else
1115 {
1116 include_once("../Services/Database/classes/class.ilDBAnalyzer.php");
1117 }
1118 $analyzer = new ilDBAnalyzer();
1119 $cons = $analyzer->getConstraintsInformation($a_table);
1120 foreach ($cons as $c)
1121 {
1122 if ($c["type"] == "unique" && count($a_fields) == count($c["fields"]))
1123 {
1124 $all_in = true;
1125 foreach ($a_fields as $f)
1126 {
1127 if (!isset($c["fields"][$f]))
1128 {
1129 $all_in = false;
1130 }
1131 }
1132 if ($all_in)
1133 {
1134 return $this->dropUniqueConstraint($a_table, $c['name']);
1135 }
1136 }
1137 }
1138 return false;
1139 }
1140
1144 function createSequence($a_table_name, $a_start = 1)
1145 {
1146 $manager = $this->db->loadModule('Manager');
1147
1148 $r = $manager->createSequence($a_table_name, $a_start);
1149
1150 return $this->handleError($r, "createSequence(".$a_table_name.")");
1151 }
1152
1153
1157 function dropSequence($a_table_name)
1158 {
1159 $manager = $this->db->loadModule('Manager');
1160
1161 $r = $manager->dropSequence($a_table_name);
1162
1163 return $this->handleError($r, "dropSequence(".$a_table_name.")");
1164 }
1165
1171 function checkTableName($a_name)
1172 {
1173 if (!preg_match ("/^[a-z]+[_a-z0-9]*$/", $a_name))
1174 {
1175 $this->error_str = "Table name must only contain _a-z0-9 and must start with a-z.";
1176 return false;
1177 }
1178
1179 if ($this->isReservedWord($a_name))
1180 {
1181 $this->error_str = "Invalid table name '".$a_name."' (Reserved Word).";
1182 return false;
1183 }
1184
1185 if (strtolower(substr($a_name, 0, 4)) == "sys_")
1186 {
1187 $this->error_str = "Invalid table name '".$a_name."'. Name must not start with 'sys_'.";
1188 return false;
1189 }
1190
1191 if (strlen($a_name) > 22)
1192 {
1193 $this->error_str = "Invalid table name '".$a_name."'. Maximum table identifer length is 22 bytes.";
1194 return false;
1195 }
1196
1197 return true;
1198 }
1199
1205 function checkTableColumns($a_cols)
1206 {
1207 foreach ($a_cols as $col => $def)
1208 {
1209 if (!$this->checkColumn($col, $def))
1210 {
1211 return false;
1212 }
1213 }
1214
1215 return true;
1216 }
1217
1221 function checkColumn($a_col, $a_def)
1222 {
1223 if (!$this->checkColumnName($a_col))
1224 {
1225 return false;
1226 }
1227
1228 if (!$this->checkColumnDefinition($a_def))
1229 {
1230 return false;
1231 }
1232
1233 return true;
1234 }
1235
1241 function checkColumnDefinition($a_def, $a_modify_mode = false)
1242 {
1243 // check valid type
1244 if (!in_array($a_def["type"], array("text", "integer", "float", "date", "time", "timestamp", "clob", "blob")))
1245 {
1246 switch ($a_def["type"])
1247 {
1248 case "boolean":
1249 $this->error_str = "Invalid column type '".$a_def["type"]."'. Use integer(1) instead.";
1250 break;
1251
1252 case "decimal":
1253 $this->error_str = "Invalid column type '".$a_def["type"]."'. Use float or integer instead.";
1254 break;
1255
1256 default:
1257 $this->error_str = "Invalid column type '".$a_def["type"]."'. Allowed types are: ".
1258 "text, integer, float, date, time, timestamp, clob and blob.";
1259 }
1260 }
1261
1262 // check used attributes
1264
1265 foreach ($a_def as $k => $v)
1266 {
1267 if ($k != "type" && !in_array($k, $allowed_attributes[$a_def["type"]]))
1268 {
1269 $this->error_str = "Attribute '".$k."' is not allowed for column type '".$a_def["type"]."'.";
1270 return false;
1271 }
1272 }
1273
1274 // type specific checks
1275 switch ($a_def["type"])
1276 {
1277 case "text":
1278 if ($a_def["length"] < 1 || $a_def["length"] > 4000)
1279 {
1280 if (!$a_modify_mode || isset($a_def["length"]))
1281 {
1282 $this->error_str = "Invalid length '".$a_def["length"]."' for type text.".
1283 " Length must be >=1 and <= 4000.";
1284 return false;
1285 }
1286 }
1287 break;
1288
1289 case "integer":
1290 if (!in_array($a_def["length"], array(1, 2, 3, 4, 8)))
1291 {
1292 if (!$a_modify_mode || isset($a_def["length"]))
1293 {
1294 $this->error_str = "Invalid length '".$a_def["length"]."' for type integer.".
1295 " Length must be 1, 2, 3, 4 or 8 (bytes).";
1296 return false;
1297 }
1298 }
1299 if ($a_def["unsigned"])
1300 {
1301 $this->error_str = "Unsigned attribut must not be true for type integer.";
1302 return false;
1303 }
1304 break;
1305 }
1306
1307 return true;
1308 }
1309
1315 function checkColumnName($a_name)
1316 {
1317 if (!preg_match ("/^[a-z]+[_a-z0-9]*$/", $a_name))
1318 {
1319 $this->error_str = "Invalid column name '".$a_name."'. Column name must only contain _a-z0-9 and must start with a-z.";
1320 return false;
1321 }
1322
1323 if ($this->isReservedWord($a_name))
1324 {
1325 $this->error_str = "Invalid column name '".$a_name."' (Reserved Word).";
1326 return false;
1327 }
1328
1329 if (strtolower(substr($a_name, 0, 4)) == "sys_")
1330 {
1331 $this->error_str = "Invalid column name '".$a_name."'. Name must not start with 'sys_'.";
1332 return false;
1333 }
1334
1335 if (strlen($a_name) > 30)
1336 {
1337 $this->error_str = "Invalid column name '".$a_name."'. Maximum column identifer length is 30 bytes.";
1338 return false;
1339 }
1340
1341 return true;
1342 }
1343
1349 function checkIndexName($a_name)
1350 {
1351 if (!preg_match ("/^[a-z]+[_a-z0-9]*$/", $a_name))
1352 {
1353 $this->error_str = "Invalid column name '".$a_name."'. Column name must only contain _a-z0-9 and must start with a-z.";
1354 return false;
1355 }
1356
1357 if ($this->isReservedWord($a_name))
1358 {
1359 $this->error_str = "Invalid column name '".$a_name."' (Reserved Word).";
1360 return false;
1361 }
1362
1363 if (strlen($a_name) > 3)
1364 {
1365 $this->error_str = "Invalid index name '".$a_name."'. Maximum index identifer length is 3 bytes.";
1366 return false;
1367 }
1368
1369 return true;
1370 }
1371
1373 {
1375 }
1376
1382 function constraintName($a_table, $a_constraint)
1383 {
1384 return $a_constraint;
1385 }
1386
1391 public static function isReservedWord($a_word)
1392 {
1393 require_once('./Services/Database/classes/PDO/FieldDefinition/class.ilDBPdoMySQLFieldDefinition.php');
1394 global $DIC;
1395 $ilDBPdoMySQLFieldDefinition = new ilDBPdoMySQLFieldDefinition($DIC['ilDB']);
1396
1397 return $ilDBPdoMySQLFieldDefinition->isReserved($a_word);
1398 }
1399
1400 //
1401 // Data query and manupilation functions
1402 //
1403
1415 function query($sql, $a_handle_error = true)
1416 {
1417 global $ilBench;
1418
1419 if (is_object($ilBench))
1420 {
1421 $ilBench->startDbBench($sql);
1422 }
1423 $r = $this->db->query($sql);
1424 if (is_object($ilBench))
1425 {
1426 $ilBench->stopDbBench();
1427 }
1428
1429 if ($a_handle_error)
1430 {
1431 return $this->handleError($r, "query(".$sql.")");
1432 }
1433
1434 return $r;
1435 }
1436
1444 function queryF($a_query, $a_types, $a_values)
1445 {
1446 if (!is_array($a_types) || !is_array($a_values) ||
1447 count($a_types) != count($a_values))
1448 {
1449 $this->raisePearError("ilDB::queryF: Types and values must be arrays of same size. ($a_query)");
1450 }
1451 $quoted_values = array();
1452 foreach($a_types as $k => $t)
1453 {
1454 $quoted_values[] = $this->quote($a_values[$k], $t);
1455 }
1456 $query = vsprintf($a_query, $quoted_values);
1457
1458 return $this->query($query);
1459 }
1460
1468 function manipulateF($a_query, $a_types, $a_values)
1469 {
1470 if (!is_array($a_types) || !is_array($a_values) ||
1471 count($a_types) != count($a_values))
1472 {
1473 $this->raisePearError("ilDB::manipulateF: types and values must be arrays of same size. ($a_query)");
1474 }
1475 $quoted_values = array();
1476 foreach($a_types as $k => $t)
1477 {
1478 $quoted_values[] = $this->quote($a_values[$k], $t);
1479 }
1480 $query = vsprintf($a_query, $quoted_values);
1481
1482 return $this->manipulate($query);
1483 }
1484
1488 function logStatement($sql)
1489 {
1490 $pos1 = strpos(strtolower($sql), "from ");
1491 $table = "";
1492 if ($pos1 > 0)
1493 {
1494 $tablef = substr($sql, $pos1+5);
1495 $pos2 = strpos(strtolower($tablef), " ");
1496 if ($pos2 > 0)
1497 {
1498 $table =substr($tablef, 0, $pos2);
1499 }
1500 else
1501 {
1502 $table = $tablef;
1503 }
1504 }
1505 if (trim($table) != "")
1506 {
1507 if (!is_array($this->ttt) || !in_array($table, $this->ttt))
1508 {
1509 echo "<br>".$table;
1510 $this->ttt[] = $table;
1511 }
1512 }
1513 else
1514 {
1515 echo "<br><b>".$sql."</b>";
1516 }
1517 }
1518
1522 function setLimit($a_limit, $a_offset = 0)
1523 {
1524 $this->db->setLimit($a_limit, $a_offset);
1525 }
1526
1530 function nextId($a_table_name)
1531 {
1532 // we do not create missing sequences automatically here
1533 // otherwise misspelled statements result in additional tables
1534 // please create sequences explicitly in the db update script
1535 $r = $this->db->nextId($a_table_name, false);
1536
1537 return $this->handleError($r, "nextId(".$a_table_name.")");
1538 }
1539
1550 function manipulate($sql)
1551 {
1552 global $ilBench;
1553
1554 if (is_object($ilBench))
1555 {
1556 $ilBench->startDbBench($sql);
1557 }
1558 $r = $this->db->exec($sql);
1559 if (is_object($ilBench))
1560 {
1561 $ilBench->stopDbBench();
1562 }
1563
1564 return $this->handleError($r, "manipulate(".$sql.")");
1565 }
1566
1575 function prepare($a_query, $a_types = null, $a_result_types = null)
1576 {
1577 $res = $this->db->prepare($a_query, $a_types, $a_result_types);
1578
1579 return $this->handleError($res, "prepare(".$a_query.")");
1580 }
1581
1590 function prepareManip($a_query, $a_types = null)
1591 {
1592 $res = $this->db->prepare($a_query, $a_types, MDB2_PREPARE_MANIP);
1593
1594 return $this->handleError($res, "prepareManip(".$a_query.")");
1595 }
1596
1605 function execute($a_stmt, $a_data = null)
1606 {
1607 $res = $a_stmt->execute($a_data);
1608
1609 return $this->handleError($res, "execute(".$a_stmt->query.")");
1610 }
1611
1621 function executeMultiple($a_stmt, $a_data)
1622 {
1623 $res = $this->db->extended->executeMultiple($a_stmt,$a_data);
1624
1625 return $this->handleError($res, "executeMultiple(".$a_stmt->query.")");
1626 }
1627
1634 function insert($a_table, $a_columns)
1635 {
1636 $fields = array();
1637 $field_values = array();
1638 $placeholders = array();
1639 $types = array();
1640 $values = array();
1641 $lobs = false;
1642 $lob = array();
1643 foreach ($a_columns as $k => $col)
1644 {
1645 $fields[] = $k;
1646 $placeholders[] = "%s";
1647 $placeholders2[] = ":$k";
1648 $types[] = $col[0];
1649
1650 // integer auto-typecast (this casts bool values to integer)
1651 if ($col[0] == 'integer' && !is_null($col[1]))
1652 {
1653 $col[1] = (int) $col[1];
1654 }
1655
1656 $values[] = $col[1];
1657 $field_values[$k] = $col[1];
1658 if ($col[0] == "blob" || $col[0] == "clob")
1659 {
1660 $lobs = true;
1661 $lob[$k] = $k;
1662 }
1663 }
1664 if ($lobs) // lobs -> use prepare execute (autoexecute broken in PEAR 2.4.1)
1665 {
1666 $st = $this->db->prepare("INSERT INTO ".$a_table." (".implode($fields,",").") VALUES (".
1667 implode($placeholders2,",").")", $types, MDB2_PREPARE_MANIP, $lob);
1668
1669 $this->handleError($st, "insert / prepare/execute(".$a_table.")");
1670
1671 $r = $st->execute($field_values);
1672
1673
1674 //$r = $this->db->extended->autoExecute($a_table, $field_values, MDB2_AUTOQUERY_INSERT, null, $types);
1675 $this->handleError($r, "insert / prepare/execute(".$a_table.")");
1676 $this->free($st);
1677 }
1678 else // if no lobs are used, take simple manipulateF
1679 {
1680 $q = "INSERT INTO ".$a_table." (".implode($fields,",").") VALUES (".
1681 implode($placeholders,",").")";
1682 $r = $this->manipulateF($q, $types, $values);
1683 }
1684 return $r;
1685 }
1686
1695 function update($a_table, $a_columns, $a_where)
1696 {
1697 $fields = array();
1698 $field_values = array();
1699 $placeholders = array();
1700 $types = array();
1701 $values = array();
1702 $lobs = false;
1703 $lob = array();
1704 foreach ($a_columns as $k => $col)
1705 {
1706 $fields[] = $k;
1707 $placeholders[] = "%s";
1708 $placeholders2[] = ":$k";
1709 $types[] = $col[0];
1710
1711 // integer auto-typecast (this casts bool values to integer)
1712 if ($col[0] == 'integer' && !is_null($col[1]))
1713 {
1714 $col[1] = (int) $col[1];
1715 }
1716
1717 $values[] = $col[1];
1718 $field_values[$k] = $col[1];
1719 if ($col[0] == "blob" || $col[0] == "clob")
1720 {
1721 $lobs = true;
1722 $lob[$k] = $k;
1723 }
1724 }
1725
1726 if ($lobs)
1727 {
1728 $q = "UPDATE ".$a_table." SET ";
1729 $lim = "";
1730 foreach ($fields as $k => $field)
1731 {
1732 $q.= $lim.$field." = ".$placeholders2[$k];
1733 $lim = ", ";
1734 }
1735 $q.= " WHERE ";
1736 $lim = "";
1737 foreach ($a_where as $k => $col)
1738 {
1739 $q.= $lim.$k." = ".$this->quote($col[1], $col[0]);
1740 $lim = " AND ";
1741 }
1742 $st = $this->db->prepare($q, $types, MDB2_PREPARE_MANIP, $lob);
1743 $r = $st->execute($field_values);
1744
1745 //$r = $this->db->extended->autoExecute($a_table, $field_values, MDB2_AUTOQUERY_INSERT, null, $types);
1746 $this->handleError($r, "update / prepare/execute(".$a_table.")");
1747 $this->free($st);
1748 }
1749 else
1750 {
1751 foreach ($a_where as $k => $col)
1752 {
1753 $types[] = $col[0];
1754 $values[] = $col[1];
1755 $field_values[$k] = $col;
1756 }
1757 $q = "UPDATE ".$a_table." SET ";
1758 $lim = "";
1759 foreach ($fields as $k => $field)
1760 {
1761 $q.= $lim.$field." = ".$placeholders[$k];
1762 $lim = ", ";
1763 }
1764 $q.= " WHERE ";
1765 $lim = "";
1766 foreach ($a_where as $k => $col)
1767 {
1768 $q.= $lim.$k." = %s";
1769 $lim = " AND ";
1770 }
1771
1772 $r = $this->manipulateF($q, $types, $values);
1773 }
1774 return $r;
1775 }
1776
1784 function replace($a_table, $a_pk_columns, $a_other_columns)
1785 {
1786 // this is the mysql implementation
1787 $a_columns = array_merge($a_pk_columns, $a_other_columns);
1788 $fields = array();
1789 $field_values = array();
1790 $placeholders = array();
1791 $types = array();
1792 $values = array();
1793 $lobs = false;
1794 $lob = array();
1795 foreach ($a_columns as $k => $col)
1796 {
1797 $fields[] = $k;
1798 $placeholders[] = "%s";
1799 $placeholders2[] = ":$k";
1800 $types[] = $col[0];
1801
1802 // integer auto-typecast (this casts bool values to integer)
1803 if ($col[0] == 'integer' && !is_null($col[1]))
1804 {
1805 $col[1] = (int) $col[1];
1806 }
1807
1808 $values[] = $col[1];
1809 $field_values[$k] = $col[1];
1810 if ($col[0] == "blob" || $col[0] == "clob")
1811 {
1812 $lobs = true;
1813 $lob[$k] = $k;
1814 }
1815 }
1816 if ($lobs) // lobs -> use prepare execute (autoexecute broken in PEAR 2.4.1)
1817 {
1818 $st = $this->db->prepare("REPLACE INTO ".$a_table." (".implode($fields,",").") VALUES (".
1819 implode($placeholders2,",").")", $types, MDB2_PREPARE_MANIP, $lob);
1820 $this->handleError($st, "insert / prepare/execute(".$a_table.")");
1821 $r = $st->execute($field_values);
1822 //$r = $this->db->extended->autoExecute($a_table, $field_values, MDB2_AUTOQUERY_INSERT, null, $types);
1823 $this->handleError($r, "insert / prepare/execute(".$a_table.")");
1824 $this->free($st);
1825 }
1826 else // if no lobs are used, take simple manipulateF
1827 {
1828 $q = "REPLACE INTO ".$a_table." (".implode($fields,",").") VALUES (".
1829 implode($placeholders,",").")";
1830 $r = $this->manipulateF($q, $types, $values);
1831 }
1832 return $r;
1833 }
1834
1840 function fetchAssoc($a_set)
1841 {
1842 return $a_set->fetchRow(ilDBConstants::FETCHMODE_ASSOC);
1843 }
1844
1848 function free($a_st)
1849 {
1850 return $a_st->free();
1851 }
1852
1858 function fetchObject($a_set)
1859 {
1860 return $a_set->fetchRow(ilDBConstants::FETCHMODE_OBJECT);
1861 }
1862
1868 function numRows($a_set)
1869 {
1870 return $a_set->numRows();
1871 }
1872
1873 //
1874 // function and clauses abstraction
1875 //
1876
1888 function in($a_field, $a_values, $negate = false, $a_type = "")
1889 {
1890 if (count($a_values) == 0)
1891 {
1892 // BEGIN fixed mantis #0014191:
1893 //return " 1=2 "; // return a false statement on empty array
1894 return $negate ? ' 1=1 ' : ' 1=2 ';
1895 // END fixed mantis #0014191:
1896 }
1897 if ($a_type == "") // untyped: used ? for prepare/execute
1898 {
1899 $str = $a_field.(($negate) ? " NOT" : "")." IN (?".str_repeat(",?", count($a_values) - 1).")";
1900 }
1901 else // typed, use values for query/manipulate
1902 {
1903 $str = $a_field.(($negate) ? " NOT" : "")." IN (";
1904 $sep = "";
1905 foreach ($a_values as $v)
1906 {
1907 $str.= $sep.$this->quote($v, $a_type);
1908 $sep = ",";
1909 }
1910 $str.= ")";
1911 }
1912
1913 return $str;
1914 }
1915
1919 function addTypesToArray($a_arr, $a_type, $a_cnt)
1920 {
1921 if (!is_array($a_arr))
1922 {
1923 $a_arr = array();
1924 }
1925 if ($a_cnt > 0)
1926 {
1927 $type_arr = array_fill(0, $a_cnt, $a_type);
1928 }
1929 else
1930 {
1931 $type_arr = array();
1932 }
1933 return array_merge($a_arr, $type_arr);
1934 }
1935
1940 function now()
1941 {
1942 return "now()";
1943 }
1944
1945
1955 public function concat(array $a_values,$a_allow_null = true)
1956 {
1957 if(!count($a_values))
1958 {
1959 return ' ';
1960 }
1961
1962 $concat = ' CONCAT(';
1963 $first = true;
1964 foreach($a_values as $field_info)
1965 {
1966 $val = $field_info[0];
1967
1968 if(!$first)
1969 {
1970 $concat .= ',';
1971 }
1972
1973 if($a_allow_null)
1974 {
1975 $concat .= 'COALESCE(';
1976 }
1977 $concat .= $val;
1978
1979 if($a_allow_null)
1980 {
1981 $concat .= ",''";
1982 $concat .= ')';
1983 }
1984
1985 $first = false;
1986 }
1987 $concat .= ') ';
1988 return $concat;
1989 }
1990
1997 function substr($a_exp, $a_pos = 1, $a_len = -1)
1998 {
1999 $lenstr = "";
2000 if ($a_len > -1)
2001 {
2002 $lenstr = ", ".$a_len;
2003 }
2004 return " SUBSTR(".$a_exp.", ".$a_pos.$lenstr.") ";
2005 }
2006
2013 function upper($a_exp)
2014 {
2015 return " UPPER(".$a_exp.") ";
2016 }
2017
2024 function lower($a_exp)
2025 {
2026 return " LOWER(".$a_exp.") ";
2027 }
2028
2036 public function locate($a_needle,$a_string,$a_start_pos = 1)
2037 {
2038 $locate = ' LOCATE( ';
2039 $locate .= $a_needle;
2040 $locate .= ',';
2041 $locate .= $a_string;
2042 $locate .= ',';
2043 $locate .= $a_start_pos;
2044 $locate .= ') ';
2045 return $locate;
2046 }
2047
2048
2054 function like($a_col, $a_type, $a_value = "?", $case_insensitive = true)
2055 {
2056 if (!in_array($a_type, array("text", "clob", "blob")))
2057 {
2058 $this->raisePearError("Like: Invalid column type '".$a_type."'.", $this->error_class->FATAL);
2059 }
2060 if ($a_value == "?")
2061 {
2062 if ($case_insensitive)
2063 {
2064 return "UPPER(".$a_col.") LIKE(UPPER(?))";
2065 }
2066 else
2067 {
2068 return $a_col ." LIKE(?)";
2069 }
2070 }
2071 else
2072 {
2073 if ($case_insensitive)
2074 {
2075 // Always quote as text
2076 return " UPPER(".$a_col.") LIKE(UPPER(".$this->quote($a_value, 'text')."))";
2077 }
2078 else
2079 {
2080 // Always quote as text
2081 return " ".$a_col." LIKE(".$this->quote($a_value, 'text').")";
2082 }
2083 }
2084 }
2085
2086
2090 function equals($a_col, $a_value, $a_type, $a_empty_or_null = false)
2091 {
2092 if (!$a_empty_or_null || $a_value != "")
2093 {
2094 return $a_col." = ".$this->quote($a_value, $a_type);
2095 }
2096 else
2097 {
2098 return "(".$a_col." = '' OR $a_col IS NULL)";
2099 }
2100 }
2101
2105 function equalsNot($a_col, $a_value, $a_type, $a_empty_or_null = false)
2106 {
2107 if (!$a_empty_or_null)
2108 {
2109 return $a_col." <> ".$this->quote($a_value, $a_type);
2110 }
2111 if ($a_value != "")
2112 {
2113 return "(".$a_col." <> ".$this->quote($a_value, $a_type). " OR ".
2114 $a_col." IS NULL)";
2115 }
2116 else
2117 {
2118 return "(".$a_col." <> '' AND $a_col IS NOT NULL)";
2119 }
2120 }
2121
2128 function fromUnixtime($a_expr, $a_to_text = true)
2129 {
2130 return "FROM_UNIXTIME(".$a_expr.")";
2131 }
2132
2136 function unixTimestamp()
2137 {
2138 return "UNIX_TIMESTAMP()";
2139 }
2140
2141
2142 //
2143 // Schema related functions
2144 //
2145
2152 function tableExists($a_table)
2153 {
2154 $tables = $this->listTables();
2155
2156 if (is_array($tables))
2157 {
2158 if (in_array($a_table, $tables))
2159 {
2160 return true;
2161 }
2162 }
2163 return false;
2164 }
2165
2173 function tableColumnExists($a_table, $a_column_name)
2174 {
2175
2176 $column_visibility = false;
2177 $manager = $this->db->loadModule('Manager');
2178 $r = $manager->listTableFields($a_table);
2179
2180 if (!MDB2::isError($r))
2181 {
2182 foreach($r as $field)
2183 {
2184 if ($field == $a_column_name)
2185 {
2186 $column_visibility = true;
2187 }
2188 }
2189 }
2190
2191 return $column_visibility;
2192 }
2193
2201 public function uniqueConstraintExists($a_table, array $a_fields)
2202 {
2203 if (is_file("./Services/Database/classes/class.ilDBAnalyzer.php"))
2204 {
2205 include_once("./Services/Database/classes/class.ilDBAnalyzer.php");
2206 }
2207 else
2208 {
2209 include_once("../Services/Database/classes/class.ilDBAnalyzer.php");
2210 }
2211 $analyzer = new ilDBAnalyzer();
2212 $cons = $analyzer->getConstraintsInformation($a_table);
2213 foreach ($cons as $c)
2214 {
2215 if ($c["type"] == "unique" && count($a_fields) == count($c["fields"]))
2216 {
2217 $all_in = true;
2218 foreach ($a_fields as $f)
2219 {
2220 if (!isset($c["fields"][$f]))
2221 {
2222 $all_in = false;
2223 }
2224 }
2225 if ($all_in)
2226 {
2227 return true;
2228 }
2229 }
2230 }
2231 return false;
2232 }
2233
2234
2240 function listTables()
2241 {
2242 $manager = $this->db->loadModule('Manager');
2243 $r = $manager->listTables();
2244
2245 if (!MDB2::isError($r))
2246 {
2247 return $r;
2248 }
2249
2250 return false;
2251 }
2252
2259 function sequenceExists($a_sequence)
2260 {
2261 $sequences = $this->listSequences();
2262
2263 if (is_array($sequences))
2264 {
2265 if (in_array($a_sequence, $sequences))
2266 {
2267 return true;
2268 }
2269 }
2270 return false;
2271 }
2272
2278 function listSequences()
2279 {
2280 $manager = $this->db->loadModule('Manager');
2281 $r = $manager->listSequences();
2282
2283 if (!MDB2::isError($r))
2284 {
2285 return $r;
2286 }
2287
2288 return false;
2289 }
2290
2291
2292 //
2293 // Quote Functions
2294 //
2295
2299 function quote($a_query, $a_type = null)
2300 {
2301 if ($a_query == "" && is_null($a_type))
2302 {
2303 $a_query = "";
2304 }
2305
2306 // Performance fix
2307 if($a_type == 'integer' && !is_null($a_query))
2308 {
2309 return (int) $a_query;
2310 }
2311
2312 if ($a_type == "blob" || $a_type == "clob")
2313 {
2314 $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);
2315 }
2316
2317 return $this->db->quote($a_query, $a_type);
2318 }
2319
2327 function quoteIdentifier($a_identifier, $check_option = false)
2328 {
2329 return $this->db->quoteIdentifier($a_identifier);
2330 }
2331
2332
2333 //
2334 // Transaction and Locking methods
2335 //
2336
2343 {
2344 if (!$this->db->supports('transactions'))
2345 {
2346 $this->raisePearError("ilDB::beginTransaction: Transactions are not supported.", $this->error_class->FATAL);
2347 }
2348 $res = $this->db->beginTransaction();
2349
2350 return $this->handleError($res, "beginTransaction()");
2351 }
2352
2356 function commit()
2357 {
2358 $res = $this->db->commit();
2359
2360 return $this->handleError($res, "commit()");
2361 }
2362
2366 function rollback()
2367 {
2368 $res = $this->db->rollback();
2369
2370 return $this->handleError($res, "rollback()");
2371 }
2372
2379 abstract public function lockTables($a_tables);
2380
2386 abstract public function unlockTables();
2387
2388
2389//
2390//
2391// Older functions. Must be checked.
2392//
2393//
2394
2403 function autoExecute($a_tablename,$a_fields,$a_mode = MDB2_AUTOQUERY_INSERT,$a_where = false)
2404 {
2405 $res = $this->db->autoExecute($a_tablename,$a_fields,$a_mode,$a_where);
2406
2407 return $this->handleError($res, "autoExecute(".$a_tablename.")");
2408 }
2409
2410//
2411//
2412// Deprecated functions.
2413//
2414//
2415
2420 {
2421 $res = $this->db->lastInsertId();
2422 if(MDB2::isError($res))
2423 {
2424 return false;
2425 }
2426 return $res;
2427 }
2428
2438 function getOne($sql)
2439 {
2440 //$r = $this->db->getOne($sql);
2441 $set = $this->db->query($sql);
2442
2443 $this->handleError($set, "getOne(".$sql.")");
2444
2445 if (!MDB2::isError($set))
2446 {
2447 $r = $set->fetchRow(ilDBConstants::FETCHMODE_ASSOC);
2448
2449 return $r[0];
2450 }
2451 }
2452
2463 {
2464 $set = $this->query($sql);
2465 $r = $set->fetchRow($mode);
2466 //$r = $this->db->getrow($sql,$mode);
2467
2468 $this->handleError($r, "getRow(".$sql.")");
2469
2470 return $r;
2471 } //end function
2472
2478 public function fetchAll($query_result, $fetch_mode = ilDBConstants::FETCHMODE_ASSOC) {
2482 $return = array();
2483 while ($data = $query_result->fetch($fetch_mode)) {
2484 $return[] = $data;
2485 }
2486
2487 return $return;
2488 }
2489
2495 function setSubType($a_value)
2496 {
2497 $this->sub_type = (string)$a_value;
2498 }
2499
2505 function getSubType()
2506 {
2507 return $this->sub_type;
2508 }
2509
2510
2517 {
2518 return array();
2519 }
2520
2521
2525 public function supportsEngineMigration()
2526 {
2527 return false;
2528 }
2529
2530
2535 public function getSequenceName($table_name) {
2536 return $this->db->getSequenceName($table_name);
2537 }
2538
2539
2543 public function buildAtomQuery() {
2544 require_once('./Services/Database/classes/Atom/class.ilAtomQueryLock.php');
2545
2546 return new ilAtomQueryLock($this);
2547 }
2548
2549
2554 {
2555 if (!$this->doesCollationSupportMB4Strings()) {
2556 $query_replaced = preg_replace(
2557 '/[\x{10000}-\x{10FFFF}]/u', ilDBConstants::MB4_REPLACEMENT, $query
2558 );
2559 if (!empty($query_replaced)) {
2560 return $query_replaced;
2561 }
2562 }
2563
2564 return $query;
2565 }
2566
2567
2572 {
2573 return false;
2574 }
2575
2576
2580 public function cast($a_field_name, $a_dest_type) {
2581 $manager = $this->db->loadModule('Manager');
2582 return $manager->getQueryUtils()->cast($a_field_name, $a_dest_type);
2583 }
2584}
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
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:380
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:210
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.
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:526
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:201
$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:649
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:893
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:233
renameTable($a_name, $a_new_name)
Rename a table.
Definition: class.ilDB.php:843
dropPrimaryKey($a_table)
Drop a primary key from a table.
Definition: class.ilDB.php:904
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:707
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:272
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
supportsSlave()
Supports slave.
Definition: class.ilDB.php:371
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:501
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:793
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:970
setDBPort($a_port)
Set database port.
Definition: class.ilDB.php:93
initHostConnection()
Initialize the host connection (no specific database)
Definition: class.ilDB.php:356
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:561
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:572
static isDbError($a_res)
Check error.
Definition: class.ilDB.php:489
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:628
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.
beginTransaction()
Begin Transaction.
migrateAllTablesToEngine($engine=ilDBConstants::MYSQL_ENGINE_INNODB)
raisePearError($a_message, $a_level="")
Raise an error.
Definition: class.ilDB.php:459
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:871
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:981
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)
addFulltextIndex($a_table, $a_fields, $a_name="in")
Add fulltext index.
Definition: class.ilDB.php:962
useSlave($a_val=true)
Use slave.
Definition: class.ilDB.php:408
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:360
dropTableColumn($a_table, $a_column)
Drop table column Use this only on aleady "abstracted" tables.
Definition: class.ilDB.php:683
$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.
$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)
if(!is_array($argv)) $options
global $DIC
$engine
Definition: workflow.php:90
$a_type
Definition: workflow.php:93