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
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 
41 
46  var $db;
47 
52  var $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  var $sub_type;
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 
360  function supportsFulltext()
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 
548  $options = $this->getCreateTableOptions();
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
1263  $allowed_attributes = $this->allowed_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 
2342  function beginTransaction()
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 
2419  function getLastInsertId()
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 }
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:459
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:501
const PEAR_ERROR_CALLBACK
Definition: PEAR.php:35
isFulltextIndex($a_table, $a_name)
Is index a fulltext index?
Definition: class.ilDB.php:970
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
checkColumnDefinition($a_def, $a_modify_mode=false)
Check whether a column definition is valid.
renameTableColumn($a_table, $a_column, $a_new_column)
Rename a table column Use this only on aleady "abstracted" tables.
Definition: class.ilDB.php:793
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.
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
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:90
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.
Class ilAtomQueryLock.
modifyTableColumn($a_table, $a_column, $a_attributes)
Modify a table column Use this only on aleady "abstracted" tables.
Definition: class.ilDB.php:707
dropIndexByFields($a_table, $a_fields)
Drop index by field(s)
Add rich text string
The name of the decorator.
$allowed_attributes
Definition: class.ilDB.php:55
addFulltextIndex($a_table, $a_fields, $a_name="in")
Add fulltext index.
Definition: class.ilDB.php:962
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:871
disconnect()
Disconnect.
Definition: class.ilDB.php:281
Class ilDatabaseException.
supportsFulltext()
Definition: class.ilDB.php:360
supports($feature)
Definition: class.ilDB.php:380
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:272
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:93
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:572
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:408
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.
if(!is_array($argv)) $options
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:371
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:201
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.
const LOCK_WRITE
Definition: class.ilDB.php:31
initHostConnection()
Initialize the host connection (no specific database)
Definition: class.ilDB.php:356
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:233
Create styles array
The data for the language used.
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:210
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:904
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:561
global $ilBench
Definition: ilias.php:18
listSequences()
Get all sequences.
dropSequence($a_table_name)
Drop a sequence for a table.
global $DIC
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
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:649
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:683
getPrimaryKeyIdentifier()
Primary key identifier.
Definition: class.ilDB.php:893
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:628
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:843
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:489
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:981
lower($a_exp)
Upper.
dropFulltextIndex($a_table, $a_name)