ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
class.ilDBPdo.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
10abstract class ilDBPdo implements ilDBInterface, ilDBPdoInterface
11{
12 const FEATURE_TRANSACTIONS = 'transactions';
13 const FEATURE_FULLTEXT = 'fulltext';
14 const FEATURE_SLAVE = 'slave';
18 protected $host = '';
22 protected $dbname = '';
26 protected $charset = 'utf8';
30 protected $username = '';
34 protected $password = '';
38 protected $port = 3306;
42 protected $pdo;
46 protected $manager;
50 protected $reverse;
54 protected $limit = null;
58 protected $offset = null;
62 protected $storage_engine = 'MyISAM';
66 protected $dsn = '';
70 protected $attributes = array(
71 // PDO::ATTR_EMULATE_PREPARES => true,
72 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
73 );
77 protected $db_type = '';
81 protected $error_code = 0;
86
87
93 public function connect($return_false_for_error = false)
94 {
95 $this->generateDSN();
96 try {
97 $options = $this->getAttributes();
98 $this->pdo = new PDO($this->getDSN(), $this->getUsername(), $this->getPassword(), $options);
99 $this->initHelpers();
100 $this->initSQLMode();
101 } catch (Exception $e) {
102 $this->error_code = $e->getCode();
103 if ($return_false_for_error) {
104 return false;
105 }
106 throw $e;
107 }
108
109 return ($this->pdo->errorCode() == PDO::ERR_NONE);
110 }
111
112
113 abstract public function initHelpers();
114
115
116 protected function initSQLMode()
117 {
118 }
119
120
124 protected function getAttributes()
125 {
126 $options = $this->attributes;
127 foreach ($this->getAdditionalAttributes() as $k => $v) {
128 $options[$k] = $v;
129 }
130
131 return $options;
132 }
133
134
138 protected function getAdditionalAttributes()
139 {
140 return array();
141 }
142
143
147 public function getFieldDefinition()
148 {
150 }
151
152
157 {
158 $this->field_definition = $field_definition;
159 }
160
161
169 public function createDatabase($a_name, $a_charset = "utf8", $a_collation = "")
170 {
171 $this->setDbname(null);
172 $this->generateDSN();
173 $this->connect(true);
174 try {
175 return $this->query($this->manager->getQueryUtils()->createDatabase($a_name, $a_charset, $a_collation));
176 } catch (PDOException $e) {
177 return false;
178 }
179 }
180
181
185 public function getLastErrorCode()
186 {
187 if ($this->pdo instanceof PDO) {
188 return $this->pdo->errorCode();
189 }
190
191 return $this->error_code;
192 }
193
194
198 public function initFromIniFile($tmpClientIniFile = null)
199 {
200 global $DIC;
201
202 if ($tmpClientIniFile instanceof ilIniFile) {
203 $clientIniFile = $tmpClientIniFile;
204 } else {
205 $ilClientIniFile = null;
206 if ($DIC->offsetExists('ilClientIniFile')) {
207 $clientIniFile = $DIC['ilClientIniFile'];
208 } else {
209 throw new InvalidArgumentException('$tmpClientIniFile is not an instance of ilIniFile');
210 }
211 }
212
213 $this->setUsername($clientIniFile->readVariable("db", "user"));
214 $this->setHost($clientIniFile->readVariable("db", "host"));
215 $this->setPort((int) $clientIniFile->readVariable("db", "port"));
216 $this->setPassword($clientIniFile->readVariable("db", "pass"));
217 $this->setDbname($clientIniFile->readVariable("db", "name"));
218 $this->setDBType($clientIniFile->readVariable("db", "type"));
219
220 $this->generateDSN();
221 }
222
223
224 public function generateDSN()
225 {
226 $port = $this->getPort() ? ";port=" . $this->getPort() : "";
227 $dbname = $this->getDbname() ? ';dbname=' . $this->getDbname() : '';
228 $host = $this->getHost();
229 $charset = ';charset=' . $this->getCharset();
230 $this->dsn = 'mysql:host=' . $host . $port . $dbname . $charset;
231 }
232
233
238 public function quoteIdentifier($identifier, $check_option = false)
239 {
240 return '`' . $identifier . '`';
241 }
242
243
249 abstract public function nextId($table_name);
250
251
260 public function createTable($table_name, $fields, $drop_table = false, $ignore_erros = false)
261 {
262 // check table name
263 if (!$this->checkTableName($table_name) && !$ignore_erros) {
264 throw new ilDatabaseException("ilDB Error: createTable(" . $table_name . ")");
265 }
266
267 // check definition array
268 if (!$this->checkTableColumns($fields) && !$ignore_erros) {
269 throw new ilDatabaseException("ilDB Error: createTable(" . $table_name . ")");
270 }
271
272 if ($drop_table) {
273 $this->dropTable($table_name, false);
274 }
275
276 return $this->manager->createTable($table_name, $fields, array());
277 }
278
279
284 protected function checkTableColumns($a_cols)
285 {
286 foreach ($a_cols as $col => $def) {
287 if (!$this->checkColumn($col, $def)) {
288 return false;
289 }
290 }
291
292 return true;
293 }
294
295
301 protected function checkColumn($a_col, $a_def)
302 {
303 if (!$this->checkColumnName($a_col)) {
304 return false;
305 }
306
307 if (!$this->checkColumnDefinition($a_def)) {
308 return false;
309 }
310
311 return true;
312 }
313
314
320 protected function checkColumnDefinition($a_def, $a_modify_mode = false)
321 {
322 return $this->field_definition->checkColumnDefinition($a_def);
323 }
324
325
330 public function checkColumnName($a_name)
331 {
332 return $this->field_definition->checkColumnName($a_name);
333 }
334
335
342 public function addPrimaryKey($table_name, $primary_keys)
343 {
344 assert(is_array($primary_keys));
345
346 $fields = array();
347 foreach ($primary_keys as $f) {
348 $fields[$f] = array();
349 }
350 $definition = array(
351 'primary' => true,
352 'fields' => $fields,
353 );
354 $this->manager->createConstraint($table_name, $this->constraintName($table_name, $this->getPrimaryKeyIdentifier()), $definition);
355
356 return true;
357 }
358
359
366 public function dropIndexByFields($table_name, $fields)
367 {
368 foreach ($this->manager->listTableIndexes($table_name) as $idx_name) {
369 $def = $this->reverse->getTableIndexDefinition($table_name, $idx_name);
370 $idx_fields = array_keys((array) $def['fields']);
371
372 if ($idx_fields === $fields) {
373 return $this->dropIndex($table_name, $idx_name);
374 }
375 }
376
377 return false;
378 }
379
380
384 public function getPrimaryKeyIdentifier()
385 {
386 return "PRIMARY";
387 }
388
389
394 public function createSequence($table_name, $start = 1)
395 {
396 $this->manager->createSequence($table_name, $start);
397 }
398
399
405 public function tableExists($table_name)
406 {
407 $result = $this->pdo->prepare("SHOW TABLES LIKE :table_name");
408 $result->execute(array('table_name' => $table_name));
409 $return = $result->rowCount();
410 $result->closeCursor();
411
412 return $return > 0;
413 }
414
415
422 public function tableColumnExists($table_name, $column_name)
423 {
424 $fields = $this->loadModule(ilDBConstants::MODULE_MANAGER)->listTableFields($table_name);
425
426 $in_array = in_array($column_name, $fields);
427
428 return $in_array;
429 }
430
431
439 public function addTableColumn($table_name, $column_name, $attributes)
440 {
441 if (!$this->checkColumnName($column_name)) {
442 throw new ilDatabaseException("ilDB Error: addTableColumn(" . $table_name . ", " . $column_name . ")");
443 }
444 if (!$this->checkColumnDefinition($attributes)) {
445 throw new ilDatabaseException("ilDB Error: addTableColumn(" . $table_name . ", " . $column_name . ")");
446 }
447
448 $changes = array(
449 "add" => array(
450 $column_name => $attributes,
451 ),
452 );
453
454 return $this->manager->alterTable($table_name, $changes, false);
455 }
456
457
464 public function dropTable($table_name, $error_if_not_existing = true)
465 {
466 $ilDBPdoManager = $this->loadModule(ilDBConstants::MODULE_MANAGER);
467 $tables = $ilDBPdoManager->listTables();
468 $table_exists = in_array($table_name, $tables);
469 if (!$table_exists && $error_if_not_existing) {
470 throw new ilDatabaseException("Table {$table_name} does not exist");
471 }
472
473 // drop sequence
474 $sequences = $ilDBPdoManager->listSequences();
475 if (in_array($table_name, $sequences)) {
476 $ilDBPdoManager->dropSequence($table_name);
477 }
478
479 // drop table
480 if ($table_exists) {
481 $ilDBPdoManager->dropTable($table_name);
482 }
483
484 return true;
485 }
486
487
494 public function query($query)
495 {
496 global $DIC;
497 $ilBench = $DIC['ilBench'];
498
499 $query = $this->appendLimit($query);
500
501 try {
502 if ($ilBench instanceof ilBenchmark) {
503 $ilBench->startDbBench($query);
504 }
505 $res = $this->pdo->query($query);
506 if ($ilBench instanceof ilBenchmark) {
507 $ilBench->stopDbBench();
508 }
509 } catch (PDOException $e) {
510 throw new ilDatabaseException($e->getMessage() . ' QUERY: ' . $query);
511 }
512
513 $err = $this->pdo->errorCode();
514 if ($err != PDO::ERR_NONE) {
515 $info = $this->pdo->errorInfo();
516 $info_message = $info[2];
517 throw new ilDatabaseException($info_message . ' QUERY: ' . $query);
518 }
519
520 return new ilPDOStatement($res);
521 }
522
523
529 public function fetchAll($query_result, $fetch_mode = ilDBConstants::FETCHMODE_ASSOC)
530 {
534 $return = array();
535 while ($data = $query_result->fetch($fetch_mode)) {
536 $return[] = $data;
537 }
538
539 return $return;
540 }
541
542
546 public function dropSequence($table_name)
547 {
548 $this->manager->dropSequence($table_name);
549 }
550
551
558 public function dropTableColumn($table_name, $column_name)
559 {
560 $changes = array(
561 "remove" => array(
562 $column_name => array(),
563 ),
564 );
565
566 return $this->manager->alterTable($table_name, $changes, false);
567 }
568
569
577 public function renameTableColumn($table_name, $column_old_name, $column_new_name)
578 {
579 // check table name
580 if (!$this->checkColumnName($column_new_name)) {
581 throw new ilDatabaseException("ilDB Error: renameTableColumn(" . $table_name . "," . $column_old_name . "," . $column_new_name . ")");
582 }
583
584 $def = $this->reverse->getTableFieldDefinition($table_name, $column_old_name);
585
586 $analyzer = new ilDBAnalyzer($this);
587 $best_alt = $analyzer->getBestDefinitionAlternative($def);
588 $def = $def[$best_alt];
589 unset($def["nativetype"]);
590 unset($def["mdb2type"]);
591
592 $f["definition"] = $def;
593 $f["name"] = $column_new_name;
594
595 $changes = array(
596 "rename" => array(
597 $column_old_name => $f,
598 ),
599 );
600
601 return $this->manager->alterTable($table_name, $changes, false);
602 }
603
604
610 public function insert($table_name, $values)
611 {
612 $real = array();
613 $fields = array();
614 foreach ($values as $key => $val) {
615 $real[] = $this->quote($val[1], $val[0]);
616 $fields[] = $this->quoteIdentifier($key);
617 }
618 $values = implode(",", $real);
619 $fields = implode(",", $fields);
620 $query = "INSERT INTO " . $this->quoteIdentifier($table_name) . " (" . $fields . ") VALUES (" . $values . ")";
621
623
624 return $this->pdo->exec($query);
625 }
626
627
633 public function fetchObject($query_result)
634 {
635 $res = $query_result->fetchObject();
636 if ($res == null) {
637 $query_result->closeCursor();
638
639 return null;
640 }
641
642 return $res;
643 }
644
645
652 public function update($table_name, $columns, $where)
653 {
654 $fields = array();
655 $field_values = array();
656 $placeholders = array();
657 $placeholders_full = array();
658 $types = array();
659 $values = array();
660 $lobs = false;
661 $lob = array();
662 foreach ($columns as $k => $col) {
663 $field_value = $col[1];
664 $fields[] = $k;
665 $placeholders[] = "%s";
666 $placeholders_full[] = ":$k";
667 $types[] = $col[0];
668
669 if ($col[0] == "blob" || $col[0] == "clob" || $col[0] == 'text') {
670 $field_value = $this->sanitizeMB4StringIfNotSupported($field_value);
671 }
672
673 // integer auto-typecast (this casts bool values to integer)
674 if ($col[0] == 'integer' && !is_null($field_value)) {
675 $field_value = (int) $field_value;
676 }
677
678 $values[] = $field_value;
679 $field_values[$k] = $field_value;
680 if ($col[0] == "blob" || $col[0] == "clob") {
681 $lobs = true;
682 $lob[$k] = $k;
683 }
684 }
685
686 if ($lobs) {
687 $q = "UPDATE " . $this->quoteIdentifier($table_name) . " SET ";
688 $lim = "";
689 foreach ($fields as $k => $field) {
690 $q .= $lim . $field . " = " . $placeholders_full[$k];
691 $lim = ", ";
692 }
693 $q .= " WHERE ";
694 $lim = "";
695 foreach ($where as $k => $col) {
696 $q .= $lim . $k . " = " . $this->quote($col[1], $col[0]);
697 $lim = " AND ";
698 }
699
700 $r = $this->prepareManip($q, $types);
701 $this->execute($r, $field_values);
702 $this->free($r);
703 } else {
704 foreach ($where as $k => $col) {
705 $types[] = $col[0];
706 $values[] = $col[1];
707 $field_values[$k] = $col;
708 }
709 $q = "UPDATE " . $this->quoteIdentifier($table_name) . " SET ";
710 $lim = "";
711 foreach ($fields as $k => $field) {
712 $q .= $lim . $this->quoteIdentifier($field) . " = " . $placeholders[$k];
713 $lim = ", ";
714 }
715 $q .= " WHERE ";
716 $lim = "";
717 foreach ($where as $k => $col) {
718 $q .= $lim . $k . " = %s";
719 $lim = " AND ";
720 }
721
722 $r = $this->manipulateF($q, $types, $values);
723 }
724
725 return $r;
726 }
727
728
729
735 public function manipulate($query)
736 {
737 global $DIC;
738 $ilBench = $DIC['ilBench'];
739 try {
741 if ($ilBench instanceof ilBenchmark) {
742 $ilBench->startDbBench($query);
743 }
744 $r = $this->pdo->exec($query);
745 if ($ilBench instanceof ilBenchmark) {
746 $ilBench->stopDbBench();
747 }
748 } catch (PDOException $e) {
749 throw new ilDatabaseException($e->getMessage() . ' QUERY: ' . $query);
750 }
751
752 return $r;
753 }
754
755
761 public function fetchAssoc($query_result)
762 {
763 $res = $query_result->fetch(PDO::FETCH_ASSOC);
764 if ($res == null) {
765 $query_result->closeCursor();
766
767 return null;
768 }
769
770 return $res;
771 }
772
773
779 public function numRows($query_result)
780 {
781 return $query_result->rowCount();
782 }
783
784
791 public function quote($value, $type = null)
792 {
793 if ($value === null) {
794 return 'NULL';
795 }
796
797 $pdo_type = PDO::PARAM_STR;
798 switch ($type) {
802 if ($value === '') {
803 return 'NULL';
804 }
805 break;
807 $value = (int) $value;
808
809 return $value;
810 break;
812 $pdo_type = PDO::PARAM_INT;
813 break;
815 default:
816 $pdo_type = PDO::PARAM_STR;
817 break;
818 }
819
820 return $this->pdo->quote($value, $pdo_type);
821 }
822
823
830 public function indexExistsByFields($table_name, $fields)
831 {
832 foreach ($this->manager->listTableIndexes($table_name) as $idx_name) {
833 $def = $this->reverse->getTableIndexDefinition($table_name, $idx_name);
834 $idx_fields = array_keys((array) $def['fields']);
835
836 if ($idx_fields === $fields) {
837 return true;
838 }
839 }
840
841 return false;
842 }
843
844
851 public function addIndex($table_name, $fields, $index_name = '', $fulltext = false)
852 {
853 assert(is_array($fields));
854 $this->field_definition->checkIndexName($index_name);
855
856 $definition_fields = array();
857 foreach ($fields as $f) {
858 $definition_fields[$f] = array();
859 }
860 $definition = array(
861 'fields' => $definition_fields,
862 );
863
864 if (!$fulltext) {
865 $this->manager->createIndex($table_name, $this->constraintName($table_name, $index_name), $definition);
866 } else {
867 if ($this->supportsFulltext()) {
868 $this->addFulltextIndex($table_name, $fields, $index_name); // TODO
869 }
870 }
871
872 return true;
873 }
874
875
883 public function addFulltextIndex($a_table, $a_fields, $a_name = "in")
884 {
885 $i_name = $this->constraintName($a_table, $a_name) . "_idx";
886 $f_str = implode(",", $a_fields);
887 $q = "ALTER TABLE $a_table ADD FULLTEXT $i_name ($f_str)";
888 $this->query($q);
889 }
890
891
895 public function dropFulltextIndex($a_table, $a_name)
896 {
897 $i_name = $this->constraintName($a_table, $a_name) . "_idx";
898 $this->query("ALTER TABLE $a_table DROP FULLTEXT $i_name");
899 }
900
901
905 public function isFulltextIndex($a_table, $a_name)
906 {
907 $set = $this->query("SHOW INDEX FROM " . $a_table);
908 while ($rec = $this->fetchAssoc($set)) {
909 if ($rec["Key_name"] == $a_name && $rec["Index_type"] == "FULLTEXT") {
910 return true;
911 }
912 }
913
914 return false;
915 }
916
917
922 public function getIndexName($index_name_base)
923 {
924 return sprintf(ilDBPdoFieldDefinition::INDEX_FORMAT, preg_replace('/[^a-z0-9_\$]/i', '_', $index_name_base));
925 }
926
927
932 public function getSequenceName($table_name)
933 {
934 return sprintf(ilDBPdoFieldDefinition::SEQUENCE_FORMAT, preg_replace('/[^a-z0-9_\$.]/i', '_', $table_name));
935 }
936
937
942 public function constraintName($a_table, $a_constraint)
943 {
944 return $a_constraint;
945 }
946
947
951 public function getDSN()
952 {
953 return $this->dsn;
954 }
955
956
960 public function getDBType()
961 {
962 return $this->db_type;
963 }
964
965
970 public function setDBType($type)
971 {
972 $this->db_type = $type;
973 }
974
975
980 public static function getReservedWords()
981 {
982 global $DIC;
983 $ilDB = $DIC->database();
984
988 return $ilDB->getFieldDefinition()->getReservedMysql();
989 }
990
991
996 public function lockTables($tables)
997 {
998 assert(is_array($tables));
999
1000 $lock = $this->manager->getQueryUtils()->lock($tables);
1001 global $DIC;
1002 $ilLogger = $DIC->logger()->root();
1003 if ($ilLogger instanceof ilLogger) {
1004 $ilLogger->log('ilDB::lockTables(): ' . $lock);
1005 }
1006
1007 $this->pdo->exec($lock);
1008 }
1009
1010
1015 public function unlockTables()
1016 {
1017 $this->pdo->exec($this->manager->getQueryUtils()->unlock());
1018 }
1019
1020
1028 public function in($field, $values, $negate = false, $type = "")
1029 {
1030 return $this->manager->getQueryUtils()->in($field, $values, $negate, $type);
1031 }
1032
1033
1041 public function queryF($query, $types, $values)
1042 {
1043 if (!is_array($types) || !is_array($values) || count($types) != count($values)) {
1044 throw new ilDatabaseException("ilDB::queryF: Types and values must be arrays of same size. ($query)");
1045 }
1046 $quoted_values = array();
1047 foreach ($types as $k => $t) {
1048 $quoted_values[] = $this->quote($values[$k], $t);
1049 }
1050 $query = vsprintf($query, $quoted_values);
1051
1052 return $this->query($query);
1053 }
1054
1055
1063 public function manipulateF($query, $types, $values)
1064 {
1065 if (!is_array($types) || !is_array($values) || count($types) != count($values)) {
1066 throw new ilDatabaseException("ilDB::manipulateF: types and values must be arrays of same size. ($query)");
1067 }
1068 $quoted_values = array();
1069 foreach ($types as $k => $t) {
1070 $quoted_values[] = $this->quote($values[$k], $t);
1071 }
1072 $query = vsprintf($query, $quoted_values);
1073
1074 return $this->manipulate($query);
1075 }
1076
1077
1084 public function useSlave($bool)
1085 {
1086 return false;
1087 }
1088
1089
1096 public function setLimit($limit, $offset = 0)
1097 {
1098 $this->limit = $limit;
1099 $this->offset = $offset;
1100 }
1101
1102
1111 public function like($column, $type, $value = "?", $case_insensitive = true)
1112 {
1113 return $this->manager->getQueryUtils()->like($column, $type, $value, $case_insensitive);
1114 }
1115
1116
1120 public function now()
1121 {
1122 return $this->manager->getQueryUtils()->now();
1123 }
1124
1125
1134 public function replace($table, $primaryKeys, $otherColumns)
1135 {
1136 $a_columns = array_merge($primaryKeys, $otherColumns);
1137 $fields = array();
1138 $field_values = array();
1139 $placeholders = array();
1140 $types = array();
1141 $values = array();
1142
1143 foreach ($a_columns as $k => $col) {
1144 $fields[] = $k;
1145 $placeholders[] = "%s";
1146 $placeholders2[] = ":$k";
1147 $types[] = $col[0];
1148
1149 // integer auto-typecast (this casts bool values to integer)
1150 if ($col[0] == 'integer' && !is_null($col[1])) {
1151 $col[1] = (int) $col[1];
1152 }
1153
1154 $values[] = $col[1];
1155 $field_values[$k] = $col[1];
1156 }
1157
1158 $q = "REPLACE INTO " . $table . " (" . implode(",", $fields) . ") VALUES (" . implode(",", $placeholders) . ")";
1159
1160 $r = $this->manipulateF($q, $types, $values);
1161
1162 return $r;
1163 }
1164
1165
1173 public function equals($columns, $value, $type, $emptyOrNull = false)
1174 {
1175 if (!$emptyOrNull || $value != "") {
1176 return $columns . " = " . $this->quote($value, $type);
1177 } else {
1178 return "(" . $columns . " = '' OR $columns IS NULL)";
1179 }
1180 }
1181
1182
1186 public function getHost()
1187 {
1188 return $this->host;
1189 }
1190
1191
1195 public function setHost($host)
1196 {
1197 $this->host = $host;
1198 }
1199
1200
1204 public function getDbname()
1205 {
1206 return $this->dbname;
1207 }
1208
1209
1213 public function setDbname($dbname)
1214 {
1215 $this->dbname = $dbname;
1216 }
1217
1218
1222 public function getCharset()
1223 {
1224 return $this->charset;
1225 }
1226
1227
1231 public function setCharset($charset)
1232 {
1233 $this->charset = $charset;
1234 }
1235
1236
1240 public function getUsername()
1241 {
1242 return $this->username;
1243 }
1244
1245
1249 public function setUsername($username)
1250 {
1251 $this->username = $username;
1252 }
1253
1254
1258 public function getPassword()
1259 {
1260 return $this->password;
1261 }
1262
1263
1267 public function setPassword($password)
1268 {
1269 $this->password = $password;
1270 }
1271
1272
1276 public function getPort()
1277 {
1278 return $this->port;
1279 }
1280
1281
1285 public function setPort($port)
1286 {
1287 $this->port = $port;
1288 }
1289
1290
1294 public function setDBUser($user)
1295 {
1296 $this->setUsername($user);
1297 }
1298
1299
1303 public function setDBPort($port)
1304 {
1305 $this->setPort($port);
1306 }
1307
1308
1312 public function setDBPassword($password)
1313 {
1314 $this->setPassword($password);
1315 }
1316
1317
1321 public function setDBHost($host)
1322 {
1323 $this->setHost($host);
1324 }
1325
1326
1331 public function upper($a_exp)
1332 {
1333 return " UPPER(" . $a_exp . ") ";
1334 }
1335
1336
1341 public function lower($a_exp)
1342 {
1343 return " LOWER(" . $a_exp . ") ";
1344 }
1345
1346
1353 public function substr($a_exp, $a_pos = 1, $a_len = -1)
1354 {
1355 $lenstr = "";
1356 if ($a_len > -1) {
1357 $lenstr = ", " . $a_len;
1358 }
1359
1360 return " SUBSTR(" . $a_exp . ", " . $a_pos . $lenstr . ") ";
1361 }
1362
1363
1369 public function prepareManip($query, $types = null)
1370 {
1371 return new ilPDOStatement($this->pdo->prepare($query));
1372 }
1373
1374
1381 public function prepare($query, $types = null, $result_types = null)
1382 {
1383 return new ilPDOStatement($this->pdo->prepare($query));
1384 }
1385
1386
1390 public function enableResultBuffering($a_status)
1391 {
1392 $this->pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, $a_status);
1393 }
1394
1395
1402 public function execute($stmt, $data = array())
1403 {
1407 $result = $stmt->execute($data);
1408 if ($result === false) {
1409 throw new ilDatabaseException(implode(', ', $stmt->errorInfo()), $stmt->errorCode());
1410 }
1411 return $stmt;
1412 }
1413
1414
1418 public function supportsSlave()
1419 {
1420 return false;
1421 }
1422
1423
1427 public function supportsFulltext()
1428 {
1429 return false;
1430 }
1431
1432
1436 public function supportsTransactions()
1437 {
1438 return false;
1439 }
1440
1441
1446 public function supports($feature)
1447 {
1448 switch ($feature) {
1450 return $this->supportsTransactions();
1452 return $this->supportsFulltext();
1454 return $this->supportsSlave();
1455 default:
1456 return false;
1457 }
1458 }
1459
1460
1464 public function listTables()
1465 {
1466 return $this->manager->listTables();
1467 }
1468
1469
1474 public function loadModule($module)
1475 {
1476 switch ($module) {
1478 return $this->manager;
1480 return $this->reverse;
1481 }
1482 }
1483
1484
1488 public function getAllowedAttributes()
1489 {
1490 return $this->field_definition->getAllowedAttributes();
1491 }
1492
1493
1498 public function sequenceExists($sequence)
1499 {
1500 return in_array($sequence, $this->listSequences());
1501 }
1502
1503
1507 public function listSequences()
1508 {
1509 return $this->manager->listSequences();
1510 }
1511
1512
1518 public function concat(array $values, $allow_null = true)
1519 {
1520 return $this->manager->getQueryUtils()->concat($values, $allow_null);
1521 }
1522
1523
1528 protected function appendLimit($query)
1529 {
1530 if ($this->limit !== null && $this->offset !== null) {
1531 $query .= ' LIMIT ' . (int) $this->offset . ', ' . (int) $this->limit;
1532 $this->limit = null;
1533 $this->offset = null;
1534
1535 return $query;
1536 }
1537
1538 return $query;
1539 }
1540
1541
1548 public function locate($a_needle, $a_string, $a_start_pos = 1)
1549 {
1550 return $this->manager->getQueryUtils()->locate($a_needle, $a_string, $a_start_pos);
1551 }
1552
1553
1561 public function modifyTableColumn($table, $a_column, $a_attributes)
1562 {
1563 $def = $this->reverse->getTableFieldDefinition($table, $a_column);
1564
1565 $analyzer = new ilDBAnalyzer($this);
1566 $best_alt = $analyzer->getBestDefinitionAlternative($def);
1567 $def = $def[$best_alt];
1568 unset($def["nativetype"]);
1569 unset($def["mdb2type"]);
1570
1571 // check attributes
1572 $ilDBPdoFieldDefinition = $this->field_definition;
1573
1574 $type = ($a_attributes["type"] ?? "" != "") ? $a_attributes["type"] : $def["type"];
1575 foreach ($def as $k => $v) {
1576 if ($k != "type" && !$ilDBPdoFieldDefinition->isAllowedAttribute($k, $type)) {
1577 unset($def[$k]);
1578 }
1579 }
1580 $check_array = $def;
1581 foreach ($a_attributes as $k => $v) {
1582 $check_array[$k] = $v;
1583 }
1584 if (!$this->checkColumnDefinition($check_array, true)) {
1585 throw new ilDatabaseException("ilDB Error: modifyTableColumn(" . $table . ", " . $a_column . ")");
1586 }
1587
1588 foreach ($a_attributes as $a => $v) {
1589 $def[$a] = $v;
1590 }
1591
1592 $a_attributes["definition"] = $def;
1593
1594 $changes = array(
1595 "change" => array(
1596 $a_column => $a_attributes,
1597 ),
1598 );
1599
1600 return $this->manager->alterTable($table, $changes, false);
1601 }
1602
1603
1608 public function free($a_st)
1609 {
1613 return $a_st->closeCursor();
1614 }
1615
1616
1623 public function renameTable($a_name, $a_new_name)
1624 {
1625 // check table name
1626 try {
1627 $this->checkTableName($a_new_name);
1628 } catch (ilDatabaseException $e) {
1629 throw new ilDatabaseException("ilDB Error: renameTable(" . $a_name . "," . $a_new_name . ")<br />" . $e->getMessage());
1630 }
1631
1632 $this->manager->alterTable($a_name, ["name" => $a_new_name], false);
1633 if ($this->sequenceExists($a_name)) {
1634 $this->manager->alterTable($this->getSequenceName($a_name), ["name" => $this->getSequenceName($a_new_name)], false);
1635 }
1636 // The abstraction_progress is no longer used in ILIAS, see http://www.ilias.de/mantis/view.php?id=19513
1637 // $query = "UPDATE abstraction_progress " . "SET table_name = " . $this->quote($a_new_name, 'text') . " " . "WHERE table_name = "
1638 // . $this->quote($a_name, 'text');
1639 // $this->pdo->query($query);
1640
1641 return true;
1642 }
1643
1644
1650 public function checkTableName($a_name)
1651 {
1652 return $this->field_definition->checkTableName($a_name);
1653 }
1654
1655
1660 public static function isReservedWord($a_word)
1661 {
1662 global $DIC;
1663 $ilDBPdoMySQLFieldDefinition = new ilDBPdoMySQLFieldDefinition($DIC->database());
1664
1665 return $ilDBPdoMySQLFieldDefinition->isReserved($a_word);
1666 }
1667
1668
1673 public function beginTransaction()
1674 {
1675 if (!$this->supports(self::FEATURE_TRANSACTIONS)) {
1676 throw new ilDatabaseException("ilDB::beginTransaction: Transactions are not supported.");
1677 }
1678
1679 return $this->pdo->beginTransaction();
1680 }
1681
1682
1687 public function commit()
1688 {
1689 if (!$this->supports(self::FEATURE_TRANSACTIONS)) {
1690 throw new ilDatabaseException("ilDB::beginTransaction: Transactions are not supported.");
1691 }
1692
1693 return $this->pdo->commit();
1694 }
1695
1696
1701 public function rollback()
1702 {
1703 if (!$this->supports(self::FEATURE_TRANSACTIONS)) {
1704 throw new ilDatabaseException("ilDB::beginTransaction: Transactions are not supported.");
1705 }
1706
1707 return $this->pdo->rollBack();
1708 }
1709
1710
1716 public function dropIndex($a_table, $a_name = "i1")
1717 {
1718 return $this->manager->dropIndex($a_table, $a_name);
1719 }
1720
1721
1726 {
1727 $this->storage_engine = $storage_engine;
1728 }
1729
1730
1734 public function getStorageEngine()
1735 {
1736 return $this->storage_engine;
1737 }
1738
1739
1746 public function queryCol($query, $type = PDO::FETCH_ASSOC, $colnum = 0)
1747 {
1748 switch ($type) {
1750 $type = PDO::FETCH_ASSOC;
1751 break;
1753 $type = PDO::FETCH_OBJ;
1754 break;
1755 default:
1756 $type = PDO::FETCH_ASSOC;
1757 break;
1758 }
1759
1760 return $this->pdo->query($query, PDO::FETCH_ASSOC)->fetchAll(PDO::FETCH_COLUMN, $colnum);
1761 }
1762
1763
1770 public function queryRow($query, $types = null, $fetchmode = ilDBConstants::FETCHMODE_DEFAULT)
1771 {
1772 switch ($fetchmode) {
1774 $type = PDO::FETCH_ASSOC;
1775 break;
1777 $type = PDO::FETCH_OBJ;
1778 break;
1779 default:
1780 $type = PDO::FETCH_ASSOC;
1781 break;
1782 }
1783
1784 return $this->pdo->query($query, $type)->fetch();
1785 }
1786
1787
1792 public function getServerVersion($native = false)
1793 {
1794 return $this->pdo->query('SELECT VERSION()')->fetchColumn();
1795 }
1796
1797
1803 public function escape($value, $escape_wildcards = false)
1804 {
1805 return $value;
1806 }
1807
1808
1813 public function escapePattern($text)
1814 {
1815 return $text;
1816 }
1817
1818
1824 {
1825 return array();
1826 }
1827
1828
1833 {
1834 return array();
1835 }
1836
1837
1842 {
1843 return false;
1844 }
1845
1846
1850 public function supportsEngineMigration()
1851 {
1852 return false;
1853 }
1854
1855
1861 public function checkIndexName($name)
1862 {
1863 return $this->getFieldDefinition()->checkIndexName($name);
1864 }
1865
1866
1874 public function addUniqueConstraint($table, $fields, $name = "con")
1875 {
1876 assert(is_array($fields));
1878
1879 // check index name
1880 if (!$this->checkIndexName($name)) {
1881 throw new ilDatabaseException("ilDB Error: addUniqueConstraint(" . $table . "," . $name . ")");
1882 }
1883
1884 $fields_corrected = array();
1885 foreach ($fields as $f) {
1886 $fields_corrected[$f] = array();
1887 }
1888 $definition = array(
1889 'unique' => true,
1890 'fields' => $fields_corrected,
1891 );
1892
1893 return $manager->createConstraint($table, $this->constraintName($table, $name), $definition);
1894 }
1895
1896
1902 public function dropUniqueConstraint($a_table, $a_name = "con")
1903 {
1904 return $this->manager->dropConstraint($a_table, $this->constraintName($a_table, $a_name), false);
1905 }
1906
1907
1913 public function dropUniqueConstraintByFields($a_table, $a_fields)
1914 {
1915 $analyzer = new ilDBAnalyzer();
1916 $cons = $analyzer->getConstraintsInformation($a_table);
1917 foreach ($cons as $c) {
1918 if ($c["type"] == "unique" && count($a_fields) == count($c["fields"])) {
1919 $all_in = true;
1920 foreach ($a_fields as $f) {
1921 if (!isset($c["fields"][$f])) {
1922 $all_in = false;
1923 }
1924 }
1925 if ($all_in) {
1926 return $this->dropUniqueConstraint($a_table, $c['name']);
1927 }
1928 }
1929 }
1930
1931 return false;
1932 }
1933
1934
1938 public function getLastInsertId()
1939 {
1940 return $this->pdo->lastInsertId();
1941 }
1942
1943
1947 public function buildAtomQuery()
1948 {
1949 return new ilAtomQueryLock($this);
1950 }
1951
1952
1958 public function uniqueConstraintExists($table, array $fields)
1959 {
1960 $analyzer = new ilDBAnalyzer();
1961 $cons = $analyzer->getConstraintsInformation($table);
1962 foreach ($cons as $c) {
1963 if ($c["type"] == "unique" && count($fields) == count($c["fields"])) {
1964 $all_in = true;
1965 foreach ($fields as $f) {
1966 if (!isset($c["fields"][$f])) {
1967 $all_in = false;
1968 }
1969 }
1970 if ($all_in) {
1971 return true;
1972 }
1973 }
1974 }
1975
1976 return false;
1977 }
1978
1979
1984 public function dropPrimaryKey($table_name)
1985 {
1986 return $this->manager->dropConstraint($table_name, "PRIMARY", true);
1987 }
1988
1989
1994 public function executeMultiple($stmt, $a_data)
1995 {
1996 for ($i = 0, $j = count($a_data); $i < $j; $i++) {
1997 $stmt->execute($a_data[$i]);
1998 }
1999 }
2000
2001
2007 public function fromUnixtime($a_expr, $a_to_text = true)
2008 {
2009 return "FROM_UNIXTIME(" . $a_expr . ")";
2010 }
2011
2012
2016 public function unixTimestamp()
2017 {
2018 return "UNIX_TIMESTAMP()";
2019 }
2020
2021
2037 public function autoExecute($tablename, $fields, $mode = ilDBConstants::AUTOQUERY_INSERT, $where = false)
2038 {
2039 $fields_values = (array) $fields;
2040 if ($mode == ilDBConstants::AUTOQUERY_INSERT) {
2041 if (!empty($fields_values)) {
2042 $keys = $fields_values;
2043 } else {
2044 $keys = array();
2045 }
2046 } else {
2047 $keys = array_keys($fields_values);
2048 }
2049 $params = array_values($fields_values);
2050 if (empty($params)) {
2051 $query = $this->buildManipSQL($tablename, $keys, $mode, $where);
2052 $result = $this->pdo->query($query);
2053 } else {
2054 $stmt = $this->autoPrepare($tablename, $keys, $mode, $where, $types, $result_types);
2055 $this->execute($stmt);
2056 $this->free($stmt);
2057 $result = $stmt;
2058 }
2059
2060 return $result;
2061 }
2062
2063
2073 protected function autoPrepare($table, $table_fields, $mode = ilDBConstants::AUTOQUERY_INSERT, $where = false, $types = null, $result_types = ilDBConstants::PREPARE_MANIP)
2074 {
2075 $query = $this->buildManipSQL($table, $table_fields, $mode, $where);
2076
2077 return $this->prepare($query, $types, $result_types);
2078 }
2079
2080
2089 protected function buildManipSQL($table, $table_fields, $mode, $where = false)
2090 {
2091 if ($this->options['quote_identifier']) {
2092 $table = $this->quoteIdentifier($table);
2093 }
2094
2095 if (!empty($table_fields) && $this->options['quote_identifier']) {
2096 foreach ($table_fields as $key => $field) {
2097 $table_fields[$key] = $this->quoteIdentifier($field);
2098 }
2099 }
2100
2101 if ($where !== false && !is_null($where)) {
2102 if (is_array($where)) {
2103 $where = implode(' AND ', $where);
2104 }
2105 $where = ' WHERE ' . $where;
2106 }
2107
2108 switch ($mode) {
2110 if (empty($table_fields)) {
2111 throw new ilDatabaseException('Insert requires table fields');
2112 }
2113 $cols = implode(', ', $table_fields);
2114 $values = '?' . str_repeat(', ?', (count($table_fields) - 1));
2115
2116 return 'INSERT INTO ' . $table . ' (' . $cols . ') VALUES (' . $values . ')';
2117 break;
2119 if (empty($table_fields)) {
2120 throw new ilDatabaseException('Update requires table fields');
2121 }
2122 $set = implode(' = ?, ', $table_fields) . ' = ?';
2123 $sql = 'UPDATE ' . $table . ' SET ' . $set . $where;
2124
2125 return $sql;
2126 break;
2128 $sql = 'DELETE FROM ' . $table . $where;
2129
2130 return $sql;
2131 break;
2133 $cols = !empty($table_fields) ? implode(', ', $table_fields) : '*';
2134 $sql = 'SELECT ' . $cols . ' FROM ' . $table . $where;
2135
2136 return $sql;
2137 break;
2138 }
2139
2140 throw new ilDatabaseException('Syntax error');
2141 }
2142
2143
2148 public function getDBVersion()
2149 {
2150 $d = $this->fetchObject($this->query("SELECT VERSION() AS version"));
2151
2152 return ($d->version ? $d->version : 'Unknown');
2153 }
2154
2155
2160 {
2161 if (!$this->doesCollationSupportMB4Strings()) {
2162 $query_replaced = preg_replace(
2163 '/[\x{10000}-\x{10FFFF}]/u',
2165 $query
2166 );
2167 if (!empty($query_replaced)) {
2168 return $query_replaced;
2169 }
2170 }
2171
2172 return $query;
2173 }
2174
2179 {
2180 return false;
2181 }
2182
2183
2187 public function groupConcat($a_field_name, $a_seperator = ",", $a_order = null)
2188 {
2189 return $this->manager->getQueryUtils()->groupConcat($a_field_name, $a_seperator, $a_order);
2190 }
2191
2195 public function cast($a_field_name, $a_dest_type)
2196 {
2197 return $this->manager->getQueryUtils()->cast($a_field_name, $a_dest_type);
2198 }
2199}
$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.
Class pdoDB.
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)
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.
for( $i=6;$i< 13;$i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296
global $ilBench
Definition: ilias.php:18
Interface ilDBInterface.
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
$engine
Definition: workflow.php:89
$DIC
Definition: xapitoken.php:46
$cols
Definition: xhr_table.php:11