changeColumnType method

  1. @override
void changeColumnType(
  1. String name,
  2. ColumnType type, {
  3. int length = Column.defaultLength,
  4. int? precision,
  5. int? scale,
  6. bool? isNullable,
  7. Object? defaultValue,
  8. bool? autoIncrement,
  9. String? using,
})

Changes the type of the column name to type, with its length, precision and scale, which are as for a Column: without a precision or scale, a numeric is unbounded on PostgreSQL, so that its values are kept, and numeric(17, 3) on MySQL and MariaDB.

The column has the constraints given after the change: it is nullable or not as isNullable, has the default defaultValue, or none if it is noDefault, and on MySQL and MariaDB is AUTO_INCREMENT or not as autoIncrement. Those not given (null) are kept as they are; a default that the new type cannot have, such as 'n/a' of an int, is removed with noDefault. MySQL and MariaDB define the whole column again, so the migration runner reads them from the database first; they keep its NOT NULL, DEFAULT, AUTO_INCREMENT, ON UPDATE, UNSIGNED, generation, INVISIBLE and COMMENT, its CHARACTER SET and COLLATE for a type of text, and on MariaDB its CHECK, where the new type can have them.

On PostgreSQL, using is the expression that converts the values when there is no implicit cast, such as price::numeric from text.

Throws an ArgumentError if type has a precision and precision is not positive, or has a scale and scale is negative or greater than the precision.

Implementation

@override
void changeColumnType(
  String name,
  ColumnType type, {
  int length = Column.defaultLength,
  int? precision,
  int? scale,
  bool? isNullable,
  Object? defaultValue,
  bool? autoIncrement,
  String? using,
}) {
  // A serial type is not a type that a column can be changed to, but an
  // integer with a default from a sequence, which a serial column keeps,
  // and which compileSequences gives a column without one.
  // With `autoIncrement: false`, a serial type is only its integer, as on
  // MySQL and MariaDB, and so it is with `noDefault`, the default from its
  // sequence being one, unless `autoIncrement: true` is given.
  var integer = sql.serialIntegers[type];
  var serial =
      integer != null &&
      autoIncrement != false &&
      !identical(defaultValue, noDefault);
  if (serial || autoIncrement == true) {
    _sequences[_columnKey(name)] =
        _sequenceTypes[integer ?? type] ?? 'bigint';
  }
  var column = changedColumn(
    integer ?? type,
    length: length,
    precision: precision,
    scale: scale,
  );
  // The column keeps its constraints, and gets those given. A new default,
  // or noDefault, replaces the old one, which is dropped first, as it may
  // not be cast to the new type.
  if (defaultValue != null) {
    _clause(
      'ALTER COLUMN ${sql.quotePostgresIdentifier(name)} DROP DEFAULT',
      [name],
    );
  }
  _clause(
    'ALTER COLUMN ${sql.quotePostgresIdentifier(name)} TYPE ${PostgresGenerator.columnType(column)}'
    '${using == null ? '' : ' USING $using'}',
    [name],
  );
  if (isNullable != null) {
    _clause(
      'ALTER COLUMN ${sql.quotePostgresIdentifier(name)} ${isNullable ? 'DROP' : 'SET'} NOT NULL',
      [name],
    );
  }
  if (defaultValue != null && !identical(defaultValue, noDefault)) {
    _clause(
      'ALTER COLUMN ${sql.quotePostgresIdentifier(name)} SET DEFAULT '
      '${PostgresGenerator.compileDefault(defaultValue)}',
      [name],
    );
  }
}