'afterColumn' and 'position' not working in Firebird and Oracle databases
See original GitHub issueEnvironment
Liquibase Version: 3.8.5 - 4.1
Liquibase Integration & Version: gradle
Liquibase Extension(s) & Version:
Database Vendor & Version: firebird 2.5, oracle
Operating System Type & Version: win 10 java 8
Description
The ‘addColumn’ tag supports ‘afterColumn’ and ‘position’, but these tags are ignored in the SQL generation in Firebird and Oracle ( https://docs.liquibase.com/concepts/advanced/column.html ). Therefore it is not possible to insert a column at a specific position in Firebird or after a column in Oracle.
There is also no documentation on which dbms supports ‘afterColumn’ or ‘position’.
Steps To Reproduce
JUnit Test:
@Test
void testLiquibaseOrderBug() throws IOException {
DatabaseChangeLog log = new DatabaseChangeLog();
ChangeSet set = new ChangeSet("Test", "test", Boolean.FALSE, Boolean.FALSE, null, "context",
"firebird", log);
AddColumnChange addcol = new AddColumnChange();
addcol.setTableName("MI6");
AddColumnConfig addColumnConfig = new AddColumnConfig();
addColumnConfig.setType("int");
addColumnConfig.setValueNumeric(0);
addColumnConfig.setName("James");
addColumnConfig.setPosition(2);
addcol.addColumn(addColumnConfig);
set.addChange(addcol);
String[] changesets = getXmlChangelogAsArray(set);
assertEquals("<column name=\"James\" position=\"2\" type=\"int\" valueNumeric=\"0\"/>",changesets[4].trim());
assertEquals("ALTER TABLE MI6 ADD James INT POSITION 2;", getLiquiSql("firebird", set));
}
@Test
void testLiquibaseAfterBug() throws IOException {
DatabaseChangeLog log = new DatabaseChangeLog();
ChangeSet set = new ChangeSet("Test", "test", Boolean.FALSE, Boolean.FALSE, null, "context",
"oracle", log);
AddColumnChange addcol = new AddColumnChange();
addcol.setTableName("MI6");
AddColumnConfig addColumnConfig = new AddColumnConfig();
addColumnConfig.setType("int");
addColumnConfig.setValueNumeric(0);
addColumnConfig.setName("James");
addColumnConfig.setAfterColumn("Bond");
addcol.addColumn(addColumnConfig);
set.addChange(addcol);
String[] changesets = getXmlChangelogAsArray(set);
assertEquals("<column afterColumn=\"Bond\" name=\"James\" type=\"int\" valueNumeric=\"0\"/>",changesets[4].trim());
assertEquals("ALTER TABLE MI6 ADD James INTEGER AFTER Bond;", getLiquiSql("oracle", set));
}
private String[] getXmlChangelogAsArray(ChangeSet set) throws IOException {
List<ChangeLogChild> changes = new ArrayList<>();
changes.add(set);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ChangeLogSerializer serializer = new XMLChangeLogSerializer();
serializer.write(changes, stream);
String[] changesets = new String(stream.toByteArray()).replaceAll("\r", "")
.split("\n");
return changesets;
}
private String getLiquiSql(String dbms, ChangeSet set) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ChangeLogSerializer serializer = new FormattedSqlChangeLogSerializer();
set.setFilePath("export."+dbms+".sql");
List<ChangeLogChild> changes = new ArrayList<>();
changes.add(set);
serializer.write(changes, stream);
return new String(stream.toByteArray()).split("\n")[3];
}
Actual Behavior
Positions and afterColumn tags are ignored.
An afterTable tag in Oracle leads to following sql: ALTER TABLE MI6 ADD James INTEGER
A position tag in Firebird leads to following sql: ALTER TABLE MI6 ADD James INT
Expected/Desired Behavior
<changeSet author="test" context="context" dbms="firebird" id="Test" objectQuotingStrategy="LEGACY"> <addColumn tableName="MI6"> <column name="James" position="2" type="int" valueNumeric="0"/> </addColumn> </changeSet>
should create in Firebird something like
ALTER TABLE MI6 ADD James INT POSITION 2
and
<changeSet author="test" context="context" dbms="firebird,oracle,mssql" id="Test" objectQuotingStrategy="LEGACY"> <addColumn tableName="MI6"> <column afterColumn="Bond" name="James" type="int" valueNumeric="0"/> </addColumn> </changeSet>
should create in Oracle something like
ALTER TABLE MI6 ADD James INTEGER AFTER Bond
Issue Analytics
- State:
- Created 3 years ago
- Comments:9 (6 by maintainers)
Top GitHub Comments
@chenmeister Thanks for the replay. I learned something again today.
Hi @kuhjunge Thanks for doing the research. I found that the same
alter table mi6 alter james position 2
works as the way you describe on Firebird 3.0 too.but that means
<changeSet author="test" context="context" dbms="firebird" id="Test" objectQuotingStrategy="LEGACY"> <addColumn tableName="MI6"> <column name="James" position="2" type="int" valueNumeric="0"/> </addColumn> </changeSet>
is two sql statements
ALTER TABLE MI6 ADD James INT;
andALTER TABLE MI6 alter James position 2;
which means 2 alter table statements are needed for the single changeset on Firebird. The first adds the column and the second moves it.
Where MYSQL is only one statement.
ALTER TABLE MI6 ADD James INT after bond;
Is that what you see? If so, we need to rethink the PR that was used to fix this issue.