[ 
https://issues.apache.org/jira/browse/DERBY-3175?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12540655
 ] 

Bryan Pendleton commented on DERBY-3175:
----------------------------------------

The core of the problem happens when 
AlterTableConstantAction.dropColumnFromTable 
calls SYSCOLUMNSRowFactory.makeRow (via DataDictionaryImpl.addDescriptorArray).

The relevant dropColumnFromTable code is here:

                // drop the column from syscolumns 
                dd.dropColumnDescriptor(td.getUUID(), columnInfo[ix].name, tc);
                ColumnDescriptor[] cdlArray = 
            new ColumnDescriptor[size - columnDescriptor.getPosition()];

                for (int i = columnDescriptor.getPosition(), j = 0; i < size; 
i++, j++)
                {
                        ColumnDescriptor cd = (ColumnDescriptor) 
tab_cdl.elementAt(i);
                        dd.dropColumnDescriptor(td.getUUID(), 
cd.getColumnName(), tc);
                        cd.setPosition(i);
                        cdlArray[j] = cd;
                }
                dd.addDescriptorArray(cdlArray, td,
                                                          
DataDictionary.SYSCOLUMNS_CATALOG_NUM, false, tc);

This code does the following:
1) For the column we're dropping, deletes the corresponding row from SYSCOLUMNS
2) For each column *after* the column we're dropping, deletes that column's
row from SYSCOLUMNS, and accumulates that ColumnDescriptor object into the
cdlArray, updating the ColumnDescriptor to have the new position of that column 
in the table
3) calls addDescriptorArray to add the new SYSCOLUMNS rows for the columns with
the modified positions.

DataDictionaryImpl.addDescriptorArray then makes a new row for each 
ColumnDescriptor
with this code:

                for (int index = 0; index < td.length; index++)
                {
                        ExecRow row = crf.makeRow(td[index], parent);
                        rl[index] = row;
                }

And the crf.makeRow() call arrives at SYSCOLUMNSRowFactory.makeRow.

*HOWEVER*, SYSCOLUMNSRowFactory.makeRow expects that the ColumnDescriptor
will specify how to set the autoincInc, autoincStart, and autoincValue columns 
in SYSCOLUMNS
via the awkwardly-named getAutoinc_create_or_modify_Start_Increment() value:

                if (autoinc_create_or_modify_Start_Increment == 
ColumnDefinitionNode.CREATE_AUTOINCREMENT ||
                                autoinc_create_or_modify_Start_Increment == 
ColumnDefinitionNode.MODIFY_AUTOINCREMENT_INC_VALUE)
                {//user is adding an autoinc column or is changing the 
increment value of autoinc column
                        row.setColumn(SYSCOLUMNS_AUTOINCREMENTVALUE, 
                                                  new SQLLongint(autoincStart));
                        row.setColumn(SYSCOLUMNS_AUTOINCREMENTSTART, 
                                                  new SQLLongint(autoincStart));
                        row.setColumn(SYSCOLUMNS_AUTOINCREMENTINC, 
                                                  new SQLLongint(autoincInc));
                } else if (autoinc_create_or_modify_Start_Increment == 
ColumnDefinitionNode.MODIFY_AUTOINCREMENT_RESTART_VALUE)
                {//user asked for restart with a new value, so don't change 
increment by and original start
                        //with values in the SYSCOLUMNS table. Just record the 
RESTART WITH value as the
                        //next value to be generated in the SYSCOLUMNS table
                        ColumnDescriptor  column = (ColumnDescriptor)td;
                        row.setColumn(SYSCOLUMNS_AUTOINCREMENTVALUE, new 
SQLLongint(autoincStart));
                        row.setColumn(SYSCOLUMNS_AUTOINCREMENTSTART, new 
SQLLongint(autoincStart));
                        row.setColumn(SYSCOLUMNS_AUTOINCREMENTINC, new 
SQLLongint(
                                        
column.getTableDescriptor().getColumnDescriptor(colName).getAutoincInc()));
                }
                else
                {
                        row.setColumn(SYSCOLUMNS_AUTOINCREMENTVALUE, 
                                                  new SQLLongint());
                        row.setColumn(SYSCOLUMNS_AUTOINCREMENTSTART, 
                                                  new SQLLongint());
                        row.setColumn(SYSCOLUMNS_AUTOINCREMENTINC,
                                                  new SQLLongint());
                }

But when we are re-adding the column descriptors in 
AlterTableConstantAction.dropColumnFromTable,
this autoinc_create_or_modify_Start_Increment value is not set, and so the 
makeRow() code
falls into the "else" block above, and resets the autoincement fields to 0, thus
corrupting the SYSCOLUMNS row.

I suspect the fix is as simple as forcing a value of 
ColumnDefinitionNode.CREATE_AUTOINCREMENT
when re-adding the ColumnDescriptors; I'll try this fix in a little while and 
report back on the results.


> NullPointerException on INSERT after ALTER TABLE ... DROP COLUMN
> ----------------------------------------------------------------
>
>                 Key: DERBY-3175
>                 URL: https://issues.apache.org/jira/browse/DERBY-3175
>             Project: Derby
>          Issue Type: Bug
>          Components: SQL
>    Affects Versions: 10.3.1.4, 10.4.0.0
>            Reporter: Knut Anders Hatlen
>            Assignee: Bryan Pendleton
>         Attachments: bug.sql
>
>
> ij version 10.3
> ij> connect 'jdbc:derby:bugdb;create=true';
> ij> create table t (
>        x varchar(12),
>        y varchar(12),
>        id int primary key generated by default as identity
> );
> 0 rows inserted/updated/deleted
> ij> alter table t drop column y;
> 0 rows inserted/updated/deleted
> ij> insert into t(x) values 'a';
> ERROR XJ001: Java exception: ': java.lang.NullPointerException'.
> java.sql.SQLException: Java exception: ': java.lang.NullPointerException'.
>         at 
> org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown 
> Source)
>         at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown 
> Source)
>         at org.apache.derby.impl.jdbc.Util.javaException(Unknown Source)
>         at 
> org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(Unknown 
> Source)
>         at 
> org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown 
> Source)
>         at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown 
> Source)
>         at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown 
> Source)
>         at org.apache.derby.impl.jdbc.EmbedStatement.execute(Unknown Source)
>         at org.apache.derby.impl.jdbc.EmbedStatement.execute(Unknown Source)
>         at org.apache.derby.impl.tools.ij.ij.executeImmediate(Unknown Source)
>         at org.apache.derby.impl.tools.ij.utilMain.doCatch(Unknown Source)
>         at org.apache.derby.impl.tools.ij.utilMain.runScriptGuts(Unknown 
> Source)
>         at org.apache.derby.impl.tools.ij.utilMain.go(Unknown Source)
>         at org.apache.derby.impl.tools.ij.Main.go(Unknown Source)
>         at org.apache.derby.impl.tools.ij.Main.mainCore(Unknown Source)
>         at org.apache.derby.impl.tools.ij.Main14.main(Unknown Source)
>         at org.apache.derby.tools.ij.main(Unknown Source)
>         at org.apache.derby.iapi.tools.run.main(Unknown Source)
> Caused by: java.sql.SQLException: Java exception: ': 
> java.lang.NullPointerException'.
>         at 
> org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
>         at 
> org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown
>  Source)
>         ... 18 more
> Caused by: java.lang.NullPointerException
>         at 
> org.apache.derby.impl.sql.compile.ResultColumn.columnTypeAndLengthMatch(Unknown
>  Source)
>         at 
> org.apache.derby.impl.sql.compile.ResultColumnList.columnTypesAndLengthsMatch(Unknown
>  Source)
>         at org.apache.derby.impl.sql.compile.InsertNode.bindStatement(Unknown 
> Source)
>         at org.apache.derby.impl.sql.GenericStatement.prepMinion(Unknown 
> Source)
>         at org.apache.derby.impl.sql.GenericStatement.prepare(Unknown Source)
>         at 
> org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(Unknown
>  Source)
>         ... 11 more

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to