Skip to content

Commit

Permalink
Bug 61532: Fix setting values/types during formula evaluation for SXSSF
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1849880 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
centic9 committed Dec 28, 2018
1 parent 24b07f1 commit 2b8200f
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 54 deletions.
47 changes: 39 additions & 8 deletions src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ Licensed to the Apache Software Foundation (ASF) under one or more
* Streaming version of XSSFCell implementing the "BigGridDemo" strategy.
*/
public class SXSSFCell implements Cell {
private static final POILogger logger = POILogFactory.getLogger(SXSSFCell.class);

private final SXSSFRow _row;
private Value _value;
private CellStyle _style;
Expand Down Expand Up @@ -277,15 +275,19 @@ public void setCellValue(Calendar value) {
public void setCellValue(RichTextString value)
{
XSSFRichTextString xvalue = (XSSFRichTextString)value;

if (xvalue != null && xvalue.getString() != null) {
ensureRichTextStringType();

if (xvalue.length() > SpreadsheetVersion.EXCEL2007.getMaxTextLength()) {
throw new IllegalArgumentException("The maximum length of cell contents (text) is 32,767 characters");
}

((RichTextValue)_value).setValue(xvalue);
if(_value instanceof RichTextStringFormulaValue) {
((RichTextStringFormulaValue) _value).setPreEvaluatedValue(xvalue);
} else {
((RichTextValue) _value).setValue(xvalue);
}
} else {
setCellType(CellType.BLANK);
}
Expand All @@ -312,6 +314,8 @@ public void setCellValue(String value)
if(_value.getType()==CellType.FORMULA)
if(_value instanceof NumericFormulaValue) {
((NumericFormulaValue) _value).setPreEvaluatedValue(Double.parseDouble(value));
} else if(_value instanceof RichTextStringFormulaValue) {
((RichTextStringFormulaValue) _value).setPreEvaluatedValue(new XSSFRichTextString(value));
} else {
((StringFormulaValue) _value).setPreEvaluatedValue(value);
}
Expand Down Expand Up @@ -461,7 +465,11 @@ public String getStringCellValue()
FormulaValue fv=(FormulaValue)_value;
if(fv.getFormulaType()!=CellType.STRING)
throw typeMismatch(CellType.STRING, CellType.FORMULA, false);
return ((StringFormulaValue)_value).getPreEvaluatedValue();
if(_value instanceof RichTextStringFormulaValue) {
return ((RichTextStringFormulaValue) _value).getPreEvaluatedValue().getString();
} else {
return ((StringFormulaValue) _value).getPreEvaluatedValue();
}
}
case STRING:
{
Expand Down Expand Up @@ -841,9 +849,15 @@ public String toString() {
}
/*package*/ void ensureRichTextStringType()
{
if(_value.getType()!=CellType.STRING
||!((StringValue)_value).isRichText())
// don't change cell type for formulas
if(_value.getType() == CellType.FORMULA) {
String formula = ((FormulaValue)_value).getValue();
_value = new RichTextStringFormulaValue();
((RichTextStringFormulaValue) _value).setValue(formula);
} else if(_value.getType()!=CellType.STRING ||
!((StringValue)_value).isRichText()) {
_value = new RichTextValue();
}
}
/*package*/ void ensureType(CellType type)
{
Expand Down Expand Up @@ -1206,6 +1220,23 @@ String getPreEvaluatedValue()
return _preEvaluatedValue;
}
}
static class RichTextStringFormulaValue extends FormulaValue
{
RichTextString _preEvaluatedValue;
@Override
CellType getFormulaType()
{
return CellType.STRING;
}
void setPreEvaluatedValue(RichTextString value)
{
_preEvaluatedValue=value;
}
RichTextString getPreEvaluatedValue()
{
return _preEvaluatedValue;
}
}
static class BooleanFormulaValue extends FormulaValue
{
boolean _preEvaluatedValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,20 @@ public void writeCell(int columnIndex, Cell cell) throws IOException {
break;
}
case FORMULA: {
switch(cell.getCachedFormulaResultType()) {
case NUMERIC:
writeAttribute("t", "n");
break;
case STRING:
writeAttribute("t", STCellType.S.toString());
break;
case BOOLEAN:
writeAttribute("t", "b");
break;
case ERROR:
writeAttribute("t", "e");
break;
}
_out.write("><f>");
outputQuotedString(cell.getCellFormula());
_out.write("</f>");
Expand All @@ -274,8 +288,27 @@ public void writeCell(int columnIndex, Cell cell) throws IOException {
_out.write("</v>");
}
break;
default:
case STRING:
String value = cell.getStringCellValue();
if(value != null && !value.isEmpty()) {
_out.write("<v>");
_out.write(value);
_out.write("</v>");
}
break;
case BOOLEAN:
_out.write("><v>");
_out.write(cell.getBooleanCellValue() ? "1" : "0");
_out.write("</v>");
break;
case ERROR: {
FormulaError error = FormulaError.forInt(cell.getErrorCellValue());

_out.write("><v>");
_out.write(error.getString());
_out.write("</v>");
break;
}
}
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.apache.poi.xssf.streaming;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;

import java.io.IOException;
Expand Down Expand Up @@ -101,14 +102,14 @@ public void testEvaluateRefOutsideWindowFails() throws IOException {
SXSSFSheet s = wb.createSheet();

s.createRow(0).createCell(0).setCellFormula("1+2");
assertEquals(false, s.areAllRowsFlushed());
assertFalse(s.areAllRowsFlushed());
assertEquals(-1, s.getLastFlushedRowNum());

for (int i=1; i<=19; i++) { s.createRow(i); }
Cell c = s.createRow(20).createCell(0);
c.setCellFormula("A1+100");
assertEquals(false, s.areAllRowsFlushed());

assertFalse(s.areAllRowsFlushed());
assertEquals(15, s.getLastFlushedRowNum());

FormulaEvaluator eval = wb.getCreationHelper().createFormulaEvaluator();
Expand Down Expand Up @@ -184,8 +185,10 @@ public void testEvaluateSimple() throws IOException {

wb.close();
}

@Test
public void testUpdateCachedFormulaResultFromErrorToNumber_bug46479() throws IOException {
public void testUpdateCachedFormulaResultFromErrorToNumber_bug46479() {
//noinspection ConstantConditions
Assume.assumeTrue("This test is disabled because it fails for SXSSF because " +
"handling of errors in formulas is slightly different than in XSSF, " +
"but this proved to be non-trivial to solve...",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ public final void bug50681_testAutoSize() throws IOException {
cell0.setCellValue(longValue);

// autoSize will fail if required fonts are not installed, skip this test then
Font font = wb.getFontAt(cell0.getCellStyle().getFontIndex());
Font font = wb.getFontAt(cell0.getCellStyle().getFontIndexAsInt());
Assume.assumeTrue("Cannot verify autoSizeColumn() because the necessary Fonts are not installed on this machine: " + font,
SheetUtil.canComputeColumnWidth(font));

Expand Down Expand Up @@ -745,79 +745,79 @@ public void stackoverflow26437323() throws IOException {
// First up, check that TRUE and ISLOGICAL both behave
cf.setCellFormula("TRUE()");
cf = evaluateCell(wb, cf);
assertEquals(true, cf.getBooleanCellValue());
assertTrue(cf.getBooleanCellValue());

cf.setCellFormula("ISLOGICAL(TRUE())");
cf = evaluateCell(wb, cf);
assertEquals(true, cf.getBooleanCellValue());
assertTrue(cf.getBooleanCellValue());

cf.setCellFormula("ISLOGICAL(4)");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());


// Now, check ISNUMBER / ISTEXT / ISNONTEXT
cf.setCellFormula("ISNUMBER(A1)");
cf = evaluateCell(wb, cf);
assertEquals(true, cf.getBooleanCellValue());
assertTrue(cf.getBooleanCellValue());

cf.setCellFormula("ISNUMBER(B1)");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());

cf.setCellFormula("ISNUMBER(C1)");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());

cf.setCellFormula("ISNUMBER(D1)");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());

cf.setCellFormula("ISNUMBER(E1)");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());


cf.setCellFormula("ISTEXT(A1)");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());

cf.setCellFormula("ISTEXT(B1)");
cf = evaluateCell(wb, cf);
assertEquals(true, cf.getBooleanCellValue());
assertTrue(cf.getBooleanCellValue());

cf.setCellFormula("ISTEXT(C1)");
cf = evaluateCell(wb, cf);
assertEquals(true, cf.getBooleanCellValue());
assertTrue(cf.getBooleanCellValue());

cf.setCellFormula("ISTEXT(D1)");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());

cf.setCellFormula("ISTEXT(E1)");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());


cf.setCellFormula("ISNONTEXT(A1)");
cf = evaluateCell(wb, cf);
assertEquals(true, cf.getBooleanCellValue());
assertTrue(cf.getBooleanCellValue());

cf.setCellFormula("ISNONTEXT(B1)");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());

cf.setCellFormula("ISNONTEXT(C1)");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());

cf.setCellFormula("ISNONTEXT(D1)");
cf = evaluateCell(wb, cf);
assertEquals(true, cf.getBooleanCellValue());
assertTrue(cf.getBooleanCellValue());

cf.setCellFormula("ISNONTEXT(E1)");
cf = evaluateCell(wb, cf);
assertEquals(true, cf.getBooleanCellValue()); // Blank and Null the same
assertTrue(cf.getBooleanCellValue()); // Blank and Null the same


// Next up, SEARCH on its own
Expand All @@ -841,23 +841,23 @@ public void stackoverflow26437323() throws IOException {
// Finally, bring it all together
cf.setCellFormula("ISNUMBER(SEARCH(\"am\", A1))");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());

cf.setCellFormula("ISNUMBER(SEARCH(\"am\", B1))");
cf = evaluateCell(wb, cf);
assertEquals(true, cf.getBooleanCellValue());
assertTrue(cf.getBooleanCellValue());

cf.setCellFormula("ISNUMBER(SEARCH(\"am\", C1))");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());

cf.setCellFormula("ISNUMBER(SEARCH(\"am\", D1))");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());

cf.setCellFormula("ISNUMBER(SEARCH(\"am\", E1))");
cf = evaluateCell(wb, cf);
assertEquals(false, cf.getBooleanCellValue());
assertFalse(cf.getBooleanCellValue());

wb.close();
}
Expand Down Expand Up @@ -1230,8 +1230,7 @@ public void test58113() throws IOException {
cell.setCellValue("somevalue");

value = cell.getStringCellValue();
assertTrue("can set value afterwards: " + value,
value.equals("somevalue"));
assertEquals("can set value afterwards: " + value, "somevalue", value);

// verify that the null-value is actually set even if there was some value in the cell before
cell.setCellValue((String)null);
Expand Down Expand Up @@ -1282,18 +1281,30 @@ public void bug55747() throws IOException {
// Check read ok, and re-evaluate fine
cell = row.getCell(5);
assertEquals("ab", cell.getStringCellValue());
assertEquals(CellType.FORMULA, cell.getCellType());
assertEquals("IF(A1<>\"\",MID(A1,1,2),\" \")", cell.getCellFormula());
ev.evaluateFormulaCell(cell);
assertEquals("ab", cell.getStringCellValue());
assertEquals(CellType.FORMULA, cell.getCellType());
assertEquals("IF(A1<>\"\",MID(A1,1,2),\" \")", cell.getCellFormula());

cell = row.getCell(6);
assertEquals("empty", cell.getStringCellValue());
assertEquals(CellType.FORMULA, cell.getCellType());
assertEquals("IF(B1<>\"\",MID(A1,1,2),\"empty\")", cell.getCellFormula());
ev.evaluateFormulaCell(cell);
assertEquals("empty", cell.getStringCellValue());
assertEquals(CellType.FORMULA, cell.getCellType());
assertEquals("IF(B1<>\"\",MID(A1,1,2),\"empty\")", cell.getCellFormula());

cell = row.getCell(7);
assertEquals("ab", cell.getStringCellValue());
assertEquals(CellType.FORMULA, cell.getCellType());
assertEquals("IF(A1<>\"\",IF(C1<>\"\",MID(A1,1,2),\"c1\"),\"c2\")", cell.getCellFormula());
ev.evaluateFormulaCell(cell);
assertEquals("ab", cell.getStringCellValue());
assertEquals(CellType.FORMULA, cell.getCellType());
assertEquals("IF(A1<>\"\",IF(C1<>\"\",MID(A1,1,2),\"c1\"),\"c2\")", cell.getCellFormula());
wb2.close();
}

Expand Down
Loading

0 comments on commit 2b8200f

Please sign in to comment.