From 2baf1380d4898e15328fa6aa62e13115ce6092a8 Mon Sep 17 00:00:00 2001 From: stronk7 Date: Thu, 2 Jul 2009 16:08:44 +0000 Subject: [PATCH] MDL-19695 field dependencies - defined new exception ddl_dependency_exception that will be thrown when one DDL operation (drop only for now) is attempted over one field being part of indexes. --- lang/en_utf8/error.php | 1 + lib/ddl/database_manager.php | 61 +++++++++++++++++++++++++++--------- lib/ddllib.php | 17 ++++++++++ 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/lang/en_utf8/error.php b/lang/en_utf8/error.php index 5a0b4fbb52..211ee8d06c 100644 --- a/lang/en_utf8/error.php +++ b/lang/en_utf8/error.php @@ -171,6 +171,7 @@ $string['dbsessionmysqlpacketsize'] = 'Serious session error detected.

field_exists($xmldb_table, $xmldb_field)) { throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName()); } + /// Check for dependencies in the DB before performing any action + $this->check_field_dependencies($xmldb_table, $xmldb_field); if (!$sqlarr = $this->generator->getDropFieldSQL($xmldb_table, $xmldb_field)) { throw new ddl_exception('ddlunknownerror', null, 'drop_field sql not generated'); @@ -679,15 +681,14 @@ class database_manager { } /** - * This function will drop the existing enum of the field in the table passed as arguments - * - * TODO: Moodle 2.1 - Drop drop_enum_from_field() + * This function will change the default of the field in the table passed as arguments + * One null value in the default field means delete the default * * @param xmldb_table table object (just the name is mandatory) * @param xmldb_field field object (full specs are required) * @return void */ - public function drop_enum_from_field(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { + public function change_field_default(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { if (!$this->table_exists($xmldb_table)) { throw new ddl_table_missing_exception($xmldb_table->getName()); } @@ -696,13 +697,7 @@ class database_manager { throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName()); } - if (!$this->check_constraint_exists($xmldb_table, $xmldb_field)) { - debugging('Enum for ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() . - ' does not exist. Delete skipped', DEBUG_DEVELOPER); - return; //Enum does not exist, nothing to delete - } - - if (!$sqlarr = $this->generator->getDropEnumSQL($xmldb_table, $xmldb_field)) { + if (!$sqlarr = $this->generator->getModifyDefaultSQL($xmldb_table, $xmldb_field)) { return; //Empty array = nothing to do = no error } @@ -710,14 +705,15 @@ class database_manager { } /** - * This function will change the default of the field in the table passed as arguments - * One null value in the default field means delete the default + * This function will drop the existing enum of the field in the table passed as arguments + * + * TODO: Moodle 2.1 - Drop drop_enum_from_field() * * @param xmldb_table table object (just the name is mandatory) * @param xmldb_field field object (full specs are required) * @return void */ - public function change_field_default(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { + public function drop_enum_from_field(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { if (!$this->table_exists($xmldb_table)) { throw new ddl_table_missing_exception($xmldb_table->getName()); } @@ -726,7 +722,13 @@ class database_manager { throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName()); } - if (!$sqlarr = $this->generator->getModifyDefaultSQL($xmldb_table, $xmldb_field)) { + if (!$this->check_constraint_exists($xmldb_table, $xmldb_field)) { + debugging('Enum for ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() . + ' does not exist. Delete skipped', DEBUG_DEVELOPER); + return; //Enum does not exist, nothing to delete + } + + if (!$sqlarr = $this->generator->getDropEnumSQL($xmldb_table, $xmldb_field)) { return; //Empty array = nothing to do = no error } @@ -777,6 +779,35 @@ class database_manager { $this->execute_sql_arr($sqlarr); } + /** + * This function will check, for the given table and field, if there there is any dependency + * preventing the field to be modified. It's used by all the public methods that perform any + * DDL change on fields, throwing one ddl_dependency_exception if dependencies are found + */ + private function check_field_dependencies(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { + + /// Check the table exists + if (!$this->table_exists($xmldb_table)) { + throw new ddl_table_missing_exception($xmldb_table->getName()); + } + + /// Check the field exists + if (!$this->field_exists($xmldb_table, $xmldb_field)) { + throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName()); + } + + /// Check the field isn't in use by any index in the table + if ($indexes = $this->mdb->get_indexes($xmldb_table->getName(), false)) { + foreach ($indexes as $indexname => $index) { + $columns = $index['columns']; + if (in_array($xmldb_field->getName(), $columns)) { + throw new ddl_dependency_exception('column', $xmldb_table->getName() . '->' . $xmldb_field->getName(), + 'index', $indexname . ' (' . implode(', ', $columns) . ')'); + } + } + } + } + /** * This function will create the key in the table passed as arguments * diff --git a/lib/ddllib.php b/lib/ddllib.php index d61c6953ba..75b069a198 100644 --- a/lib/ddllib.php +++ b/lib/ddllib.php @@ -130,3 +130,20 @@ class ddl_change_structure_exception extends ddl_exception { parent::__construct('ddlexecuteerror', NULL, $errorinfo); } } + +/** + * Error changing db structure, caused by some depency found + * like trying to modify one field having related indexes. + */ +class ddl_dependency_exception extends ddl_exception { + + function __construct($targettype, $targetname, $offendingtype, $offendingname, $debuginfo=null) { + $a = new object(); + $a->targettype = $targettype; + $a->targetname = $targetname; + $a->offendingtype = $offendingtype; + $a->offendingname = $offendingname; + + parent::__construct('ddldependencyerror', $a, $debuginfo); + } +} -- 2.39.5