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
10 require_once('./Services/Database/lib/PEAR/MDB2.php');
11 require_once 'Services/Database/classes/QueryUtils/class.ilMySQLQueryUtils.php';
12 require_once 'Services/Database/interfaces/interface.ilDBInterface.php';
13 
14 //echo "-".ilDBConstants::FETCHMODE_ASSOC."-";
15 //echo "+".ilDBConstants::FETCHMODE_OBJECT."+";
16 
17 
29 abstract class ilDB extends PEAR implements ilDBInterface
30 {
31  const LOCK_WRITE = 1;
32  const LOCK_READ = 2;
33 
34 
40  public $error_class;
41 
46  public $db;
47 
52  public $result;
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 
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 
544  $options = $this->getCreateTableOptions();
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 }
static getReservedWords()
Get reserved words.
Definition: class.ilDB.php:192
upper($a_exp)
Upper.
raisePearError($a_message, $a_level="")
Raise an error.
Definition: class.ilDB.php:460
Add rich text string
prepare($a_query, $a_types=null, $a_result_types=null)
Prepare a query (SELECT) statement to be used with execute.
checkTableColumns($a_cols)
Check table columns definition.
getOne($sql)
getOne.
numRows($a_set)
Fetch row as associative array from result set.
rollback()
Rollback a transaction.
createDatabase($a_name, $a_charset="utf8", $a_collation="")
Create database.
Definition: class.ilDB.php:500
const PEAR_ERROR_CALLBACK
Definition: PEAR.php:35
isFulltextIndex($a_table, $a_name)
Is index a fulltext index?
Definition: class.ilDB.php:937
isError($data, $code=null)
Tell whether a value is a MDB2 error.
Definition: MDB2.php:599
setDBUser($a_user)
Set database user.
Definition: class.ilDB.php:73
sequenceExists($a_sequence)
Check, whether a given sequence exists.
$error_class
Definition: class.ilDB.php:40
$type
checkColumnDefinition($a_def, $a_modify_mode=false)
Check whether a column definition is valid.
global $DIC
Definition: saml.php:7
renameTableColumn($a_table, $a_column, $a_new_column)
Rename a table column Use this only on aleady "abstracted" tables.
Definition: class.ilDB.php:766
tableExists($a_table)
Check, whether a given table exists.
query($sql, $a_handle_error=true)
Query.
nextId($a_table_name)
Get next ID for an index.
const MDB2_PORTABILITY_EMPTY_TO_NULL
Portability: convert empty values to null strings in data output by query*() and fetch*().
Definition: MDB2.php:203
migrateAllTablesToEngine($engine=ilDBConstants::MYSQL_ENGINE_INNODB)
doesCollationSupportMB4Strings()
locate($a_needle, $a_string, $a_start_pos=1)
Create locate string.
replace($a_table, $a_pk_columns, $a_other_columns)
Replace into method.
beginTransaction()
Begin Transaction.
checkIndexName($a_name)
Check whether an index name is valid.
like($a_col, $a_type, $a_value="?", $case_insensitive=true)
Like.
fetchObject($a_set)
Fetch row as object from result set.
$engine
Definition: workflow.php:89
getSubType()
Get sub type.
static setErrorHandling($mode=null, $options=null)
Sets how errors generated by this object should be handled.
Definition: PEAR.php:337
uniqueConstraintExists($a_table, array $a_fields)
Checks if a unique constraint exists based on the fields of the unique constraint (not the name) ...
dropIndex($a_table, $a_name="in")
Drop an index from a table.
Definition: class.ilDB.php:995
Class ilAtomQueryLock.
modifyTableColumn($a_table, $a_column, $a_attributes)
Modify a table column Use this only on aleady "abstracted" tables.
Definition: class.ilDB.php:691
dropIndexByFields($a_table, $a_fields)
Drop index by field(s)
Definition: class.ilDB.php:971
$allowed_attributes
Definition: class.ilDB.php:55
addFulltextIndex($a_table, $a_fields, $a_name="in")
Add fulltext index.
Definition: class.ilDB.php:929
getDBPort()
Get database port.
Definition: class.ilDB.php:103
addPrimaryKey($a_table, $a_fields)
Add a primary key to a table.
Definition: class.ilDB.php:839
disconnect()
Disconnect.
Definition: class.ilDB.php:281
Class ilDatabaseException.
supportsFulltext()
Definition: class.ilDB.php:359
supports($feature)
Definition: class.ilDB.php:379
in($a_field, $a_values, $negate=false, $a_type="")
Get abstract in-clause for given array.
addUniqueConstraint($a_table, $a_fields, $a_name="con")
Add a unique constraint to a table.
doConnect()
Standard way to connect to db.
Definition: class.ilDB.php:270
const MDB2_AUTOQUERY_SELECT
Definition: Extended.php:59
getLastInsertId()
Get last insert id.
equals($a_col, $a_value, $a_type, $a_empty_or_null=false)
Use this only on text fields.
setSubType($a_value)
Set sub type.
manipulateF($a_query, $a_types, $a_values)
Formatted manupulate (for DELETE, UPDATE, INSERT).
getDBName()
Get database name.
Definition: class.ilDB.php:163
Interface ilDBInterface.
$a_type
Definition: workflow.php:92
addIndex($table_name, $fields, $index_name='', $fulltext=false)
fetchAssoc($a_set)
Fetch row as associative array from result set.
dropTable($a_name, $a_error_if_not_existing=true)
Drop a table.
Definition: class.ilDB.php:568
quote($a_query, $a_type=null)
Wrapper for quote method.
executeMultiple($a_stmt, $a_data)
Execute a query statement prepared by either prepare() or prepareManip() with multiple data arrays...
unixTimestamp()
Unix timestamp.
createSequence($a_table_name, $a_start=1)
Create a sequence for a table.
prepareManip($a_query, $a_types=null)
Prepare a data manipulation statement to be used with execute.
const MDB2_AUTOQUERY_DELETE
Definition: Extended.php:58
$r
Definition: example_031.php:79
getDBHost()
Get database host.
Definition: class.ilDB.php:123
initConnection()
Initialize the database connection.
Definition: class.ilDB.php:293
setDBPort($a_port)
Set database port.
Definition: class.ilDB.php:93
useSlave($a_val=true)
Use slave.
Definition: class.ilDB.php:409
const MDB2_PREPARE_MANIP
These are just helper constants to more verbosely express parameters to prepare() ...
Definition: MDB2.php:114
substr($a_exp, $a_pos=1, $a_len=-1)
Substring.
checkTableName($a_name)
Check whether a table name is valid.
foreach($_POST as $key=> $value) $res
getDBUser()
Get database user.
Definition: class.ilDB.php:83
getRow($sql, $mode=ilDBConstants::FETCHMODE_OBJECT)
getRow.
& connect($dsn, $options=false)
Create a new MDB2 connection object and connect to the specified database.
Definition: MDB2.php:436
free($a_st)
Free a statement / result set.
supportsSlave()
Supports slave.
Definition: class.ilDB.php:370
supportsTransactions()
Definition: class.ilDB.php:397
cast($a_field_name, $a_dest_type)
quoteIdentifier($a_identifier, $check_option=false)
Quote table and field names.
checkColumnName($a_name)
Check whether a column name is valid.
fromUnixtime($a_expr, $a_to_text=true)
fromUnixtime (makes timestamp out of unix timestamp)
setDBName($a_name)
Set database name.
Definition: class.ilDB.php:153
autoExecute($a_tablename, $a_fields, $a_mode=MDB2_AUTOQUERY_INSERT, $a_where=false)
Wrapper for Pear autoExecute.
setLimit($a_limit, $a_offset=0)
Set limit and offset for a query.
const MDB2_PORTABILITY_ALL
Portability: turn on all portability features.
Definition: MDB2.php:215
getAllowedAttributes()
supportsEngineMigration()
enableResultBuffering($a_status)
En/disable result buffering.
Definition: class.ilDB.php:202
unlockTables()
Unlock tables locked by previous lock table calls.
execute($a_stmt, $a_data=null)
Execute a query statement prepared by either prepare() or prepareManip()
const MDB2_AUTOQUERY_UPDATE
Definition: Extended.php:57
concat(array $a_values, $a_allow_null=true)
Abstraction of SQL function CONCAT.
static isReservedWord($a_word)
Checks whether a word is a reserved word in one of the supported databases.
listTables()
Get all tables.
$query
const LOCK_WRITE
Definition: class.ilDB.php:31
initHostConnection()
Initialize the host connection (no specific database)
Definition: class.ilDB.php:355
handleError($a_res, $a_info="", $a_level="")
Handle MDB2 Errors.
Definition: class.ilDB.php:423
loadMDB2Extensions()
load additional mdb2 extensions and set their constants
Definition: class.ilDB.php:474
insert($a_table, $a_columns)
Convenient method for standard insert statements, example field array:
getDSN()
Get DSN.
connectHost()
Sets up a host connection only (no specific database used).
Definition: class.ilDB.php:312
connect($a_return_false_for_error=false)
Open the connection.
Definition: class.ilDB.php:234
Create styles array
The data for the language used.
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
const LOCK_READ
Definition: class.ilDB.php:32
buildAtomQuery()
queryF($a_query, $a_types, $a_values)
Formatted query (for SELECTS).
$sub_type
Definition: class.ilDB.php:66
Class ilDBPdoMySQLFieldDefinition.
logStatement($sql)
Helper function, should usually not be called.
initFromIniFile($tmpClientIniFile=null)
Init db parameters from ini file.
Definition: class.ilDB.php:211
manipulate($sql)
Data manipulation.
now()
now()
constraintName($a_table, $a_constraint)
Determine contraint name by table name and constraint name.
sanitizeMB4StringIfNotSupported($query)
string to sanitize, all MB4-Characters like emojis will re replaced with ???string sanitized query ...
Database Wrapper.
Definition: class.ilDB.php:29
setDBPassword($a_password)
Set database password.
Definition: class.ilDB.php:133
getDBType()
Get DSN.
commit()
Commit a transaction.
dropPrimaryKey($a_table)
Drop a primary key from a table.
Definition: class.ilDB.php:874
update($a_table, $a_columns, $a_where)
Convenient method for standard update statements, example field array:
& 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&#39;s de...
Definition: PEAR.php:522
getCreateTableOptions()
Get options for the create table statement.
Definition: class.ilDB.php:557
global $ilBench
Definition: ilias.php:18
listSequences()
Get all sequences.
$i
Definition: disco.tpl.php:19
$def
Definition: croninfo.php:21
dropSequence($a_table_name)
Drop a sequence for a table.
getHostDSN()
Should return a valid value, if host connections are possible (connectHost) to create a new database ...
Definition: class.ilDB.php:303
getDBPassword()
Get database password.
Definition: class.ilDB.php:143
if(empty($password)) $table
Definition: pwgen.php:24
This class gives all kind of DB information using the MDB2 manager and reverse module.
equalsNot($a_col, $a_value, $a_type, $a_empty_or_null=false)
Use this only on text fields.
addTableColumn($a_table, $a_column, $a_attributes)
Add table column Use this only on aleady "abstracted" tables.
Definition: class.ilDB.php:637
getSequenceName($table_name)
dropUniqueConstraint($a_table, $a_name="con")
Drop a constraint from a table.
dropTableColumn($a_table, $a_column)
Drop table column Use this only on aleady "abstracted" tables.
Definition: class.ilDB.php:668
getPrimaryKeyIdentifier()
Primary key identifier.
Definition: class.ilDB.php:863
addTypesToArray($a_arr, $a_type, $a_cnt)
Adds a type x times to an array.
dropUniqueConstraintByFields($a_table, $a_fields)
Drop constraint by field(s)
checkColumn($a_col, $a_def)
Check column definition.
alterTable($a_name, $a_changes)
Alter a table in the database This method is DEPRECATED, see http://www.ilias.de/docu/goto.php?target=pg_25354_42&client_id=docu PLEASE USE THE SPECIALIZED METHODS OF THIS CLASS TO CHANGE THE DB SCHEMA.
Definition: class.ilDB.php:617
setDBHost($a_host)
Set database host.
Definition: class.ilDB.php:113
tableColumnExists($a_table, $a_column_name)
Checks for the existence of a table column.
fetchAll($query_result, $fetch_mode=ilDBConstants::FETCHMODE_ASSOC)
renameTable($a_name, $a_new_name)
Rename a table.
Definition: class.ilDB.php:812
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_AUTOQUERY_INSERT
Used by autoPrepare()
Definition: Extended.php:56
static isDbError($a_res)
Check error.
Definition: class.ilDB.php:488
lockTables($a_tables)
Abstraction of lock table.
getDBVersion()
Get DB version.
Definition: class.ilDB.php:176
indexExistsByFields($a_table, $a_fields)
Check if index exists.
Definition: class.ilDB.php:948
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
lower($a_exp)
Upper.
dropFulltextIndex($a_table, $a_name)