ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
class.ilDBPdo.php
Go to the documentation of this file.
1 <?php
24 abstract class ilDBPdo implements ilDBInterface, ilDBPdoInterface
25 {
26  const FEATURE_TRANSACTIONS = 'transactions';
27  const FEATURE_FULLTEXT = 'fulltext';
28  const FEATURE_SLAVE = 'slave';
32  protected $host = '';
36  protected $dbname = '';
40  protected $charset = 'utf8';
44  protected $username = '';
48  protected $password = '';
52  protected $port = 3306;
56  protected $pdo;
60  protected $manager;
64  protected $reverse;
68  protected $limit = null;
72  protected $offset = null;
76  protected $storage_engine = 'MyISAM';
80  protected $dsn = '';
84  protected $attributes = array(
85  // PDO::ATTR_EMULATE_PREPARES => true,
86  PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
87  );
91  protected $db_type = '';
95  protected $error_code = 0;
99  protected $field_definition;
100 
101 
107  public function connect($return_false_for_error = false)
108  {
109  $this->generateDSN();
110  try {
111  $options = $this->getAttributes();
112  $this->pdo = new PDO($this->getDSN(), $this->getUsername(), $this->getPassword(), $options);
113  $this->initHelpers();
114  $this->initSQLMode();
115  } catch (Exception $e) {
116  $this->error_code = $e->getCode();
117  if ($return_false_for_error) {
118  return false;
119  }
120  throw $e;
121  }
122 
123  return ($this->pdo->errorCode() == PDO::ERR_NONE);
124  }
125 
126 
127  abstract public function initHelpers();
128 
129 
130  protected function initSQLMode()
131  {
132  }
133 
134 
138  protected function getAttributes()
139  {
140  $options = $this->attributes;
141  foreach ($this->getAdditionalAttributes() as $k => $v) {
142  $options[$k] = $v;
143  }
144 
145  return $options;
146  }
147 
148 
152  protected function getAdditionalAttributes()
153  {
154  return array();
155  }
156 
157 
161  public function getFieldDefinition()
162  {
164  }
165 
166 
171  {
172  $this->field_definition = $field_definition;
173  }
174 
175 
183  public function createDatabase($a_name, $a_charset = "utf8", $a_collation = "")
184  {
185  $this->setDbname(null);
186  $this->generateDSN();
187  $this->connect(true);
188  try {
189  return $this->query($this->manager->getQueryUtils()->createDatabase($a_name, $a_charset, $a_collation));
190  } catch (PDOException $e) {
191  return false;
192  }
193  }
194 
195 
199  public function getLastErrorCode()
200  {
201  if ($this->pdo instanceof PDO) {
202  return $this->pdo->errorCode();
203  }
204 
205  return $this->error_code;
206  }
207 
208 
212  public function initFromIniFile($tmpClientIniFile = null)
213  {
214  global $DIC;
215 
216  if ($tmpClientIniFile instanceof ilIniFile) {
217  $clientIniFile = $tmpClientIniFile;
218  } else {
219  $ilClientIniFile = null;
220  if ($DIC->offsetExists('ilClientIniFile')) {
221  $clientIniFile = $DIC['ilClientIniFile'];
222  } else {
223  throw new InvalidArgumentException('$tmpClientIniFile is not an instance of ilIniFile');
224  }
225  }
226 
227  $this->setUsername($clientIniFile->readVariable("db", "user"));
228  $this->setHost($clientIniFile->readVariable("db", "host"));
229  $this->setPort((int) $clientIniFile->readVariable("db", "port"));
230  $this->setPassword($clientIniFile->readVariable("db", "pass"));
231  $this->setDbname($clientIniFile->readVariable("db", "name"));
232  $this->setDBType($clientIniFile->readVariable("db", "type"));
233 
234  $this->generateDSN();
235  }
236 
237 
238  public function generateDSN()
239  {
240  $port = $this->getPort() ? ";port=" . $this->getPort() : "";
241  $dbname = $this->getDbname() ? ';dbname=' . $this->getDbname() : '';
242  $host = $this->getHost();
243  $charset = ';charset=' . $this->getCharset();
244  $this->dsn = 'mysql:host=' . $host . $port . $dbname . $charset;
245  }
246 
247 
252  public function quoteIdentifier($identifier, $check_option = false)
253  {
254  return '`' . $identifier . '`';
255  }
256 
257 
263  abstract public function nextId($table_name);
264 
265 
274  public function createTable($table_name, $fields, $drop_table = false, $ignore_erros = false)
275  {
276  // check table name
277  if (!$this->checkTableName($table_name) && !$ignore_erros) {
278  throw new ilDatabaseException("ilDB Error: createTable(" . $table_name . ")");
279  }
280 
281  // check definition array
282  if (!$this->checkTableColumns($fields) && !$ignore_erros) {
283  throw new ilDatabaseException("ilDB Error: createTable(" . $table_name . ")");
284  }
285 
286  if ($drop_table) {
287  $this->dropTable($table_name, false);
288  }
289 
290  return $this->manager->createTable($table_name, $fields, array());
291  }
292 
293 
298  protected function checkTableColumns($a_cols)
299  {
300  foreach ($a_cols as $col => $def) {
301  if (!$this->checkColumn($col, $def)) {
302  return false;
303  }
304  }
305 
306  return true;
307  }
308 
309 
315  protected function checkColumn($a_col, $a_def)
316  {
317  if (!$this->checkColumnName($a_col)) {
318  return false;
319  }
320 
321  if (!$this->checkColumnDefinition($a_def)) {
322  return false;
323  }
324 
325  return true;
326  }
327 
328 
334  protected function checkColumnDefinition($a_def, $a_modify_mode = false)
335  {
336  return $this->field_definition->checkColumnDefinition($a_def);
337  }
338 
339 
344  public function checkColumnName($a_name)
345  {
346  return $this->field_definition->checkColumnName($a_name);
347  }
348 
349 
356  public function addPrimaryKey($table_name, $primary_keys)
357  {
358  assert(is_array($primary_keys));
359 
360  $fields = array();
361  foreach ($primary_keys as $f) {
362  $fields[$f] = array();
363  }
364  $definition = array(
365  'primary' => true,
366  'fields' => $fields,
367  );
368  $this->manager->createConstraint($table_name, $this->constraintName($table_name, $this->getPrimaryKeyIdentifier()), $definition);
369 
370  return true;
371  }
372 
373 
380  public function dropIndexByFields($table_name, $fields)
381  {
382  foreach ($this->manager->listTableIndexes($table_name) as $idx_name) {
383  $def = $this->reverse->getTableIndexDefinition($table_name, $idx_name);
384  $idx_fields = array_keys((array) $def['fields']);
385 
386  if ($idx_fields === $fields) {
387  return $this->dropIndex($table_name, $idx_name);
388  }
389  }
390 
391  return false;
392  }
393 
394 
398  public function getPrimaryKeyIdentifier()
399  {
400  return "PRIMARY";
401  }
402 
403 
408  public function createSequence($table_name, $start = 1)
409  {
410  $this->manager->createSequence($table_name, $start);
411  }
412 
413 
419  public function tableExists($table_name)
420  {
421  $result = $this->pdo->prepare("SHOW TABLES LIKE :table_name");
422  $result->execute(array('table_name' => $table_name));
423  $return = $result->rowCount();
424  $result->closeCursor();
425 
426  return $return > 0;
427  }
428 
429 
436  public function tableColumnExists($table_name, $column_name)
437  {
438  $fields = $this->loadModule(ilDBConstants::MODULE_MANAGER)->listTableFields($table_name);
439 
440  $in_array = in_array($column_name, $fields);
441 
442  return $in_array;
443  }
444 
445 
453  public function addTableColumn($table_name, $column_name, $attributes)
454  {
455  if (!$this->checkColumnName($column_name)) {
456  throw new ilDatabaseException("ilDB Error: addTableColumn(" . $table_name . ", " . $column_name . ")");
457  }
458  if (!$this->checkColumnDefinition($attributes)) {
459  throw new ilDatabaseException("ilDB Error: addTableColumn(" . $table_name . ", " . $column_name . ")");
460  }
461 
462  $changes = array(
463  "add" => array(
464  $column_name => $attributes,
465  ),
466  );
467 
468  return $this->manager->alterTable($table_name, $changes, false);
469  }
470 
471 
478  public function dropTable($table_name, $error_if_not_existing = true)
479  {
480  $ilDBPdoManager = $this->loadModule(ilDBConstants::MODULE_MANAGER);
481  $tables = $ilDBPdoManager->listTables();
482  $table_exists = in_array($table_name, $tables);
483  if (!$table_exists && $error_if_not_existing) {
484  throw new ilDatabaseException("Table {$table_name} does not exist");
485  }
486 
487  // drop sequence
488  $sequences = $ilDBPdoManager->listSequences();
489  if (in_array($table_name, $sequences)) {
490  $ilDBPdoManager->dropSequence($table_name);
491  }
492 
493  // drop table
494  if ($table_exists) {
495  $ilDBPdoManager->dropTable($table_name);
496  }
497 
498  return true;
499  }
500 
501 
508  public function query($query)
509  {
510  global $DIC;
511  $ilBench = $DIC['ilBench'] ?? null;
512 
513  $query = $this->appendLimit($query);
514 
515  try {
516  if ($ilBench instanceof ilBenchmark) {
517  $ilBench->startDbBench($query);
518  }
519  $res = $this->pdo->query($query);
520  if ($ilBench instanceof ilBenchmark) {
521  $ilBench->stopDbBench();
522  }
523  } catch (PDOException $e) {
524  throw new ilDatabaseException($e->getMessage() . ' QUERY: ' . $query);
525  }
526 
527  $err = $this->pdo->errorCode();
528  if ($err != PDO::ERR_NONE) {
529  $info = $this->pdo->errorInfo();
530  $info_message = $info[2];
531  throw new ilDatabaseException($info_message . ' QUERY: ' . $query);
532  }
533 
534  return new ilPDOStatement($res);
535  }
536 
537 
543  public function fetchAll($query_result, $fetch_mode = ilDBConstants::FETCHMODE_ASSOC)
544  {
548  $return = array();
549  while ($data = $query_result->fetch($fetch_mode)) {
550  $return[] = $data;
551  }
552 
553  return $return;
554  }
555 
556 
560  public function dropSequence($table_name)
561  {
562  $this->manager->dropSequence($table_name);
563  }
564 
565 
572  public function dropTableColumn($table_name, $column_name)
573  {
574  $changes = array(
575  "remove" => array(
576  $column_name => array(),
577  ),
578  );
579 
580  return $this->manager->alterTable($table_name, $changes, false);
581  }
582 
583 
591  public function renameTableColumn($table_name, $column_old_name, $column_new_name)
592  {
593  // check table name
594  if (!$this->checkColumnName($column_new_name)) {
595  throw new ilDatabaseException("ilDB Error: renameTableColumn(" . $table_name . "," . $column_old_name . "," . $column_new_name . ")");
596  }
597 
598  $def = $this->reverse->getTableFieldDefinition($table_name, $column_old_name);
599 
600  $analyzer = new ilDBAnalyzer($this);
601  $best_alt = $analyzer->getBestDefinitionAlternative($def);
602  $def = $def[$best_alt];
603  unset($def["nativetype"]);
604  unset($def["mdb2type"]);
605 
606  $f["definition"] = $def;
607  $f["name"] = $column_new_name;
608 
609  $changes = array(
610  "rename" => array(
611  $column_old_name => $f,
612  ),
613  );
614 
615  return $this->manager->alterTable($table_name, $changes, false);
616  }
617 
618 
624  public function insert($table_name, $values)
625  {
626  $real = array();
627  $fields = array();
628  foreach ($values as $key => $val) {
629  $real[] = $this->quote($val[1], $val[0]);
630  $fields[] = $this->quoteIdentifier($key);
631  }
632  $values = implode(",", $real);
633  $fields = implode(",", $fields);
634  $query = "INSERT INTO " . $this->quoteIdentifier($table_name) . " (" . $fields . ") VALUES (" . $values . ")";
635 
637 
638  return $this->pdo->exec($query);
639  }
640 
641 
647  public function fetchObject($query_result)
648  {
649  $res = $query_result->fetchObject();
650  if ($res == null) {
651  $query_result->closeCursor();
652 
653  return null;
654  }
655 
656  return $res;
657  }
658 
659 
666  public function update($table_name, $columns, $where)
667  {
668  $fields = array();
669  $field_values = array();
670  $placeholders = array();
671  $placeholders_full = array();
672  $types = array();
673  $values = array();
674  $lobs = false;
675  $lob = array();
676  foreach ($columns as $k => $col) {
677  $field_value = $col[1];
678  $fields[] = $k;
679  $placeholders[] = "%s";
680  $placeholders_full[] = ":$k";
681  $types[] = $col[0];
682 
683  if ($col[0] == "blob" || $col[0] == "clob" || $col[0] == 'text') {
684  $field_value = $this->sanitizeMB4StringIfNotSupported($field_value);
685  }
686 
687  // integer auto-typecast (this casts bool values to integer)
688  if ($col[0] == 'integer' && !is_null($field_value)) {
689  $field_value = (int) $field_value;
690  }
691 
692  $values[] = $field_value;
693  $field_values[$k] = $field_value;
694  if ($col[0] == "blob" || $col[0] == "clob") {
695  $lobs = true;
696  $lob[$k] = $k;
697  }
698  }
699 
700  if ($lobs) {
701  $q = "UPDATE " . $this->quoteIdentifier($table_name) . " SET ";
702  $lim = "";
703  foreach ($fields as $k => $field) {
704  $q .= $lim . $this->quoteIdentifier($field) . " = " . $placeholders_full[$k];
705  $lim = ", ";
706  }
707  $q .= " WHERE ";
708  $lim = "";
709  foreach ($where as $k => $col) {
710  $q .= $lim . $this->quoteIdentifier($k) . " = " . $this->quote($col[1], $col[0]);
711  $lim = " AND ";
712  }
713 
714  $r = $this->prepareManip($q, $types);
715  $this->execute($r, $field_values);
716  $this->free($r);
717  } else {
718  foreach ($where as $k => $col) {
719  $types[] = $col[0];
720  $values[] = $col[1];
721  $field_values[$k] = $col;
722  }
723  $q = "UPDATE " . $this->quoteIdentifier($table_name) . " SET ";
724  $lim = "";
725  foreach ($fields as $k => $field) {
726  $q .= $lim . $this->quoteIdentifier($field) . " = " . $placeholders[$k];
727  $lim = ", ";
728  }
729  $q .= " WHERE ";
730  $lim = "";
731  foreach ($where as $k => $col) {
732  $q .= $lim . $this->quoteIdentifier($k) . " = %s";
733  $lim = " AND ";
734  }
735 
736  $r = $this->manipulateF($q, $types, $values);
737  }
738 
739  return $r;
740  }
741 
742 
743 
749  public function manipulate($query)
750  {
751  global $DIC;
752  $ilBench = $DIC['ilBench'] ?? null;
753  try {
755  if ($ilBench instanceof ilBenchmark) {
756  $ilBench->startDbBench($query);
757  }
758  $r = $this->pdo->exec($query);
759  if ($ilBench instanceof ilBenchmark) {
760  $ilBench->stopDbBench();
761  }
762  } catch (PDOException $e) {
763  throw new ilDatabaseException($e->getMessage() . ' QUERY: ' . $query);
764  }
765 
766  return $r;
767  }
768 
769 
775  public function fetchAssoc($query_result)
776  {
777  $res = $query_result->fetch(PDO::FETCH_ASSOC);
778  if ($res == null) {
779  $query_result->closeCursor();
780 
781  return null;
782  }
783 
784  return $res;
785  }
786 
787 
793  public function numRows($query_result)
794  {
795  return $query_result->rowCount();
796  }
797 
798 
805  public function quote($value, $type = null)
806  {
807  if ($value === null) {
808  return 'NULL';
809  }
810 
811  $pdo_type = PDO::PARAM_STR;
812  switch ($type) {
816  if ($value === '') {
817  return 'NULL';
818  }
819  if ($value === $this->now()) {
820  return $value;
821  }
822  break;
824  $value = (int) $value;
825 
826  return $value;
827  break;
829  $pdo_type = PDO::PARAM_INT;
830  break;
832  default:
833  $pdo_type = PDO::PARAM_STR;
834  break;
835  }
836 
837  return $this->pdo->quote($value, $pdo_type);
838  }
839 
840 
847  public function indexExistsByFields($table_name, $fields)
848  {
849  foreach ($this->manager->listTableIndexes($table_name) as $idx_name) {
850  $def = $this->reverse->getTableIndexDefinition($table_name, $idx_name);
851  $idx_fields = array_keys((array) $def['fields']);
852 
853  if ($idx_fields === $fields) {
854  return true;
855  }
856  }
857 
858  return false;
859  }
860 
861 
868  public function addIndex($table_name, $fields, $index_name = '', $fulltext = false)
869  {
870  assert(is_array($fields));
871  $this->field_definition->checkIndexName($index_name);
872 
873  $definition_fields = array();
874  foreach ($fields as $f) {
875  $definition_fields[$f] = array();
876  }
877  $definition = array(
878  'fields' => $definition_fields,
879  );
880 
881  if (!$fulltext) {
882  $this->manager->createIndex($table_name, $this->constraintName($table_name, $index_name), $definition);
883  } else {
884  if ($this->supportsFulltext()) {
885  $this->addFulltextIndex($table_name, $fields, $index_name); // TODO
886  }
887  }
888 
889  return true;
890  }
891 
892 
900  public function addFulltextIndex($a_table, $a_fields, $a_name = "in")
901  {
902  $i_name = $this->constraintName($a_table, $a_name) . "_idx";
903  $f_str = implode(",", $a_fields);
904  $q = "ALTER TABLE $a_table ADD FULLTEXT $i_name ($f_str)";
905  $this->query($q);
906  }
907 
908 
912  public function dropFulltextIndex($a_table, $a_name)
913  {
914  $i_name = $this->constraintName($a_table, $a_name) . "_idx";
915  $this->query("ALTER TABLE $a_table DROP FULLTEXT $i_name");
916  }
917 
918 
922  public function isFulltextIndex($a_table, $a_name)
923  {
924  $set = $this->query("SHOW INDEX FROM " . $a_table);
925  while ($rec = $this->fetchAssoc($set)) {
926  if ($rec["Key_name"] == $a_name && $rec["Index_type"] == "FULLTEXT") {
927  return true;
928  }
929  }
930 
931  return false;
932  }
933 
934 
939  public function getIndexName($index_name_base)
940  {
941  return sprintf(ilDBPdoFieldDefinition::INDEX_FORMAT, preg_replace('/[^a-z0-9_\$]/i', '_', $index_name_base));
942  }
943 
944 
949  public function getSequenceName($table_name)
950  {
951  return sprintf(ilDBPdoFieldDefinition::SEQUENCE_FORMAT, preg_replace('/[^a-z0-9_\$.]/i', '_', $table_name));
952  }
953 
954 
959  public function constraintName($a_table, $a_constraint)
960  {
961  return $a_constraint;
962  }
963 
964 
968  public function getDSN()
969  {
970  return $this->dsn;
971  }
972 
973 
977  public function getDBType()
978  {
979  return $this->db_type;
980  }
981 
982 
987  public function setDBType($type)
988  {
989  $this->db_type = $type;
990  }
991 
992 
997  public static function getReservedWords()
998  {
999  global $DIC;
1000  $ilDB = $DIC->database();
1001 
1005  return $ilDB->getFieldDefinition()->getReservedMysql();
1006  }
1007 
1008 
1013  public function lockTables($tables)
1014  {
1015  assert(is_array($tables));
1016 
1017  $lock = $this->manager->getQueryUtils()->lock($tables);
1018  global $DIC;
1019  $ilLogger = $DIC->logger()->root();
1020  if ($ilLogger instanceof ilLogger) {
1021  $ilLogger->log('ilDB::lockTables(): ' . $lock);
1022  }
1023 
1024  $this->pdo->exec($lock);
1025  }
1026 
1027 
1032  public function unlockTables()
1033  {
1034  $this->pdo->exec($this->manager->getQueryUtils()->unlock());
1035  }
1036 
1037 
1045  public function in($field, $values, $negate = false, $type = "")
1046  {
1047  return $this->manager->getQueryUtils()->in($field, $values, $negate, $type);
1048  }
1049 
1050 
1058  public function queryF($query, $types, $values)
1059  {
1060  if (!is_array($types) || !is_array($values) || count($types) != count($values)) {
1061  throw new ilDatabaseException("ilDB::queryF: Types and values must be arrays of same size. ($query)");
1062  }
1063  $quoted_values = array();
1064  foreach ($types as $k => $t) {
1065  $quoted_values[] = $this->quote($values[$k], $t);
1066  }
1067  $query = vsprintf($query, $quoted_values);
1068 
1069  return $this->query($query);
1070  }
1071 
1072 
1080  public function manipulateF($query, $types, $values)
1081  {
1082  if (!is_array($types) || !is_array($values) || count($types) != count($values)) {
1083  throw new ilDatabaseException("ilDB::manipulateF: types and values must be arrays of same size. ($query)");
1084  }
1085  $quoted_values = array();
1086  foreach ($types as $k => $t) {
1087  $quoted_values[] = $this->quote($values[$k], $t);
1088  }
1089  $query = vsprintf($query, $quoted_values);
1090 
1091  return $this->manipulate($query);
1092  }
1093 
1094 
1101  public function useSlave($bool)
1102  {
1103  return false;
1104  }
1105 
1106 
1113  public function setLimit($limit, $offset = 0)
1114  {
1115  $this->limit = $limit;
1116  $this->offset = $offset;
1117  }
1118 
1119 
1128  public function like($column, $type, $value = "?", $case_insensitive = true)
1129  {
1130  return $this->manager->getQueryUtils()->like($column, $type, $value, $case_insensitive);
1131  }
1132 
1133 
1137  public function now()
1138  {
1139  return $this->manager->getQueryUtils()->now();
1140  }
1141 
1142 
1151  public function replace($table, $primaryKeys, $otherColumns)
1152  {
1153  $a_columns = array_merge($primaryKeys, $otherColumns);
1154  $fields = array();
1155  $field_values = array();
1156  $placeholders = array();
1157  $types = array();
1158  $values = array();
1159 
1160  foreach ($a_columns as $k => $col) {
1161  $fields[] = $this->quoteIdentifier($k);
1162  $placeholders[] = "%s";
1163  $placeholders2[] = ":$k";
1164  $types[] = $col[0];
1165 
1166  // integer auto-typecast (this casts bool values to integer)
1167  if ($col[0] == 'integer' && !is_null($col[1])) {
1168  $col[1] = (int) $col[1];
1169  }
1170 
1171  $values[] = $col[1];
1172  $field_values[$k] = $col[1];
1173  }
1174 
1175  $q = "REPLACE INTO " . $table . " (" . implode(",", $fields) . ") VALUES (" . implode(",", $placeholders) . ")";
1176 
1177  $r = $this->manipulateF($q, $types, $values);
1178 
1179  return $r;
1180  }
1181 
1182 
1190  public function equals($columns, $value, $type, $emptyOrNull = false)
1191  {
1192  if (!$emptyOrNull || $value != "") {
1193  return $columns . " = " . $this->quote($value, $type);
1194  } else {
1195  return "(" . $columns . " = '' OR $columns IS NULL)";
1196  }
1197  }
1198 
1199 
1203  public function getHost()
1204  {
1205  return $this->host;
1206  }
1207 
1208 
1212  public function setHost($host)
1213  {
1214  $this->host = $host;
1215  }
1216 
1217 
1221  public function getDbname()
1222  {
1223  return $this->dbname;
1224  }
1225 
1226 
1230  public function setDbname($dbname)
1231  {
1232  $this->dbname = $dbname;
1233  }
1234 
1235 
1239  public function getCharset()
1240  {
1241  return $this->charset;
1242  }
1243 
1244 
1248  public function setCharset($charset)
1249  {
1250  $this->charset = $charset;
1251  }
1252 
1253 
1257  public function getUsername()
1258  {
1259  return $this->username;
1260  }
1261 
1262 
1266  public function setUsername($username)
1267  {
1268  $this->username = $username;
1269  }
1270 
1271 
1275  public function getPassword()
1276  {
1277  return $this->password;
1278  }
1279 
1280 
1284  public function setPassword($password)
1285  {
1286  $this->password = $password;
1287  }
1288 
1289 
1293  public function getPort()
1294  {
1295  return $this->port;
1296  }
1297 
1298 
1302  public function setPort($port)
1303  {
1304  $this->port = $port;
1305  }
1306 
1307 
1311  public function setDBUser($user)
1312  {
1313  $this->setUsername($user);
1314  }
1315 
1316 
1320  public function setDBPort($port)
1321  {
1322  $this->setPort($port);
1323  }
1324 
1325 
1329  public function setDBPassword($password)
1330  {
1331  $this->setPassword($password);
1332  }
1333 
1334 
1338  public function setDBHost($host)
1339  {
1340  $this->setHost($host);
1341  }
1342 
1343 
1348  public function upper($a_exp)
1349  {
1350  return " UPPER(" . $a_exp . ") ";
1351  }
1352 
1353 
1358  public function lower($a_exp)
1359  {
1360  return " LOWER(" . $a_exp . ") ";
1361  }
1362 
1363 
1370  public function substr($a_exp, $a_pos = 1, $a_len = -1)
1371  {
1372  $lenstr = "";
1373  if ($a_len > -1) {
1374  $lenstr = ", " . $a_len;
1375  }
1376 
1377  return " SUBSTR(" . $a_exp . ", " . $a_pos . $lenstr . ") ";
1378  }
1379 
1380 
1386  public function prepareManip($query, $types = null)
1387  {
1388  return new ilPDOStatement($this->pdo->prepare($query));
1389  }
1390 
1391 
1398  public function prepare($query, $types = null, $result_types = null)
1399  {
1400  return new ilPDOStatement($this->pdo->prepare($query));
1401  }
1402 
1403 
1407  public function enableResultBuffering($a_status)
1408  {
1409  $this->pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, $a_status);
1410  }
1411 
1412 
1419  public function execute($stmt, $data = array())
1420  {
1424  $result = $stmt->execute($data);
1425  if ($result === false) {
1426  throw new ilDatabaseException(implode(', ', $stmt->errorInfo()), $stmt->errorCode());
1427  }
1428  return $stmt;
1429  }
1430 
1431 
1435  public function supportsSlave()
1436  {
1437  return false;
1438  }
1439 
1440 
1444  public function supportsFulltext()
1445  {
1446  return false;
1447  }
1448 
1449 
1453  public function supportsTransactions()
1454  {
1455  return false;
1456  }
1457 
1458 
1463  public function supports($feature)
1464  {
1465  switch ($feature) {
1466  case self::FEATURE_TRANSACTIONS:
1467  return $this->supportsTransactions();
1468  case self::FEATURE_FULLTEXT:
1469  return $this->supportsFulltext();
1470  case self::FEATURE_SLAVE:
1471  return $this->supportsSlave();
1472  default:
1473  return false;
1474  }
1475  }
1476 
1477 
1481  public function listTables()
1482  {
1483  return $this->manager->listTables();
1484  }
1485 
1486 
1491  public function loadModule($module)
1492  {
1493  switch ($module) {
1495  return $this->manager;
1497  return $this->reverse;
1498  }
1499  }
1500 
1501 
1505  public function getAllowedAttributes()
1506  {
1507  return $this->field_definition->getAllowedAttributes();
1508  }
1509 
1510 
1515  public function sequenceExists($sequence)
1516  {
1517  return in_array($sequence, $this->listSequences());
1518  }
1519 
1520 
1524  public function listSequences()
1525  {
1526  return $this->manager->listSequences();
1527  }
1528 
1529 
1535  public function concat(array $values, $allow_null = true)
1536  {
1537  return $this->manager->getQueryUtils()->concat($values, $allow_null);
1538  }
1539 
1540 
1545  protected function appendLimit($query)
1546  {
1547  if ($this->limit !== null && $this->offset !== null) {
1548  $query .= ' LIMIT ' . (int) $this->offset . ', ' . (int) $this->limit;
1549  $this->limit = null;
1550  $this->offset = null;
1551 
1552  return $query;
1553  }
1554 
1555  return $query;
1556  }
1557 
1558 
1565  public function locate($a_needle, $a_string, $a_start_pos = 1)
1566  {
1567  return $this->manager->getQueryUtils()->locate($a_needle, $a_string, $a_start_pos);
1568  }
1569 
1570 
1578  public function modifyTableColumn($table, $a_column, $a_attributes)
1579  {
1580  $def = $this->reverse->getTableFieldDefinition($table, $a_column);
1581 
1582  $analyzer = new ilDBAnalyzer($this);
1583  $best_alt = $analyzer->getBestDefinitionAlternative($def);
1584  $def = $def[$best_alt];
1585  unset($def["nativetype"]);
1586  unset($def["mdb2type"]);
1587 
1588  // check attributes
1589  $ilDBPdoFieldDefinition = $this->field_definition;
1590 
1591  $type = ($a_attributes["type"] ?? "" != "") ? $a_attributes["type"] : $def["type"];
1592  foreach ($def as $k => $v) {
1593  if ($k != "type" && !$ilDBPdoFieldDefinition->isAllowedAttribute($k, $type)) {
1594  unset($def[$k]);
1595  }
1596  }
1597  $check_array = $def;
1598  foreach ($a_attributes as $k => $v) {
1599  $check_array[$k] = $v;
1600  }
1601  if (!$this->checkColumnDefinition($check_array, true)) {
1602  throw new ilDatabaseException("ilDB Error: modifyTableColumn(" . $table . ", " . $a_column . ")");
1603  }
1604 
1605  foreach ($a_attributes as $a => $v) {
1606  $def[$a] = $v;
1607  }
1608 
1609  $a_attributes["definition"] = $def;
1610 
1611  $changes = array(
1612  "change" => array(
1613  $a_column => $a_attributes,
1614  ),
1615  );
1616 
1617  return $this->manager->alterTable($table, $changes, false);
1618  }
1619 
1620 
1625  public function free($a_st)
1626  {
1630  return $a_st->closeCursor();
1631  }
1632 
1633 
1640  public function renameTable($a_name, $a_new_name)
1641  {
1642  // check table name
1643  try {
1644  $this->checkTableName($a_new_name);
1645  } catch (ilDatabaseException $e) {
1646  throw new ilDatabaseException("ilDB Error: renameTable(" . $a_name . "," . $a_new_name . ")<br />" . $e->getMessage());
1647  }
1648 
1649  $this->manager->alterTable($a_name, ["name" => $a_new_name], false);
1650  if ($this->sequenceExists($a_name)) {
1651  $this->manager->alterTable($this->getSequenceName($a_name), ["name" => $this->getSequenceName($a_new_name)], false);
1652  }
1653  // The abstraction_progress is no longer used in ILIAS, see http://www.ilias.de/mantis/view.php?id=19513
1654  // $query = "UPDATE abstraction_progress " . "SET table_name = " . $this->quote($a_new_name, 'text') . " " . "WHERE table_name = "
1655  // . $this->quote($a_name, 'text');
1656  // $this->pdo->query($query);
1657 
1658  return true;
1659  }
1660 
1661 
1667  public function checkTableName($a_name)
1668  {
1669  return $this->field_definition->checkTableName($a_name);
1670  }
1671 
1672 
1677  public static function isReservedWord($a_word)
1678  {
1679  global $DIC;
1680  $ilDBPdoMySQLFieldDefinition = new ilDBPdoMySQLFieldDefinition($DIC->database());
1681 
1682  return $ilDBPdoMySQLFieldDefinition->isReserved($a_word);
1683  }
1684 
1685 
1690  public function beginTransaction()
1691  {
1692  if (!$this->supports(self::FEATURE_TRANSACTIONS)) {
1693  throw new ilDatabaseException("ilDB::beginTransaction: Transactions are not supported.");
1694  }
1695 
1696  return $this->pdo->beginTransaction();
1697  }
1698 
1699 
1704  public function commit()
1705  {
1706  if (!$this->supports(self::FEATURE_TRANSACTIONS)) {
1707  throw new ilDatabaseException("ilDB::beginTransaction: Transactions are not supported.");
1708  }
1709 
1710  return $this->pdo->commit();
1711  }
1712 
1713 
1718  public function rollback()
1719  {
1720  if (!$this->supports(self::FEATURE_TRANSACTIONS)) {
1721  throw new ilDatabaseException("ilDB::beginTransaction: Transactions are not supported.");
1722  }
1723 
1724  return $this->pdo->rollBack();
1725  }
1726 
1727 
1733  public function dropIndex($a_table, $a_name = "i1")
1734  {
1735  return $this->manager->dropIndex($a_table, $a_name);
1736  }
1737 
1738 
1743  {
1744  $this->storage_engine = $storage_engine;
1745  }
1746 
1747 
1751  public function getStorageEngine()
1752  {
1753  return $this->storage_engine;
1754  }
1755 
1756 
1763  public function queryCol($query, $type = PDO::FETCH_ASSOC, $colnum = 0)
1764  {
1765  switch ($type) {
1767  $type = PDO::FETCH_ASSOC;
1768  break;
1770  $type = PDO::FETCH_OBJ;
1771  break;
1772  default:
1773  $type = PDO::FETCH_ASSOC;
1774  break;
1775  }
1776 
1777  return $this->pdo->query($query, PDO::FETCH_ASSOC)->fetchAll(PDO::FETCH_COLUMN, $colnum);
1778  }
1779 
1780 
1787  public function queryRow($query, $types = null, $fetchmode = ilDBConstants::FETCHMODE_DEFAULT)
1788  {
1789  switch ($fetchmode) {
1791  $type = PDO::FETCH_ASSOC;
1792  break;
1794  $type = PDO::FETCH_OBJ;
1795  break;
1796  default:
1797  $type = PDO::FETCH_ASSOC;
1798  break;
1799  }
1800 
1801  return $this->pdo->query($query, $type)->fetch();
1802  }
1803 
1804 
1809  public function getServerVersion($native = false)
1810  {
1811  return $this->pdo->query('SELECT VERSION()')->fetchColumn();
1812  }
1813 
1814 
1820  public function escape($value, $escape_wildcards = false)
1821  {
1822  return $value;
1823  }
1824 
1825 
1830  public function escapePattern($text)
1831  {
1832  return $text;
1833  }
1834 
1835 
1841  {
1842  return array();
1843  }
1844 
1845 
1850  {
1851  return array();
1852  }
1853 
1854 
1858  public function supportsCollationMigration()
1859  {
1860  return false;
1861  }
1862 
1863 
1867  public function supportsEngineMigration()
1868  {
1869  return false;
1870  }
1871 
1872 
1878  public function checkIndexName($name)
1879  {
1880  return $this->getFieldDefinition()->checkIndexName($name);
1881  }
1882 
1883 
1891  public function addUniqueConstraint($table, $fields, $name = "con")
1892  {
1893  assert(is_array($fields));
1895 
1896  // check index name
1897  if (!$this->checkIndexName($name)) {
1898  throw new ilDatabaseException("ilDB Error: addUniqueConstraint(" . $table . "," . $name . ")");
1899  }
1900 
1901  $fields_corrected = array();
1902  foreach ($fields as $f) {
1903  $fields_corrected[$f] = array();
1904  }
1905  $definition = array(
1906  'unique' => true,
1907  'fields' => $fields_corrected,
1908  );
1909 
1910  return $manager->createConstraint($table, $this->constraintName($table, $name), $definition);
1911  }
1912 
1913 
1919  public function dropUniqueConstraint($a_table, $a_name = "con")
1920  {
1921  return $this->manager->dropConstraint($a_table, $this->constraintName($a_table, $a_name), false);
1922  }
1923 
1924 
1930  public function dropUniqueConstraintByFields($a_table, $a_fields)
1931  {
1932  $analyzer = new ilDBAnalyzer();
1933  $cons = $analyzer->getConstraintsInformation($a_table);
1934  foreach ($cons as $c) {
1935  if ($c["type"] == "unique" && count($a_fields) == count($c["fields"])) {
1936  $all_in = true;
1937  foreach ($a_fields as $f) {
1938  if (!isset($c["fields"][$f])) {
1939  $all_in = false;
1940  }
1941  }
1942  if ($all_in) {
1943  return $this->dropUniqueConstraint($a_table, $c['name']);
1944  }
1945  }
1946  }
1947 
1948  return false;
1949  }
1950 
1951 
1955  public function getLastInsertId()
1956  {
1957  return $this->pdo->lastInsertId();
1958  }
1959 
1960 
1964  public function buildAtomQuery()
1965  {
1966  return new ilAtomQueryLock($this);
1967  }
1968 
1969 
1975  public function uniqueConstraintExists($table, array $fields)
1976  {
1977  $analyzer = new ilDBAnalyzer();
1978  $cons = $analyzer->getConstraintsInformation($table);
1979  foreach ($cons as $c) {
1980  if ($c["type"] == "unique" && count($fields) == count($c["fields"])) {
1981  $all_in = true;
1982  foreach ($fields as $f) {
1983  if (!isset($c["fields"][$f])) {
1984  $all_in = false;
1985  }
1986  }
1987  if ($all_in) {
1988  return true;
1989  }
1990  }
1991  }
1992 
1993  return false;
1994  }
1995 
1996 
2001  public function dropPrimaryKey($table_name)
2002  {
2003  return $this->manager->dropConstraint($table_name, "PRIMARY", true);
2004  }
2005 
2006 
2011  public function executeMultiple($stmt, $a_data)
2012  {
2013  for ($i = 0, $j = count($a_data); $i < $j; $i++) {
2014  $stmt->execute($a_data[$i]);
2015  }
2016  }
2017 
2018 
2024  public function fromUnixtime($a_expr, $a_to_text = true)
2025  {
2026  return "FROM_UNIXTIME(" . $a_expr . ")";
2027  }
2028 
2029 
2033  public function unixTimestamp()
2034  {
2035  return "UNIX_TIMESTAMP()";
2036  }
2037 
2038 
2054  public function autoExecute($tablename, $fields, $mode = ilDBConstants::AUTOQUERY_INSERT, $where = false)
2055  {
2056  $fields_values = (array) $fields;
2057  if ($mode == ilDBConstants::AUTOQUERY_INSERT) {
2058  if (!empty($fields_values)) {
2059  $keys = $fields_values;
2060  } else {
2061  $keys = array();
2062  }
2063  } else {
2064  $keys = array_keys($fields_values);
2065  }
2066  $params = array_values($fields_values);
2067  if (empty($params)) {
2068  $query = $this->buildManipSQL($tablename, $keys, $mode, $where);
2069  $result = $this->pdo->query($query);
2070  } else {
2071  $stmt = $this->autoPrepare($tablename, $keys, $mode, $where, $types, $result_types);
2072  $this->execute($stmt);
2073  $this->free($stmt);
2074  $result = $stmt;
2075  }
2076 
2077  return $result;
2078  }
2079 
2080 
2090  protected function autoPrepare($table, $table_fields, $mode = ilDBConstants::AUTOQUERY_INSERT, $where = false, $types = null, $result_types = ilDBConstants::PREPARE_MANIP)
2091  {
2092  $query = $this->buildManipSQL($table, $table_fields, $mode, $where);
2093 
2094  return $this->prepare($query, $types, $result_types);
2095  }
2096 
2097 
2106  protected function buildManipSQL($table, $table_fields, $mode, $where = false)
2107  {
2108  if ($this->options['quote_identifier']) {
2109  $table = $this->quoteIdentifier($table);
2110  }
2111 
2112  if (!empty($table_fields) && $this->options['quote_identifier']) {
2113  foreach ($table_fields as $key => $field) {
2114  $table_fields[$key] = $this->quoteIdentifier($field);
2115  }
2116  }
2117 
2118  if ($where !== false && !is_null($where)) {
2119  if (is_array($where)) {
2120  $where = implode(' AND ', $where);
2121  }
2122  $where = ' WHERE ' . $where;
2123  }
2124 
2125  switch ($mode) {
2127  if (empty($table_fields)) {
2128  throw new ilDatabaseException('Insert requires table fields');
2129  }
2130  $cols = implode(', ', $table_fields);
2131  $values = '?' . str_repeat(', ?', (count($table_fields) - 1));
2132 
2133  return 'INSERT INTO ' . $table . ' (' . $cols . ') VALUES (' . $values . ')';
2134  break;
2136  if (empty($table_fields)) {
2137  throw new ilDatabaseException('Update requires table fields');
2138  }
2139  $set = implode(' = ?, ', $table_fields) . ' = ?';
2140  $sql = 'UPDATE ' . $table . ' SET ' . $set . $where;
2141 
2142  return $sql;
2143  break;
2145  $sql = 'DELETE FROM ' . $table . $where;
2146 
2147  return $sql;
2148  break;
2150  $cols = !empty($table_fields) ? implode(', ', $table_fields) : '*';
2151  $sql = 'SELECT ' . $cols . ' FROM ' . $table . $where;
2152 
2153  return $sql;
2154  break;
2155  }
2156 
2157  throw new ilDatabaseException('Syntax error');
2158  }
2159 
2160 
2165  public function getDBVersion()
2166  {
2167  $d = $this->fetchObject($this->query("SELECT VERSION() AS version"));
2168 
2169  return ($d->version ? $d->version : 'Unknown');
2170  }
2171 
2172 
2177  {
2178  if (!$this->doesCollationSupportMB4Strings()) {
2179  $query_replaced = preg_replace(
2180  '/[\x{10000}-\x{10FFFF}]/u',
2182  $query
2183  );
2184  if (!empty($query_replaced)) {
2185  return $query_replaced;
2186  }
2187  }
2188 
2189  return $query;
2190  }
2191 
2196  {
2197  return false;
2198  }
2199 
2200 
2204  public function groupConcat($a_field_name, $a_seperator = ",", $a_order = null)
2205  {
2206  return $this->manager->getQueryUtils()->groupConcat($a_field_name, $a_seperator, $a_order);
2207  }
2208 
2212  public function cast($a_field_name, $a_dest_type)
2213  {
2214  return $this->manager->getQueryUtils()->cast($a_field_name, $a_dest_type);
2215  }
2216 
2220  public function primaryExistsByFields(string $table_name, array $fields) : bool
2221  {
2222  $constraints = $this->manager->listTableConstraints($table_name);
2223 
2224  if (in_array('primary', $constraints)) {
2225  $definitions = $this->reverse->getTableConstraintDefinition($table_name, 'primary');
2226  $primary_fields = array_keys($definitions['fields']);
2227  sort($primary_fields);
2228  sort($fields);
2229 
2230  return $primary_fields === $fields;
2231  }
2232  return false;
2233  }
2234 }
sanitizeMB4StringIfNotSupported($query)
string to sanitize, all MB4-Characters like emojis will re replaced with ???string sanitized query ...
autoPrepare($table, $table_fields, $mode=ilDBConstants::AUTOQUERY_INSERT, $where=false, $types=null, $result_types=ilDBConstants::PREPARE_MANIP)
upper($a_exp)
supportsTransactions()
setPassword($password)
useSlave($bool)
addPrimaryKey($table_name, $primary_keys)
checkTableName($a_name)
setFieldDefinition($field_definition)
escapePattern($text)
$data
Definition: storeScorm.php:23
addIndex($table_name, $fields, $index_name='', $fulltext=false)
static getReservedWords()
Get reserved words.
$c
Definition: cli.php:37
getSequenceName($table_name)
doesCollationSupportMB4Strings()
$result
equals($columns, $value, $type, $emptyOrNull=false)
execute($stmt, $data=array())
$type
Class ilPDOStatement is a Wrapper Class for PDOStatement.
like($column, $type, $value="?", $case_insensitive=true)
queryF($query, $types, $values)
getServerVersion($native=false)
escape($value, $escape_wildcards=false)
setDBPort($port)
Interface ilDBPdoInterface.
numRows($query_result)
dropUniqueConstraint($a_table, $a_name="con")
Class ilAtomQueryLock.
setUsername($username)
supportsCollationMigration()
dropSequence($table_name)
setDBType($type)
sequenceExists($sequence)
update($table_name, $columns, $where)
renameTableColumn($table_name, $column_old_name, $column_new_name)
queryCol($query, $type=PDO::FETCH_ASSOC, $colnum=0)
concat(array $values, $allow_null=true)
quote($value, $type=null)
modifyTableColumn($table, $a_column, $a_attributes)
const FEATURE_FULLTEXT
Class ilDatabaseException.
initHelpers()
executeMultiple($stmt, $a_data)
dropFulltextIndex($a_table, $a_name)
Drop fulltext index.
checkColumnName($a_name)
indexExistsByFields($table_name, $fields)
migrateAllTablesToCollation($collation=ilDBConstants::MYSQL_COLLATION_UTF8MB4)
manipulateF($query, $types, $values)
addFulltextIndex($a_table, $a_fields, $a_name="in")
getAdditionalAttributes()
setHost($host)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
supports($feature)
setDBUser($user)
lockTables($tables)
if($format !==null) $name
Definition: metadata.php:230
autoExecute($tablename, $fields, $mode=ilDBConstants::AUTOQUERY_INSERT, $where=false)
Generate an insert, update or delete query and call prepare() and execute() on it.
dropTable($table_name, $error_if_not_existing=true)
checkTableColumns($a_cols)
queryRow($query, $types=null, $fetchmode=ilDBConstants::FETCHMODE_DEFAULT)
const FEATURE_SLAVE
foreach($_POST as $key=> $value) $res
quoteIdentifier($identifier, $check_option=false)
$keys
Definition: metadata.php:187
dropUniqueConstraintByFields($a_table, $a_fields)
isFulltextIndex($a_table, $a_name)
Is index a fulltext index?
query($query)
replace($table, $primaryKeys, $otherColumns)
Replace into method.
static isReservedWord($a_word)
createTable($table_name, $fields, $drop_table=false, $ignore_erros=false)
getFieldDefinition()
fetchAssoc($query_result)
nextId($table_name)
setCharset($charset)
createDatabase($a_name, $a_charset="utf8", $a_collation="")
tableExists($table_name)
tableColumnExists($table_name, $column_name)
global $DIC
Definition: goto.php:24
dropPrimaryKey($table_name)
getLastErrorCode()
supportsEngineMigration()
setLimit($limit, $offset=0)
Set the Limit for the next Query.
setDbname($dbname)
$query
lower($a_exp)
dropTableColumn($table_name, $column_name)
dropIndexByFields($table_name, $fields)
checkColumn($a_col, $a_def)
groupConcat($a_field_name, $a_seperator=",", $a_order=null)
string
constraintName($a_table, $a_constraint)
Determine contraint name by table name and constraint name.
prepareManip($query, $types=null)
checkIndexName($name)
getPrimaryKeyIdentifier()
loadModule($module)
setDBHost($host)
appendLimit($query)
Class ilDBPdoMySQLFieldDefinition.
createSequence($table_name, $start=1)
in($field, $values, $negate=false, $type="")
getAllowedAttributes()
array
buildManipSQL($table, $table_fields, $mode, $where=false)
setPort($port)
setStorageEngine($storage_engine)
addUniqueConstraint($table, $fields, $name="con")
const FEATURE_TRANSACTIONS
addTableColumn($table_name, $column_name, $attributes)
locate($a_needle, $a_string, $a_start_pos=1)
fromUnixtime($a_expr, $a_to_text=true)
global $ilBench
Definition: ilias.php:21
global $ilDB
enableResultBuffering($a_status)
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
performance measurement class
primaryExistsByFields(string $table_name, array $fields)
bool
insert($table_name, $values)
setDBPassword($password)
cast($a_field_name, $a_dest_type)
string;
Component logger with individual log levels by component id.
This class gives all kind of DB information using the database manager and reverse module...
connect($return_false_for_error=false)
uniqueConstraintExists($table, array $fields)
manipulate($query)
if(! $in) $columns
Definition: Utf8Test.php:45
renameTable($a_name, $a_new_name)
dropIndex($a_table, $a_name="i1")
$cols
Definition: xhr_table.php:11
migrateAllTablesToEngine($engine=ilDBConstants::MYSQL_ENGINE_INNODB)
INIFile Parser.
prepare($query, $types=null, $result_types=null)
fetchObject($query_result)
substr($a_exp, $a_pos=1, $a_len=-1)
initFromIniFile($tmpClientIniFile=null)
fetchAll($query_result, $fetch_mode=ilDBConstants::FETCHMODE_ASSOC)
for($i=6; $i< 13; $i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296
getIndexName($index_name_base)
$i
Definition: metadata.php:24
checkColumnDefinition($a_def, $a_modify_mode=false)