3 declare(strict_types=1);
49 self::T_TEXT => [
'length',
'notnull',
'default',
'fixed'],
50 self::T_INTEGER => [
'length',
'notnull',
'default',
'unsigned'],
51 self::T_FLOAT => [
'notnull',
'default'],
52 self::T_DATE => [
'notnull',
'default'],
53 self::T_TIME => [
'notnull',
'default'],
54 self::T_TIMESTAMP => [
'notnull',
'default'],
55 self::T_CLOB => [
'notnull',
'default'],
56 self::T_BLOB => [
'notnull',
'default'],
62 "text" => [
"length",
"notnull",
"default",
"fixed"],
63 "integer" => [
"length",
"notnull",
"default",
"unsigned"],
64 "float" => [
"notnull",
"default"],
65 "date" => [
"notnull",
"default"],
66 "time" => [
"notnull",
"default"],
67 "timestamp" => [
"notnull",
"default"],
68 "clob" => [
"length",
"notnull",
"default"],
69 "blob" => [
"length",
"notnull",
"default"],
73 self::T_INTEGER => [1, 2, 3, 4, 8],
173 "CONSTRAINT_CATALOG",
287 "GEOMETRYCOLLECTION",
376 "MASTER_AUTO_POSITION",
378 "MASTER_CONNECT_RETRY",
380 "MASTER_HEARTBEAT_PERIOD",
386 "MASTER_RETRY_COUNT",
394 "MASTER_SSL_CRLPATH",
396 "MASTER_SSL_VERIFY_SERVER_CERT",
397 "MASTER_TLS_VERSION",
401 "MAX_CONNECTIONS_PER_HOUR",
402 "MAX_QUERIES_PER_HOUR",
405 "MAX_STATEMENT_TIME",
406 "MAX_UPDATES_PER_HOUR",
407 "MAX_USER_CONNECTIONS",
419 "MINUTE_MICROSECOND",
448 "NO_WRITE_TO_BINLOG",
531 "REPLICATE_DO_TABLE",
532 "REPLICATE_IGNORE_DB",
533 "REPLICATE_IGNORE_TABLE",
534 "REPLICATE_REWRITE_DB",
535 "REPLICATE_WILD_DO_TABLE",
536 "REPLICATE_WILD_IGNORE_TABLE",
566 "SECOND_MICROSECOND",
598 "SQL_AFTER_MTS_GAPS",
603 "SQL_CALC_FOUND_ROWS",
622 "STATS_SAMPLE_PAGES",
829 $this->db_instance = $ilDBInterface;
834 if ($this->query_utils === null) {
847 'timestamp' =>
'1970-01-01 00:00:00',
848 'time' =>
'00:00:00',
849 'date' =>
'1970-01-01',
859 if (!preg_match(self::DEFINITION_TABLE_NAME, $table_name)) {
860 throw new ilDatabaseException(
'Table name must only contain _a-z0-9 and must start with a-z.');
864 throw new ilDatabaseException(
"Invalid table name '" . $table_name .
"' (Reserved Word).");
867 if (stripos($table_name,
"sys_") === 0) {
868 throw new ilDatabaseException(
"Invalid table name '" . $table_name .
"'. Name must not start with 'sys_'.");
871 if (strlen($table_name) > 22) {
872 throw new ilDatabaseException(
"Invalid table name '" . $table_name .
"'. Maximum table identifer length is 22 bytes.");
913 if (!preg_match(
"/^[a-z]+[_a-z0-9]*$/", $column_name)) {
915 .
"'. Column name must only contain _a-z0-9 and must start with a-z.");
919 throw new ilDatabaseException(
"Invalid column name '" . $column_name .
"' (Reserved Word).");
922 if (stripos($column_name,
"sys_") === 0) {
923 throw new ilDatabaseException(
"Invalid column name '" . $column_name .
"'. Name must not start with 'sys_'.");
926 if (strlen($column_name) > 30) {
927 throw new ilDatabaseException(
"Invalid column name '" . $column_name .
"'. Maximum column identifer length is 30 bytes.");
938 if (!preg_match(
"/^[a-z]+[_a-z0-9]*$/", $a_name)) {
939 throw new ilDatabaseException(
"Invalid column name '" . $a_name .
"'. Column name must only contain _a-z0-9 and must start with a-z.");
946 if (strlen($a_name) > 3) {
947 throw new ilDatabaseException(
"Invalid index name '" . $a_name .
"'. Maximum index identifer length is 3 bytes.");
960 switch ($a_def[
"type"]) {
962 throw new ilDatabaseException(
"Invalid column type '" . $a_def[
"type"] .
"'. Use integer(1) instead.");
965 throw new ilDatabaseException(
"Invalid column type '" . $a_def[
"type"] .
"'. Use float or integer instead.");
968 throw new ilDatabaseException(
"Invalid column type '" . $a_def[
"type"] .
"'. Allowed types are: " 975 foreach (array_keys($a_def) as $k) {
976 if ($k !==
"type" && !in_array($k, $allowed_attributes[$a_def[
"type"]],
true)) {
977 throw new ilDatabaseException(
"Attribute '" . $k .
"' is not allowed for column type '" . $a_def[
"type"] .
"'.");
983 switch ($a_def[
"type"]) {
985 if ((!isset($a_def[
"length"]) || $a_def[
"length"] < 1 || $a_def[
"length"] > $max_length[self::T_TEXT]) && isset($a_def[
"length"])) {
986 throw new ilDatabaseException(
"Invalid length '" . $a_def[
"length"] .
"' for type text." .
" Length must be >=1 and <= " 987 . $max_length[self::T_TEXT] .
".");
991 case self::T_INTEGER:
992 if (isset($a_def[
"length"]) && !in_array((
int) $a_def[
"length"], $max_length[self::T_INTEGER],
true)) {
993 throw new ilDatabaseException(
"Invalid length '" . $a_def[
"length"] .
"' for type integer." .
" Length must be " 994 . implode(
', ', $max_length[self::T_INTEGER]) .
" (bytes).");
996 if ($a_def[
"unsigned"] ?? null) {
1007 return in_array($attribute, $this->allowed_attributes[$type],
true);
1065 if (!empty($db->options[
'datatype_map'])) {
1066 foreach ($db->options[
'datatype_map'] as
$type => $mapped_type) {
1067 if (array_key_exists($mapped_type, $types)) {
1068 $types[
$type] = $types[$mapped_type];
1069 } elseif (!empty($db->options[
'datatype_map_callback'][
$type])) {
1070 $parameter = array(
'type' =>
$type,
'mapped_type' => $mapped_type);
1071 $default = call_user_func_array(
1072 $db->options[
'datatype_map_callback'][
$type],
1073 array(&$db, __FUNCTION__, $parameter)
1075 $types[
$type] = $default;
1093 if (!empty($db->options[
'datatype_map'][$type])) {
1094 $type = $db->options[
'datatype_map'][
$type];
1095 if (!empty($db->options[
'datatype_map_callback'][$type])) {
1096 $parameter = array(
'type' => $type,
'name' => $name,
'field' => $field);
1098 return call_user_func_array(
1099 $db->options[
'datatype_map_callback'][$type],
1100 array(&$db, __FUNCTION__, $parameter)
1103 $field[
'type'] =
$type;
1106 if (!method_exists($this,
"get{$type}Declaration")) {
1110 return $this->{
"get{$type}Declaration"}(
$name, $field);
1117 switch ($field[
'type']) {
1119 $length = empty($field[
'length']) ? $db->options[
'default_text_field_length'] : $field[
'length'];
1120 $fixed = empty($field[
'fixed']) ? false : $field[
'fixed'];
1122 return $length ?
'CHAR(' . $length .
')' :
'CHAR(' . $db->options[
'default_text_field_length'] .
')';
1125 return $length ?
'VARCHAR(' . $length .
')' :
'TEXT';
1135 return 'CHAR (' . strlen(
'YYYY-MM-DD') .
')';
1137 return 'CHAR (' . strlen(
'HH:MM:SS') .
')';
1139 return 'CHAR (' . strlen(
'YYYY-MM-DD HH:MM:SS') .
')';
1149 $name = $db->quoteIdentifier($name,
true);
1150 $declaration_options =
'';
1151 $fd = $db->getFieldDefinition();
1153 $declaration_options = $fd->getDeclarationOptions($field);
1167 if (array_key_exists(
'default', $field)) {
1168 if ($field[
'default'] ===
'') {
1171 if (empty($field[
'notnull'])) {
1172 $field[
'default'] = null;
1175 $field[
'default'] = $valid_default_values[$field[
'type']];
1177 if ($field[
'default'] ===
'' 1178 && isset($db->options[
"portability"])
1179 && ($db->options[
'portability'] & 32)
1181 $field[
'default'] =
' ';
1184 $default =
' DEFAULT ' . $this->
quote($field[
'default'], $field[
'type']);
1185 } elseif (empty($field[
'notnull'])) {
1186 $default =
' DEFAULT NULL';
1189 $notnull = empty($field[
'notnull']) ?
'' :
' NOT NULL';
1191 if (isset($field[
"notnull"]) && $field[
'notnull'] ===
false) {
1198 return $charset . $default . $notnull . $collation;
1231 $notnull = empty($field[
'notnull']) ?
'' :
' NOT NULL';
1232 $name = $db->quoteIdentifier($name,
true);
1241 $notnull = empty($field[
'notnull']) ?
'' :
' NOT NULL';
1242 $name = $db->quoteIdentifier($name,
true);
1284 $type = empty($current[
'type']) ? null : $current[
'type'];
1286 if (!method_exists($this,
"compare{$type}Definition")) {
1289 if (!empty($db->options[
'datatype_map_callback'][
$type])) {
1290 $parameter = array(
'current' => $current,
'previous' => $previous);
1292 return call_user_func_array(
1293 $db->options[
'datatype_map_callback'][
$type],
1294 array(&$db, __FUNCTION__, $parameter)
1301 if (empty($previous[
'type']) || $previous[
'type'] !=
$type) {
1305 $change = $this->{
"compare{$type}Definition"}($current, $previous);
1307 if ($previous[
'type'] !=
$type) {
1308 $change[
'type'] =
true;
1311 $previous_notnull = empty($previous[
'notnull']) ? false : $previous[
'notnull'];
1312 $notnull = empty($current[
'notnull']) ? false : $current[
'notnull'];
1313 if ($previous_notnull !== $notnull) {
1314 $change[
'notnull'] =
true;
1317 $alt = $previous_notnull ?
'' : null;
1318 $previous_default = array_key_exists(
1321 ) ? $previous[
'default'] : $alt;
1322 $alt = $notnull ?
'' : null;
1323 $default = array_key_exists(
'default', $current) ? $current[
'default'] : $alt;
1324 if ($previous_default !== $default) {
1325 $change[
'default'] =
true;
1337 $previous_unsigned = empty($previous[
'unsigned']) ? false : $previous[
'unsigned'];
1338 $unsigned = empty($current[
'unsigned']) ? false : $current[
'unsigned'];
1339 if ($previous_unsigned != $unsigned) {
1340 $change[
'unsigned'] =
true;
1342 $previous_autoincrement = empty($previous[
'autoincrement']) ? false : $previous[
'autoincrement'];
1343 $autoincrement = empty($current[
'autoincrement']) ? false : $current[
'autoincrement'];
1344 if ($previous_autoincrement != $autoincrement) {
1345 $change[
'autoincrement'] =
true;
1357 $previous_length = empty($previous[
'length']) ? 0 : $previous[
'length'];
1358 $length = empty($current[
'length']) ? 0 : $current[
'length'];
1359 if ($previous_length != $length) {
1360 $change[
'length'] =
true;
1362 $previous_fixed = empty($previous[
'fixed']) ? 0 : $previous[
'fixed'];
1363 $fixed = empty($current[
'fixed']) ? 0 : $current[
'fixed'];
1364 if ($previous_fixed != $fixed) {
1365 $change[
'fixed'] =
true;
1420 public function quote($value, ?
string $type = null,
bool $quote =
true,
bool $escape_wildcards =
false): string
1430 return (
int) $value;
1433 protected function quoteText(
string $value,
bool $quote,
bool $escape_wildcards): string
1441 $value = $db->escape($value, $escape_wildcards);
1443 return "'" . $value .
"'";
1452 if (is_string($value) && preg_match(
'/^(\w+:\/\/)(.*)$/', $value, $match)) {
1454 if ($match[1] ===
'file://') {
1458 #$value = @fopen($value, 'r'); 1461 if (is_resource($value)) {
1466 while (!@feof($fp)) {
1467 $value .= @fread($fp, $db->options[
'lob_buffer_length']);
1480 protected function quoteLOB($value,
bool $quote,
bool $escape_wildcards): string
1484 return $this->
quoteText($value, $quote, $escape_wildcards);
1489 protected function quoteCLOB($value,
bool $quote,
bool $escape_wildcards): string
1491 return $this->
quoteLOB($value, $quote, $escape_wildcards);
1496 protected function quoteBLOB($value,
bool $quote,
bool $escape_wildcards): string
1498 return $this->
quoteLOB($value, $quote, $escape_wildcards);
1503 return ($value ? 1 : 0);
1506 protected function quoteDate(
string $value,
bool $quote,
bool $escape_wildcards): string
1508 if ($value ===
'CURRENT_DATE') {
1509 return 'CURRENT_DATE';
1512 return $this->
quoteText($value, $quote, $escape_wildcards);
1518 protected function quoteTimestamp(
int $value,
bool $quote,
bool $escape_wildcards): string
1526 protected function quoteTime(
int $value,
bool $quote,
bool $escape_wildcards): string
1531 protected function quoteFloat(
string $value,
bool $quote,
bool $escape_wildcards): ?string
1533 if (preg_match(
'/^(.*)e([-+])(\d+)$/i', $value, $matches)) {
1534 $decimal = $this->
quoteDecimal($matches[1], $quote, $escape_wildcards);
1535 $sign = $matches[2];
1536 $exponent = str_pad($matches[3], 2,
'0', STR_PAD_LEFT);
1537 $value = $decimal .
'E' . $sign . $exponent;
1539 $value = $this->
quoteDecimal($value, $quote, $escape_wildcards);
1545 protected function quoteDecimal(
string $value,
bool $quote,
bool $escape_wildcards): ?string
1547 $value = preg_replace(
'/[^\d\.,\-+eE]/',
'', $value);
1548 if (preg_match(
'/[^.0-9]/', $value) && strpos($value,
',')) {
1550 if (!strpos($value,
'.')) {
1552 $value = strrev(str_replace(
',',
'.', strrev($value)));
1554 } elseif (strpos($value,
'.') && strpos($value,
'.') < strpos($value,
',')) {
1555 $value = str_replace(
'.',
'', $value);
1557 $value = strrev(str_replace(
',',
'.', strrev($value)));
1560 $value = str_replace(
',',
'', $value);
1576 if (preg_match(
'/^(\w+:\/\/)(.*)$/', $file, $match) && $match[1] ===
'file://') {
1580 $fp = @fopen($file,
'wb');
1581 while (!@feof($lob)) {
1582 $result = @fread($lob, $db->options[
'lob_buffer_length']);
1583 $read = strlen($result);
1584 if (@fwrite($fp, $result, $read) !== $read) {
1597 if (is_null($lob[
'value'])) {
1598 $lob[
'value'] = $lob[
'resource'];
1600 $lob[
'loaded'] =
true;
1605 protected function readLOB(array $lob,
int $length): string
1607 return substr($lob[
'value'], $lob[
'position'], $length);
1615 return $lob[
'endOfLOB'];
1623 $lob_data = stream_get_meta_data($lob);
1624 $lob_index = $lob_data[
'wrapper_data']->lob_index;
1626 if (isset($this->lobs[$lob_index])) {
1627 unset($this->lobs[$lob_index]);
1637 public function matchPattern(array $pattern, $operator = null, $field = null): string
1642 if (!is_null($operator)) {
1643 $operator = strtoupper($operator);
1644 switch ($operator) {
1647 if (is_null($field)) {
1648 throw new ilDatabaseException(
'case insensitive LIKE matching requires passing the field name');
1650 $db->loadModule(
'Function');
1651 $match = $db->lower($field) .
' LIKE ';
1655 $match = is_null($field) ?
'LIKE ' : $field .
' LIKE ';
1662 foreach ($pattern as
$key => $value) {
1663 if (
$key % 2 !== 0) {
1666 if ($operator ===
'ILIKE') {
1667 $value = strtolower($value);
1669 $escaped = $db->escape($value);
1670 $match .= $db->escapePattern($escaped);
1690 $db_type = strtok($field[
'type'],
'(), ');
1691 if (!empty($db->options[
'nativetype_map_callback'][$db_type])) {
1692 return call_user_func_array($db->options[
'nativetype_map_callback'][$db_type], array($db, $field));
1710 if (!empty($db->options[
'datatype_map'][$type])) {
1711 $type = $db->options[
'datatype_map'][
$type];
1712 if (!empty($db->options[
'datatype_map_callback'][$type])) {
1713 $parameter = array(
'type' => $type);
1715 return call_user_func_array(
1716 $db->options[
'datatype_map_callback'][$type],
1717 array(&$db, __FUNCTION__, $parameter)
compareIntegerDefinition(array $current, array $previous)
compareDecimalDefinition(array $current, array $previous)
compareBooleanDefinition(array $current, array $previous)
getIntegerDeclaration(string $name, array $field)
quoteBoolean(bool $value, bool $quote, bool $escape_wildcards)
compareTimeDefinition(array $current, array $previous)
isAllowedAttribute(string $attribute, string $type)
quoteCLOB($value, bool $quote, bool $escape_wildcards)
quoteFloat(string $value, bool $quote, bool $escape_wildcards)
mapNativeDatatype(array $field)
getTimeDeclaration(string $name, array $field)
compareDefinition(array $current, array $previous)
quoteInteger($value, bool $quote, bool $escape_wildcards)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getTextDeclaration(string $name, array $field)
array $valid_default_values
array checkTableName(string $table_name)
compareCLOBDefinition(array $current, array $previous)
getTimestampDeclaration(string $name, array $field)
const DEFINITION_COLUMN_NAME
getInternalDeclaration(string $name, array $field)
quoteDecimal(string $value, bool $quote, bool $escape_wildcards)
setAvailableTypes(array $available_types)
mapNativeDatatypeInternal(array $field)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
mapPrepareDatatype(string $type)
getDeclarationOptions(array $field)
quoteBLOB($value, bool $quote, bool $escape_wildcards)
getCharsetFieldDeclaration(string $charset)
quoteLOB($value, bool $quote, bool $escape_wildcards)
getFloatDeclaration(string $name, array $field)
array ilDBInterface $db_instance
checkColumnName(string $column_name)
compareTextDefinition(array $current, array $previous)
compareTimestampDefinition(array $current, array $previous)
writeLOBToFile($lob, string $file)
getDecimalDeclaration(string $name, array $field)
checkIndexName(string $a_name)
compareFloatDefinition(array $current, array $previous)
setAllowedAttributes(array $allowed_attributes)
checkColumnDefinition(array $a_def)
array $allowed_attributes_old
const DEFAULT_DECIMAL_PLACES
quoteText(string $value, bool $quote, bool $escape_wildcards)
const SEQUENCE_COLUMNS_NAME
getCLOBDeclaration(string $name, array $field)
readLOB(array $lob, int $length)
getBooleanDeclaration(string $name, array $field)
array $allowed_attributes
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
matchPattern(array $pattern, $operator=null, $field=null)
quoteTime(int $value, bool $quote, bool $escape_wildcards)
getDateDeclaration(string $name, array $field)
setReservedMysql(array $reserved_mysql)
quoteTimestamp(int $value, bool $quote, bool $escape_wildcards)
quoteDate(string $value, bool $quote, bool $escape_wildcards)
compareDateDefinition(array $current, array $previous)
getTypeDeclaration(array $field)
setMaxLength(array $max_length)
quote($value, ?string $type=null, bool $quote=true, bool $escape_wildcards=false)
__construct(\ilDBInterface $ilDBInterface)
ilDBPdoFieldDefinition constructor.
const DEFINITION_TABLE_NAME
compareBLOBDefinition(array $current, array $previous)
getDeclaration(string $type, string $name, $field)
isReserved(string $table_name)
ilMySQLQueryUtils $query_utils
const DEFAULT_TEXT_LENGTH
getBLOBDeclaration(string $name, array $field)
getCollationFieldDeclaration(string $collation)
static ilDBPdoFieldDefinition $instance