question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

'afterColumn' and 'position' not working in Firebird and Oracle databases

See original GitHub issue

Environment

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:closed
  • Created 3 years ago
  • Comments:9 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
theovanessencommented, Nov 2, 2020

@chenmeister Thanks for the replay. I learned something again today.

0reactions
molivasdatcommented, Jan 5, 2021

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; and ALTER 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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

afterColumn not working in DB liquibase 3.2.2 - Stack Overflow
According to this link, afterColumn works in DB liquibase now. But its still not working on my system. I am using DB liquibase...
Read more >
addColumn | Liquibase Docs
Step 2: Deploy your changeset by running the update command. ... sets all rows existing to the specified value without modifying the column...
Read more >
order of table columns: alter table add/modify ... position ...
I would like to resubmit the not very popular "Need a command to reorder columns in a ... MySQL allows ALTER TABLE ADD...
Read more >
Liquibase createIndex column order – iTecNote
I'm trying to use Liquibase for our project. We mainly use Oracle database and some other database less often. I'm trying to figureout...
Read more >
Liquibase 3.0.4 Released
Even an Oracle database with the same structure finished in a couple minutes. ... [CORE-1469] – GenerateChangelog not working on Firebird; [CORE-1470] –...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found