diff --git a/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java index 887e23ae11d..9f66adffcc6 100644 --- a/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java +++ b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java @@ -24,6 +24,10 @@ Licensed to the Apache Software Foundation (ASF) under one or more import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; +import java.text.DecimalFormat; import java.util.HashMap; import java.util.Map; import java.util.function.Function; @@ -32,6 +36,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more import org.apache.poi.ss.usermodel.BaseTestFormulaEvaluator; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellValue; +import org.apache.poi.ss.usermodel.DataFormatter; import org.apache.poi.ss.usermodel.FormulaEvaluator; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; @@ -444,4 +449,17 @@ void testBug62834() throws IOException { assertEquals("another value", value.getStringCellValue(), "wrong value A5"); } } + + @Test + void testBug63934() throws IOException { + try (Workbook wb = XSSFTestDataSamples.openSampleWorkbook("63934.xlsx")) { + + final Cell cell = wb.getSheetAt(0).getRow(1).getCell(1); + assertNotNull(cell); + + final FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator(); + final CellValue value = evaluator.evaluate(cell); + assertEquals("Male", value.getStringValue()); + } + } } diff --git a/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaParser.java b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaParser.java index fc4a9c60321..b312ab70f9a 100644 --- a/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaParser.java +++ b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaParser.java @@ -655,6 +655,7 @@ The following cases are tested (copied from FormulaParser.parseStructuredReferen 16 Table1[[#Headers],[#Data],[col2]] 17 Table1[[#This Row], [col1]] 18 Table1[ [col1]:[col2] ] + 19 Table1[] */ final String tbl = "\\_Prime.1"; @@ -697,7 +698,7 @@ The following cases are tested (copied from FormulaParser.parseStructuredReferen assertEquals(1, ptgs.length); assertEquals("Table!A1:C7", ptgs[0].toFormulaString(), "Table1[#All]"); - ////// Case 5: Evaluate "Table1[#Data]" (excludes Header and Data rows) //////// + ////// Case 5: Evaluate "Table1[#Data]" (excludes Header and Total rows) //////// ptgs = parse(fpb, tbl+"[#Data]"); assertEquals(1, ptgs.length); assertEquals("Table!A2:C7", ptgs[0].toFormulaString(), "Table1[#Data]"); @@ -790,6 +791,13 @@ The following cases are tested (copied from FormulaParser.parseStructuredReferen assertEquals(1, ptgs.length); assertEquals("Table!B2:C7", ptgs[0].toFormulaString(), "Table1[[col]:[col2]]"); + ////// Case 19: Evaluate "Table1[]" //////// + // Excludes Header and Total rows, equivalent to Table1[#Data] (see case 5). + // This is the only case where [] is allowed. + ptgs = parse(fpb, tbl+"[]"); + assertEquals(1, ptgs.length); + assertEquals("Table!A2:C7", ptgs[0].toFormulaString(), "Table1[]"); + wb.close(); } } diff --git a/poi/src/main/java/org/apache/poi/ss/formula/FormulaParser.java b/poi/src/main/java/org/apache/poi/ss/formula/FormulaParser.java index 28d13bfbc8c..3203120f523 100644 --- a/poi/src/main/java/org/apache/poi/ss/formula/FormulaParser.java +++ b/poi/src/main/java/org/apache/poi/ss/formula/FormulaParser.java @@ -595,6 +595,7 @@ private ParseNode parseRangeable() { * Parses a structured reference, returns it as area reference. * Examples: *
+ * Table1[] * Table1[col] * Table1[[#Totals],[col]] * Table1[#Totals] @@ -637,6 +638,29 @@ private ParseNode parseStructuredReference(String tableName) { int savePtr0 = _pointer; nextChar(); + // Special case: Table1[] is equivalent to Table1[#Data] + if (look == ']') { + + // Consume the ']' character + nextChar(); + + // Skip header and total rows if available + int actualStartRow = startRow; + if (tbl.getHeaderRowCount() > 0) { + actualStartRow = startRow + 1; + } + int actualEndRow = endRow; + if (tbl.getTotalsRowCount() > 0) { + actualEndRow = endRow - 1; + } + + final CellReference topLeft = new CellReference(actualStartRow, startCol); + final CellReference bottomRight = new CellReference(actualEndRow, endCol); + final SheetIdentifier sheetIden = new SheetIdentifier( null, new NameIdentifier(sheetName, true)); + final Ptg ptg = _book.get3DReferencePtg(new AreaReference(topLeft, bottomRight, _ssVersion), sheetIden); + return new ParseNode(ptg); + } + boolean isTotalsSpec = false; boolean isThisRowSpec = false; boolean isDataSpec = false; diff --git a/test-data/spreadsheet/63934.xlsx b/test-data/spreadsheet/63934.xlsx new file mode 100644 index 00000000000..d8aa43c4a63 Binary files /dev/null and b/test-data/spreadsheet/63934.xlsx differ