Uploaded image for project: 'Jira Data Center'
  1. Jira Data Center
  2. JRASERVER-59681

Version Picker (multiple versions) incorrectly persists data in JIRA change history

    XMLWordPrintable

Details

    Description

      Summary

      The Version Picker (multiple versions) custom field incorrectly persists data in the change history table when making changes to issues. This can cause project imports to subsequently fail as the data's not in an expected state.

      Steps to Reproduce

      1. Create a Version Picker (multiple versions).
      2. Create an issue in a project that has versions.
      3. Edit the issue to have a version in that field.

      Expected Results

      The data is persisted normally.

      Actual Results

      The data is persisted inside square brackets, such as [123456], instead of 123456.

      This can also lead to project imports failing with the below exception:

      2016-01-22 16:20:57,097 JiraTaskExectionThread-10 ERROR sysadmin 978x3742x1 z25doj 0:0:0:0:0:0:0:1 /secure/admin/ProjectImportSummary.jspa [c.a.jira.task.TaskManagerImpl] Task 'Importing project 'Central Services'.' failed.
      java.lang.NumberFormatException: For input string: "[10150]"
      	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
      	at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
      	at java.lang.Double.parseDouble(Double.java:538)
      	at java.lang.Double.<init>(Double.java:608)
      	at com.atlassian.jira.imports.project.customfield.VersionCustomFieldImporter.getNonDecimalValue(VersionCustomFieldImporter.java:36)
      	at com.atlassian.jira.imports.project.customfield.VersionCustomFieldImporter.getMappedImportValue(VersionCustomFieldImporter.java:26)
      	at com.atlassian.jira.imports.project.transformer.ChangeItemTransformerImpl.mapCustomFieldIdList(ChangeItemTransformerImpl.java:73)
      	at com.atlassian.jira.imports.project.transformer.ChangeItemTransformerImpl.transform(ChangeItemTransformerImpl.java:55)
      	at com.atlassian.jira.imports.project.handler.ChangeItemPersisterHandler.handleEntity(ChangeItemPersisterHandler.java:54)
      	at com.atlassian.jira.imports.project.handler.ChainedOfBizSaxHandler.endTopLevelElement(ChainedOfBizSaxHandler.java:219)
      	at com.atlassian.jira.imports.project.handler.ChainedOfBizSaxHandler.endElement(ChainedOfBizSaxHandler.java:167)
      	at com.atlassian.jira.imports.project.handler.ChainedOfBizSaxHandler.endElement(ChainedOfBizSaxHandler.java:134)
      	at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source)
      	at org.apache.xerces.parsers.AbstractXMLDocumentParser.emptyElement(Unknown Source)
      	at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanStartElement(Unknown Source)
      	at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
      	at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
      	at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
      	at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
      	at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
      	at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
      	at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
      	at com.atlassian.security.xml.RestrictedXMLReader.parse(RestrictedXMLReader.java:103)
      	at com.atlassian.jira.imports.xml.DefaultBackupXmlParser$XmlParser.parseXml(DefaultBackupXmlParser.java:115)
      	at com.atlassian.jira.imports.xml.DefaultBackupXmlParser.parse(DefaultBackupXmlParser.java:64)
      	at com.atlassian.jira.imports.xml.DefaultBackupXmlParser.parseXml(DefaultBackupXmlParser.java:52)
      	at com.atlassian.jira.imports.xml.DefaultBackupXmlParser.parseOfBizBackupXml(DefaultBackupXmlParser.java:41)
      	at com.atlassian.jira.imports.project.DefaultProjectImportManager.importChangeItemEntities(DefaultProjectImportManager.java:1113)
      	at com.atlassian.jira.imports.project.DefaultProjectImportManager.doImport(DefaultProjectImportManager.java:659)
      	at com.atlassian.jira.bc.imports.project.DefaultProjectImportService.doImport(DefaultProjectImportService.java:416)
      	at com.atlassian.jira.web.action.admin.importer.project.ProjectImportSummary$ProjectImportCallable.call(ProjectImportSummary.java:285)
      	at com.atlassian.jira.web.action.admin.importer.project.ProjectImportSummary$ProjectImportCallable.call(ProjectImportSummary.java:236)
      	at com.atlassian.jira.task.TaskManagerImpl$TaskCallableDecorator.call(TaskManagerImpl.java:458)
      	at com.atlassian.jira.task.TaskManagerImpl$TaskCallableDecorator.call(TaskManagerImpl.java:426)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      	at com.atlassian.jira.task.ForkedThreadExecutor$ForkedRunnableDecorator.run(ForkedThreadExecutor.java:216)
      	at java.lang.Thread.run(Thread.java:745)
      

      Also if the workaround is applied without removing empty values it can result in the following:

      2016-10-13 12:09:30,335 JiraTaskExectionThread-9 ERROR jira_user 728x1290x1 1osbo1w 0:0:0:0:0:0:0:1 /secure/admin/ProjectImportSummary.jspa [c.a.jira.task.TaskManagerImpl] Task 'Importing project 'JEM 2.0'.' failed.
      java.lang.NumberFormatException: empty String
      	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
      	at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
      	at java.lang.Double.parseDouble(Double.java:538)
      	at java.lang.Double.<init>(Double.java:608)
      	at com.atlassian.jira.imports.project.customfield.VersionCustomFieldImporter.getNonDecimalValue(VersionCustomFieldImporter.java:36)
      	at com.atlassian.jira.imports.project.customfield.VersionCustomFieldImporter.getMappedImportValue(VersionCustomFieldImporter.java:26)
      	at com.atlassian.jira.imports.project.transformer.ChangeItemTransformerImpl.mapCustomFieldIdList(ChangeItemTransformerImpl.java:73)
      	at com.atlassian.jira.imports.project.transformer.ChangeItemTransformerImpl.transform(ChangeItemTransformerImpl.java:53)
      	at com.atlassian.jira.imports.project.handler.ChangeItemPersisterHandler.handleEntity(ChangeItemPersisterHandler.java:54)
      	at com.atlassian.jira.imports.project.handler.ChainedOfBizSaxHandler.endTopLevelElement(ChainedOfBizSaxHandler.java:219)
      	at com.atlassian.jira.imports.project.handler.ChainedOfBizSaxHandler.endElement(ChainedOfBizSaxHandler.java:167)
      	at com.atlassian.jira.imports.project.handler.ChainedOfBizSaxHandler.endElement(ChainedOfBizSaxHandler.java:134)
      	at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source)
      

      Notes

      The XML backup and restore functionality will still continue to work.

      Workaround

      If needing to project import, the database can be edited with the below steps. These were verified on PostgreSQL and the syntax may vary for different DBMS.

      1. Backup JIRA.
      2. Stop JIRA.
      3. Run these queries to identify the rows you need to update:

      SELECT * FROM changeitem WHERE oldvalue LIKE '[%]' OR newvalue LIKE '[%]';

      4. Execute the below SQL to remove the brackets:

      • PostgreSQL
        UPDATE changeitem SET oldvalue = TRIM(BOTH '[]' FROM oldvalue), newvalue = TRIM(BOTH '[]' FROM newvalue) WHERE field = '<affected field name>';
      • MySQL
        UPDATE changeitem SET oldvalue = TRIM(LEADING '[' FROM oldvalue), oldvalue = TRIM(TRAILING ']' FROM oldvalue), newvalue = TRIM(LEADING '[' FROM newvalue), newvalue = TRIM(TRAILING ']' FROM newvalue) WHERE field = '<affected field name>';

      5. In some cases, this may cause empty values to be present. We can identify these cases with the following query:

      SELECT * FROM changeitem WHERE oldvalue = '' OR newvalue = '';

      6. We can fix these with the below (run the first query if oldvalue is the field that's blank, and the second query if it's newvalue that's blank):

      UPDATE changeitem SET oldvalue = NULL WHERE oldvalue = '' AND field = <affected field name>;
      UPDATE changeitem SET newvalue = NULL WHERE newvalue = '' AND field = <affected field name>;

      7. Start JIRA.
      8. Generate an XML backup and use that for importing into the target instance.

      KB article related to this: https://confluence.atlassian.com/jirakb/version-picker-multiple-versions-incorrectly-persists-data-in-jira-change-history-875322422.html

      Attachments

        Issue Links

          Activity

            People

              9e3a0496a19c Jakub Sildatk
              dcurrie@atlassian.com Dave C
              Votes:
              47 Vote for this issue
              Watchers:
              55 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: