db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Bryan Pendleton (JIRA)" <j...@apache.org>
Subject [jira] Commented: (DERBY-3175) NullPointerException on INSERT after ALTER TABLE ... DROP COLUMN
Date Wed, 07 Nov 2007 02:53:50 GMT

    [ 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.


Mime
View raw message