title: In Liquibase, how to add a new column/field to an existing composite primary key
body: <p>We have an <em>existing table</em>, with 2 existing columns that serve as a composite primary key.  They were set up very similarly to this:</p>
  <pre class="lang-xml prettyprint-override"><code>&lt;!--  WE CAN NO LONGER MODIFY THIS CHANGESET  --&gt;
  
  &lt;changeSet author=&quot;an_awesome_author&quot; id=&quot;EXAMPLE-01&quot;&gt;
    &lt;createTable tableName=&quot;our_awesome_table&quot;&gt;
      &lt;column name=&quot;source&quot; type=&quot;varchar(32)&quot;&gt;
        &lt;constraints 
            primaryKey=&quot;true&quot; 
            nullable=&quot;false&quot; 
            primaryKeyName=&quot;CPK_OUR_AWESOME_TABLE&quot;/&gt;
      &lt;/column&gt;
      &lt;column
          name=&quot;external_id&quot;
          type=&quot;varchar(255)&quot;&gt;
        &lt;constraints 
            primaryKey=&quot;true&quot; 
            nullable=&quot;false&quot;  
            primaryKeyName=&quot;CPK_OUR_AWESOME_TABLE&quot;/&gt;
      &lt;/column&gt;
    &lt;/createTable&gt;
  &lt;/changeSet&gt;
  </code></pre>
  <hr />
  <p>It has subsequently come to our attention that there can be multiple records with the same <code>source</code> &amp; <code>external_id</code> (<img src="https://i.stack.imgur.com/40silt.gif" width="20" alt="twitching eye" />).  The group submitting the data submits on a regular schedule and they've assured us that they never use the same combination of <code>source</code> &amp; <code>external_id</code> in the same batch of data.</p>
  <p>So (for reasons beyond this question) we've decided that we're going to add a <code>created_at</code> field, that is non-nullable and defaults to when each record is added to the table.  That's not that difficult, e.g. we can run this pair of <code>changeSet</code>s</p>
  <pre class="lang-xml prettyprint-override"><code>&lt;!-- WE ARE TRYING TO FINALIZE THESE CHANGESETS --&gt;
  
  &lt;changeSet author=&quot;yours_truly&quot;
             id=&quot;EXAMPLE-02-01&quot;&gt;
    &lt;addColumn tableName=&quot;our_awesome_table&quot;&gt;
      &lt;column name=&quot;CREATED_AT&quot;
              type=&quot;datetime&quot;
              valueDate=&quot;current_datetime&quot;
              defaultValueDate=&quot;current_datetime&quot; /&gt;
      &lt;!-- the above:
        adds the new field
        sets the type
        adds the current timestamp to existing records
        will default to the current timestamp for new records
      --&gt;
    &lt;/addColumn&gt;
  &lt;/changeSet&gt;
  &lt;changeSet author=&quot;yours_truly&quot;
             id=&quot;EXAMPLE-02-02&quot;&gt;
    &lt;addNotNullConstraint tableName=&quot;our_awesome_table&quot;
                          columnName=&quot;CREATED_AT&quot;/&gt;
    &lt;!-- the above:
      now that every record has a value in the newly created field,
      we can add a constrant preventing null entries into the column
    --&gt;
  &lt;/changeSet&gt;
  </code></pre>
  <hr />
  <p><strong><em>BUT, we also need to add <code>created_at</code> to our existing composite primary key!</em></strong></p>
  <p>If I try to include the primary key as a constraint when we're creating the field it complains about the table only being able to have one primary key —<em>despite the fact that it's already a composite key and I'm only trying add this to the already in existence composite key.</em>  But it also complains about the <code>created_at</code> timestamp being null.  So, I'm not sure which is the actual problem ‍♂️, but it definitely doesn't work here.</p>
  <p>e.g.</p>
  <pre class="lang-xml prettyprint-override"><code>&lt;changeSet author=&quot;yours_truly&quot;
             id=&quot;EXAMPLE-02-01&quot;&gt;
    &lt;addColumn tableName=&quot;our_awesome_table&quot;&gt;
      &lt;column name=&quot;CREATED_AT&quot;
              type=&quot;datetime&quot;
              valueDate=&quot;current_datetime&quot;
              defaultValueDate=&quot;current_datetime&quot;&gt;
        &lt;constraints primaryKey=&quot;true&quot;
                     primaryKeyName=&quot;PK_OUR_AWESOME_TABLE&quot;/&gt;
        &lt;!-- this constraints causes multiple problems --&gt;
      &lt;/column&gt;
    &lt;/addColumn&gt;
  &lt;/changeSet&gt;
  </code></pre>
  <p>results in something like:</p>
  <pre class="lang-sh prettyprint-override"><code>[ERROR]      Reason: liquibase.exception.DatabaseException: ORA-02260: table can have only one primary key
  [ERROR]  [Failed SQL: ALTER TABLE OUR_AWESOME_TABLE.OUR_AWESOME_TABLE ADD CREATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP PRIMARY KEY NOT NULL]
  </code></pre>
  <hr />
  <p>If I try to include the primary key as a <code>&lt;constraint&gt;</code> in the changeSet where we add the non-nullable constraint then I'm basically told that I can't use <code>&lt;constraints&gt;</code> there and instead need to one of a list of <code>&lt;addXxxConstraint&gt;</code> and in the list is an <code>&lt;addPrimaryKey&gt;</code> —this sounds like the right constraint.</p>
  <p>So if I change the second changeSet to something like this, I would expect it to work:</p>
  <pre class="lang-xml prettyprint-override"><code>&lt;changeSet author=&quot;yours_truly&quot;
             id=&quot;EXAMPLE-02-02&quot;&gt;
    &lt;addNotNullConstraint tableName=&quot;our_awesome_table&quot;
                          columnName=&quot;CREATED_AT&quot;/&gt;
    &lt;addPrimaryKey tableName=&quot;our_awesome_table&quot;
                   columnNames=&quot;CREATED_AT&quot;
                   primaryKeyName=&quot;CPK_OUR_AWESOME_TABLE&quot;/&gt;
  &lt;/changeSet&gt;
  </code></pre>
  <p><em>But</em> —as you can probably guess— it doesn't work.  Instead, it informs me that, <code>cvc-complex-type.3.2.2: Attribute 'primaryKeyName' is not allowed to appear in element 'addPrimaryKey'.</code></p>
  <hr />
  <p><strong><em>So, how can I add a new non-nullable field, to an existing composite primary key?</em></strong></p>