ILIAS  release_7 Revision v7.30-3-g800a261c036
class.ilDBPdo.php
Go to the documentation of this file.
1<?php
24abstract 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;
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) {
1467 return $this->supportsTransactions();
1469 return $this->supportsFulltext();
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
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}
$result
if(! $in) $columns
Definition: Utf8Test.php:45
An exception for terminatinating execution or to throw for unit testing.
Class ilAtomQueryLock.
performance measurement class
This class gives all kind of DB information using the database manager and reverse module.
Class ilDBPdoMySQLFieldDefinition.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
upper($a_exp)
supportsTransactions()
update($table_name, $columns, $where)
setUsername($username)
connect($return_false_for_error=false)
renameTable($a_name, $a_new_name)
dropUniqueConstraintByFields($a_table, $a_fields)
concat(array $values, $allow_null=true)
dropPrimaryKey($table_name)
queryRow($query, $types=null, $fetchmode=ilDBConstants::FETCHMODE_DEFAULT)
setDBType($type)
loadModule($module)
sanitizeMB4StringIfNotSupported($query)
string sanitized query
createSequence($table_name, $start=1)
indexExistsByFields($table_name, $fields)
getFieldDefinition()
equals($columns, $value, $type, $emptyOrNull=false)
escape($value, $escape_wildcards=false)
lockTables($tables)
query($query)
quote($value, $type=null)
setStorageEngine($storage_engine)
like($column, $type, $value="?", $case_insensitive=true)
setDBHost($host)
setFieldDefinition($field_definition)
in($field, $values, $negate=false, $type="")
setDBPassword($password)
groupConcat($a_field_name, $a_seperator=",", $a_order=null)
string
prepare($query, $types=null, $result_types=null)
prepareManip($query, $types=null)
addIndex($table_name, $fields, $index_name='', $fulltext=false)
setDBUser($user)
dropIndex($a_table, $a_name="i1")
getLastErrorCode()
setPort($port)
supportsEngineMigration()
checkIndexName($name)
dropUniqueConstraint($a_table, $a_name="con")
getPrimaryKeyIdentifier()
getAllowedAttributes()
array
setPassword($password)
checkTableName($a_name)
executeMultiple($stmt, $a_data)
isFulltextIndex($a_table, $a_name)
Is index a fulltext index?
queryF($query, $types, $values)
getSequenceName($table_name)
tableExists($table_name)
createTable($table_name, $fields, $drop_table=false, $ignore_erros=false)
initFromIniFile($tmpClientIniFile=null)
addUniqueConstraint($table, $fields, $name="con")
getAdditionalAttributes()
supports($feature)
autoExecute($tablename, $fields, $mode=ilDBConstants::AUTOQUERY_INSERT, $where=false)
Generate an insert, update or delete query and call prepare() and execute() on it.
checkColumnName($a_name)
appendLimit($query)
const FEATURE_SLAVE
supportsCollationMigration()
@inheritDoc
manipulateF($query, $types, $values)
checkTableColumns($a_cols)
replace($table, $primaryKeys, $otherColumns)
Replace into method.
static isReservedWord($a_word)
manipulate($query)
numRows($query_result)
checkColumn($a_col, $a_def)
addFulltextIndex($a_table, $a_fields, $a_name="in")
buildManipSQL($table, $table_fields, $mode, $where=false)
uniqueConstraintExists($table, array $fields)
primaryExistsByFields(string $table_name, array $fields)
bool
locate($a_needle, $a_string, $a_start_pos=1)
setDBPort($port)
autoPrepare($table, $table_fields, $mode=ilDBConstants::AUTOQUERY_INSERT, $where=false, $types=null, $result_types=ilDBConstants::PREPARE_MANIP)
constraintName($a_table, $a_constraint)
Determine contraint name by table name and constraint name.
escapePattern($text)
dropTableColumn($table_name, $column_name)
migrateAllTablesToEngine($engine=ilDBConstants::MYSQL_ENGINE_INNODB)
fetchAssoc($query_result)
fromUnixtime($a_expr, $a_to_text=true)
substr($a_exp, $a_pos=1, $a_len=-1)
getIndexName($index_name_base)
addPrimaryKey($table_name, $primary_keys)
dropTable($table_name, $error_if_not_existing=true)
doesCollationSupportMB4Strings()
@inheritDoc
createDatabase($a_name, $a_charset="utf8", $a_collation="")
const FEATURE_TRANSACTIONS
sequenceExists($sequence)
renameTableColumn($table_name, $column_old_name, $column_new_name)
getServerVersion($native=false)
dropSequence($table_name)
insert($table_name, $values)
tableColumnExists($table_name, $column_name)
cast($a_field_name, $a_dest_type)
string;
lower($a_exp)
const FEATURE_FULLTEXT
setDbname($dbname)
quoteIdentifier($identifier, $check_option=false)
checkColumnDefinition($a_def, $a_modify_mode=false)
setCharset($charset)
dropFulltextIndex($a_table, $a_name)
Drop fulltext index.
nextId($table_name)
enableResultBuffering($a_status)
setLimit($limit, $offset=0)
Set the Limit for the next Query.
modifyTableColumn($table, $a_column, $a_attributes)
addTableColumn($table_name, $column_name, $attributes)
initHelpers()
migrateAllTablesToCollation($collation=ilDBConstants::MYSQL_COLLATION_UTF8MB4)
@inheritDoc
fetchObject($query_result)
setHost($host)
dropIndexByFields($table_name, $fields)
queryCol($query, $type=PDO::FETCH_ASSOC, $colnum=0)
useSlave($bool)
Class ilDatabaseException.
INIFile Parser.
Component logger with individual log levels by component id.
Class ilPDOStatement is a Wrapper Class for PDOStatement.
$c
Definition: cli.php:37
for( $i=6;$i< 13;$i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296
global $DIC
Definition: goto.php:24
global $ilBench
Definition: ilias.php:21
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getReservedWords()
Get reserved words.
execute($stmt, $data=array())
fetchAll($query_result, $fetch_mode=ilDBConstants::FETCHMODE_ASSOC)
Interface ilDBPdoInterface.
if($format !==null) $name
Definition: metadata.php:230
$i
Definition: metadata.php:24
$keys
Definition: metadata.php:187
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
$query
$type
foreach($_POST as $key=> $value) $res
global $ilDB
$data
Definition: storeScorm.php:23
$cols
Definition: xhr_table.php:11