From: stronk7 Date: Sun, 24 Sep 2006 17:39:20 +0000 (+0000) Subject: Now Oracle generator is able to change the precision and decimals of X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=11b75afe8ba18934cd6e650f90d6d53ae58b04a5;p=moodle.git Now Oracle generator is able to change the precision and decimals of one column by using one temp column. This prevents ORA-1440 errors. --- diff --git a/lib/xmldb/classes/generators/oci8po/oci8po.class.php b/lib/xmldb/classes/generators/oci8po/oci8po.class.php index f16981eff5..46c9801883 100644 --- a/lib/xmldb/classes/generators/oci8po/oci8po.class.php +++ b/lib/xmldb/classes/generators/oci8po/oci8po.class.php @@ -200,45 +200,146 @@ class XMLDBoci8po extends XMLDBgenerator { * Oracle has some severe limits: * - clob and blob fields doesn't allow type to be specified * - error is dropped if the null/not null clause is specified and hasn't changed + * - changes in precision/decimals of numeric fields drop an ORA-1440 error */ function getAlterFieldSQL($xmldb_table, $xmldb_field) { - global $db; - - /// Get the quoted name of the table and field - $tablename = $this->getEncQuoted($this->prefix . $xmldb_table->getName()); - $fieldname = $this->getEncQuoted($xmldb_field->getName()); - - /// Take a look to field metadata - $meta = array_change_key_case($db->MetaColumns($tablename)); - $metac = $meta[$fieldname]; - $oldtype = strtolower($metac->type); - $oldlength = $metac->max_length; - $olddecimals = empty($metac->scale) ? null : $metac->scale; - $oldnotnull = empty($metac->not_null) ? false : $metac->not_null; - $olddefault = empty($metac->default_value) ? null : $metac->default_value; - - $islob = false; - - /// If field is CLOB and new one is also XMLDB_TYPE_TEXT or - /// if fiels is BLOB and new one is also XMLDB_TYPE_BINARY - /// prevent type to be specified, so only NULL and DEFAULT clauses are allowed - if (($oldtype = 'clob' && $xmldb_field->getType() == XMLDB_TYPE_TEXT) || - ($oldtype = 'blob' && $xmldb_field->getType() == XMLDB_TYPE_BINARY)) { - $this->alter_column_skip_type = true; - $islob = true; - } - - /// If field is NOT NULL and the new one too or - /// if field is NULL and the new one too - /// prevent null clause to be specified - if (($oldnotnull && $xmldb_field->getNotnull()) || - (!$oldnotnull && !$xmldb_field->getNotnull())) { - $this->alter_column_skip_notnull = true; - } - - /// In the rest of cases, use the general generator - return parent::getAlterFieldSQL($xmldb_table, $xmldb_field); + global $db; + + $results = array(); /// To store all the needed SQL commands + + /// Get the quoted name of the table and field + $tablename = $this->getEncQuoted($this->prefix . $xmldb_table->getName()); + $fieldname = $this->getEncQuoted($xmldb_field->getName()); + + /// Take a look to field metadata + $meta = array_change_key_case($db->MetaColumns($tablename)); + $metac = $meta[$fieldname]; + $oldtype = strtolower($metac->type); + $oldmetatype = column_type($xmldb_table->getName(), $fieldname); + $oldlength = $metac->max_length; + /// To calculate the oldlength if the field is numeric, we need to perform one extra query + /// because ADOdb has one bug here. http://phplens.com/lens/lensforum/msgs.php?id=15883 + if ($oldmetatype == 'N') { + $uppertablename = strtoupper($tablename); + $upperfieldname = strtoupper($fieldname); + if ($col = get_record_sql("SELECT cname, precision + FROM col + WHERE tname = '$uppertablename' + AND cname = '$upperfieldname'")) { + $oldlength = $col->precision; + } + } + $olddecimals = empty($metac->scale) ? null : $metac->scale; + $oldnotnull = empty($metac->not_null) ? false : $metac->not_null; + $olddefault = empty($metac->default_value) ? null : $metac->default_value; + + $typechanged = true; //By default, assume that the column type has changed + $precisionchanged = true; //By default, assume that the column precision has changed + $decimalchanged = true; //By default, assume that the column decimal has changed + $defaultchanged = true; //By default, assume that the column default has changed + $notnullchanged = true; //By default, assume that the column notnull has changed + + $from_temp_fields = false; //By default don't assume we are going to use temporal fields + + /// Detect if we are changing the type of the column + if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && substr($oldmetatype, 0, 1) == 'I') || + ($xmldb_field->getType() == XMLDB_TYPE_NUMBER && $oldmetatype == 'N') || + ($xmldb_field->getType() == XMLDB_TYPE_FLOAT && $oldmetatype == 'F') || + ($xmldb_field->getType() == XMLDB_TYPE_CHAR && substr($oldmetatype, 0, 1) == 'C') || + ($xmldb_field->getType() == XMLDB_TYPE_TEXT && substr($oldmetatype, 0, 1) == 'X') || + ($xmldb_field->getType() == XMLDB_TYPE_BINARY && $oldmetatype == 'B')) { + $typechanged = false; + } + /// Detect if precision has changed + if (($xmldb_field->getType() == XMLDB_TYPE_TEXT) || + ($xmldb_field->getType() == XMLDB_TYPE_BINARY) || + ($oldlength == -1) || + ($xmldb_field->getLength() == $oldlength)) { + $precisionchanged = false; + } + /// Detect if decimal has changed + if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER) || + ($xmldb_field->getType() == XMLDB_TYPE_CHAR) || + ($xmldb_field->getType() == XMLDB_TYPE_TEXT) || + ($xmldb_field->getType() == XMLDB_TYPE_BINARY) || + (!$xmldb_field->getDecimals()) || + (!$olddecimals) || + ($xmldb_field->getDecimals() == $olddecimals)) { + $decimalchanged = false; + } + /// Detect if we are changing the default + if (($xmldb_field->getDefault() === null && $olddefault === null) || + ($xmldb_field->getDefault() === $olddefault) || //Check both equality and + ("'" . $xmldb_field->getDefault() . "'" === $olddefault)) { //Equality with quotes because ADOdb returns the default with quotes + $defaultchanged = false; + } + /// Detect if we are changing the nullability + if (($xmldb_field->getNotnull() === $oldnotnull)) { + $notnullchanged = false; + } + + /// If type has changed or precision or decimal has changed and we are in one numeric field + /// - create one temp column with the new specs + /// - fill the new column with the values from the old one + /// - drop the old column + /// - rename the temp column to the original name + if (($typechanged) || ($oldmetatype == 'N' && ($precisionchanged || $decimalchanged))) { + $tempcolname = $xmldb_field->getName() . '_alter_column_tmp'; + /// Prevent temp field to have both NULL/NOT NULL and DEFAULT constraints + $this->alter_column_skip_notnull = true; + $this->alter_column_skip_default = true; + $xmldb_field->setName($tempcolname); + /// Create the temporal column + $results = array_merge($results, $this->getAddFieldSQL($xmldb_table, $xmldb_field)); + /// Copy contents from original col to the temporal one + $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = ' . $fieldname; + /// Drop the old column + $xmldb_field->setName($fieldname); //Set back the original field name + $results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field)); + /// Rename the temp column to the original one + $results[] = 'ALTER TABLE ' . $tablename . ' RENAME COLUMN ' . $tempcolname . ' TO ' . $fieldname; + /// Mark we have performed one change based in temp fields + $from_temp_fields = true; + /// Re-enable the notnull and default sections so the general AlterFieldSQL can use it + $this->alter_column_skip_notnull = false; + $this->alter_column_skip_default = false; + /// Dissavle the type section because we have done it with the temp field + $this->alter_column_skip_type = true; + } + + /// If type and precision and decimals hasn't changed, prevent the type clause + if (!$typechanged && !$precisionchanged && !$decimalchanged) { + $this->alter_column_skip_type = true; + } + + /// If NULL/NOT NULL hasn't changed + /// prevent null clause to be specified + if (!$notnullchanged) { + $this->alter_column_skip_notnull = true; /// Initially, prevent the notnull clause + /// But, if we have used the temp field and the new field is not null, then enforce the not null clause + if ($from_temp_fields && $xmldb_field->getNotnull()) { + $this->alter_column_skip_notnull = false; + } + } + /// If default hasn't changed + /// prevent default clause to be specified + if (!$defaultchanged) { + $this->alter_column_skip_default = true; /// Initially, prevent the default clause + /// But, if we have used the temp field and the new field has default clause, then enforce the default clause + if ($from_temp_fields && $default_clause = $this->getDefaultClause($xmldb_field)) { + $this->alter_column_skip_default = false; + } + } + + /// If arriving here, something is not being skiped (type, notnull, default), calculate the standar AlterFieldSQL + if (!$this->alter_column_skip_type || !$this->alter_column_skip_notnull || !$this->alter_column_skip_default) { + $results = array_merge($results, parent::getAlterFieldSQL($xmldb_table, $xmldb_field)); + return $results; + } + + /// Finally return results + return $results; } /**