db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Knut Anders Hatlen (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (DERBY-4160) getMetaData().getIndexInfo crashes with "ERROR X0Y68: Column 'PARAM1' already exists."
Date Wed, 19 Feb 2014 14:20:24 GMT

    [ https://issues.apache.org/jira/browse/DERBY-4160?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13905475#comment-13905475

Knut Anders Hatlen commented on DERBY-4160:

It looks like this is a race condition in the handling of the SYS.SYSSTATEMENTS.INITIALLY_COMPILABLE
column. We have seen other race conditions in the handling of this column before, see for
example DERBY-2584.

The column tells whether a stored prepared statement is compiled when it's created, or if
it has to be compiled later. In practice, this means it should be true for trigger statements,
and false for meta-data statements (because meta-data statements are added to the database
so early in the database creation or upgrade that there is no LanguageConnectionContext available
yet, and they cannot be compiled).

However, once a meta-data statement has been compiled, the value of the column is switched
from false to true. So it doesn't actually tell whether the SPS was initially compilable,
but rather whether it has been compiled at least once. This is used by DataDictionaryImpl.updateSPS()
to decide whether it should update the existing SPS or create it from scratch.

What happens in the repro, is: Two threads attempt to execute the same meta-data query. They
both read the SPSDescriptor from the dictionary, and they both see that INITIALLY_COMPILABLE
is false because the meta-data query has not been executed before. Both of them compile the
query, and both of them try to store the SPS. Because of locking in the system tables, one
of them has to wait for the other to complete before it goes ahead and stores it. Since it
had previously seen that INITIALLY_COMPILABLE was false, it gets confused when it finds that
the SPS is already in the database, and throws the above mentioned exception "ERROR X0Y68:
Column 'PARAM1' already exists."

I suppose we could add more logic to synchronize between the two threads to avoid the race
condition. But I think the best solution would be to change the use of INITIALLY_COMPILABLE
so that its value represents what its name suggests: whether or not the statement was initially
compilable. Now, since this means INITIALLY_COMPILABLE won't change during the lifetime of
the SPS, it also means that there won't be any race conditions when accessing it.

This change means that DataDictionaryImpl.updateSPS() can no longer tell whether or not the
SPS is already stored in the database based on that column. But that information is not strictly
needed. It is currently used in order to decide whether the existing SPS should be updated
or a new one created. We could instead change the code to always replace the existing one
(that is, delete the existing one if one exists, and create a new one). This change will actually
simplify this part of the code significantly, since we get a shared code path for the first
compilation of an SPS and subsequent recompilations, whereas they currently have two separate
code paths. Additionally, the redefinition of INITIALLY_COMPILABLE probably fixes DERBY-2584
as well, so that we can remove the current workaround that we have for that bug.

> getMetaData().getIndexInfo crashes with "ERROR X0Y68: Column 'PARAM1' already exists."
> --------------------------------------------------------------------------------------
>                 Key: DERBY-4160
>                 URL: https://issues.apache.org/jira/browse/DERBY-4160
>             Project: Derby
>          Issue Type: Bug
>          Components: SQL
>    Affects Versions:
>         Environment: FreeBSD java 1.6.0, 64-Bit Server VM; DataNucleus JDO
>            Reporter: ArtemGr
>            Assignee: Knut Anders Hatlen
>              Labels: derby_triage10_5_2
>         Attachments: D4160.java
> The following code in DataNucleus:
> rs = conn.getMetaData().getIndexInfo(catalogName, schemaName, tableName, false,
> true);
> triggers an Exception (http://gist.github.com/95679):
> Caused by: java.sql.SQLException: Column 'PARAM1' already exists.
>         at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(SQLExceptionFactory.java:45)
>         at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(SQLExceptionFactory40.java:119)
>         at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(SQLExceptionFactory40.java:70)
>         ... 105 more
> Caused by: ERROR X0Y68: Column 'PARAM1' already exists.
>         at org.apache.derby.iapi.error.StandardException.newException(StandardException.java:303)
>         at org.apache.derby.impl.sql.catalog.DataDictionaryImpl.duplicateDescriptorException(DataDictionaryImpl.java:1678)
>         at org.apache.derby.impl.sql.catalog.DataDictionaryImpl.addDescriptor(DataDictionaryImpl.java:1662)
>         at org.apache.derby.impl.sql.catalog.DataDictionaryImpl.addSPSParams(DataDictionaryImpl.java:3682)
>         at org.apache.derby.impl.sql.catalog.DataDictionaryImpl.updateSPS(DataDictionaryImpl.java:3830)
>         at org.apache.derby.iapi.sql.dictionary.SPSDescriptor.updateSYSSTATEMENTS(SPSDescriptor.java:1112)
>         at org.apache.derby.iapi.sql.dictionary.SPSDescriptor.getPreparedStatement(SPSDescriptor.java:736)
>         at org.apache.derby.iapi.sql.dictionary.SPSDescriptor.getPreparedStatement(SPSDescriptor.java:642)
>         at org.apache.derby.impl.sql.compile.ExecSPSNode.generate(ExecSPSNode.java:177)
>         at org.apache.derby.impl.sql.GenericStatement.prepMinion(GenericStatement.java:447)
>         at org.apache.derby.impl.sql.GenericStatement.prepare(GenericStatement.java:88)
>         at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(GenericLanguageConnectionContext.java:794)
>         at org.apache.derby.impl.jdbc.EmbedPreparedStatement.<init>(EmbedPreparedStatement.java:128)
>         ... 99 more

This message was sent by Atlassian JIRA

View raw message