<!-- Don't forget to update status.xml too! -->
<release version="3.5-beta6" date="2009-??-??">
+ <action dev="POI-DEVELOPERS" type="fix">46279 - Allow 255 arguments for excel functions in XSSF </action>
<action dev="POI-DEVELOPERS" type="fix">47028 - Fixed XSSFCell to preserve cell style when cell value is set to blank</action>
<action dev="POI-DEVELOPERS" type="fix">47026 - Avoid NPE in XSSFCell.setCellType() when workbook does not have SST</action>
<action dev="POI-DEVELOPERS" type="fix">46987 - Allow RecordFactory to handle non-zero padding at the end of the workbook stream</action>
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.5-beta6" date="2009-??-??">
+ <action dev="POI-DEVELOPERS" type="fix">46279 - Allow 255 arguments for excel functions in XSSF </action>
<action dev="POI-DEVELOPERS" type="fix">47028 - Fixed XSSFCell to preserve cell style when cell value is set to blank</action>
<action dev="POI-DEVELOPERS" type="fix">47026 - Avoid NPE in XSSFCell.setCellType() when workbook does not have SST</action>
<action dev="POI-DEVELOPERS" type="fix">46987 - Allow RecordFactory to handle non-zero padding at the end of the workbook stream</action>
*/
public static final String FUNCTION_NAME_IF = "IF";
- public static final short FUNCTION_INDEX_SUM = 4;
+ /**
+ * maxParams=30 in functionMetadata.txt means the maximum number arguments supported
+ * by the given version of Excel. Validation routines should take the actual limit (Excel 97 or 2007)
+ * from the SpreadsheetVersion enum.
+ * @see org.apache.poi.ss.formula.FormulaParser#validateNumArgs(int, FunctionMetadata)
+ */
+ public static final short FUNCTION_MAX_PARAMS = 30;
+
+ public static final short FUNCTION_INDEX_SUM = 4;
public static final short FUNCTION_INDEX_EXTERNAL = 255;
private static FunctionMetadataRegistry _instance;
import org.apache.poi.hssf.record.formula.NameXPtg;\r
import org.apache.poi.hssf.record.formula.Ptg;\r
import org.apache.poi.ss.formula.*;\r
+import org.apache.poi.ss.SpreadsheetVersion;\r
\r
/**\r
* Internal POI use only\r
return new NamePtg(_index);\r
}\r
}\r
+\r
+ public SpreadsheetVersion getSpreadsheetVersion(){\r
+ return SpreadsheetVersion.EXCEL97; \r
+ }\r
}\r
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.CellReference.NameType;
+import org.apache.poi.ss.SpreadsheetVersion;
/**
* This class parses a formula string into a List of tokens in RPN order.
}
msg += " but got " + numArgs + ".";
throw new FormulaParseException(msg);
- }
- if(numArgs > fm.getMaxParams()) {
+ }
+ //the maximum number of arguments depends on the Excel version
+ int maxArgs = fm.getMaxParams();
+ if( maxArgs == FunctionMetadataRegistry.FUNCTION_MAX_PARAMS) {
+ //_book can be omitted by test cases
+ if(_book != null) maxArgs = _book.getSpreadsheetVersion().getMaxFunctionArgs();
+ }
+
+ if(numArgs > maxArgs) {
String msg = "Too many arguments to function '" + fm.getName() + "'. ";
if(fm.hasFixedArgsLength()) {
- msg += "Expected " + fm.getMaxParams();
+ msg += "Expected " + maxArgs;
} else {
- msg += "At most " + fm.getMaxParams() + " were expected";
+ msg += "At most " + maxArgs + " were expected";
}
msg += " but got " + numArgs + ".";
throw new FormulaParseException(msg);
package org.apache.poi.ss.formula;\r
\r
import org.apache.poi.hssf.record.formula.NameXPtg;\r
+import org.apache.poi.ss.SpreadsheetVersion;\r
\r
/**\r
* Abstracts a workbook for the purpose of formula parsing.<br/>\r
* @param sheetName a name of a sheet in that workbook\r
*/\r
int getExternalSheetIndex(String workbookName, String sheetName);\r
+\r
+ /**\r
+ * Returns an enum holding spreadhseet properties specific to an Excel version (\r
+ * max column and row numbers, max arguments to a function, etc.)\r
+ */\r
+ SpreadsheetVersion getSpreadsheetVersion();\r
+\r
}\r
}
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
- try {
- Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, wb.getSheetIndex(getSheet()));
- } catch (RuntimeException e) {
- if (e.getClass().getName().startsWith(FormulaParser.class.getName())) {
- throw new IllegalArgumentException("Unparsable formula '" + formula + "'", e);
- }
- throw e;
- }
+ //validate through the FormulaParser
+ FormulaParser.parse(formula, fpb, FormulaType.CELL, wb.getSheetIndex(getSheet()));
CTCellFormula f = CTCellFormula.Factory.newInstance();
f.setStringValue(formula);
import org.apache.poi.hssf.record.formula.NameXPtg;\r
import org.apache.poi.hssf.record.formula.Ptg;\r
import org.apache.poi.ss.formula.*;\r
+import org.apache.poi.ss.SpreadsheetVersion;\r
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;\r
\r
/**\r
return new NamePtg(_index);\r
}\r
}\r
+ \r
+ public SpreadsheetVersion getSpreadsheetVersion(){\r
+ return SpreadsheetVersion.EXCEL2007;\r
+ }\r
}\r
public void setRefersToFormula(String formulaText) {
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(workbook);
- try {
- FormulaParser.parse(formulaText, fpb, FormulaType.NAMEDRANGE, getSheetIndex());
- } catch (RuntimeException e) {
- if (e.getClass().getName().startsWith(FormulaParser.class.getName())) {
- throw new IllegalArgumentException("Unparsable formula '" + formulaText + "'", e);
- }
- throw e;
- }
+ //validate through the FormulaParser
+ FormulaParser.parse(formulaText, fpb, FormulaType.NAMEDRANGE, getSheetIndex());
+
ctName.setStringValue(formulaText);
}
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.ss.formula.FormulaParser;
-import org.apache.poi.ss.formula.FormulaType;
-import org.apache.poi.ss.formula.FormulaRenderer;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.xssf.model.CalculationChain;
-import org.apache.poi.hssf.record.formula.Ptg;
-import org.apache.poi.hssf.record.formula.FormulaShifter;
-import org.apache.poi.hssf.record.SharedFormulaRecord;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula;
/**
* High level representation of a row of a spreadsheet.
import javax.xml.namespace.QName;
import org.apache.poi.hssf.util.PaneInformation;
-import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.FormulaShifter;
-import org.apache.poi.hssf.record.SharedFormulaRecord;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.ss.util.AreaReference;
-import org.apache.poi.ss.formula.FormulaParser;
-import org.apache.poi.ss.formula.FormulaType;
-import org.apache.poi.ss.formula.FormulaRenderer;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.xssf.model.CommentsTable;
-import org.apache.poi.xssf.model.CalculationChain;
import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
import org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter;
import org.apache.poi.POIXMLDocumentPart;
}\r
\r
public SpreadsheetVersion getSpreadsheetVersion(){\r
- return SpreadsheetVersion.EXCEL2007;\r
+ return SpreadsheetVersion.EXCEL97;\r
}\r
\r
private HSSFITestDataProvider(){}\r
import junit.framework.TestCase;\r
import junit.framework.AssertionFailedError;\r
import org.apache.poi.ss.ITestDataProvider;\r
+import org.apache.poi.ss.SpreadsheetVersion;\r
import org.apache.poi.ss.util.CellRangeAddress;\r
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;\r
\r
/**\r
* A base class for bugzilla issues that can be described in terms of common ss interfaces.\r
\r
assertEquals(d, (311+312+321+322), 0.0000001);\r
}\r
+\r
+ public void testMaxFunctionArguments_bug46729(){\r
+ String[] func = {"COUNT", "AVERAGE", "MAX", "MIN", "OR", "SUBTOTAL", "SKEW"};\r
+\r
+ SpreadsheetVersion ssVersion = getTestDataProvider().getSpreadsheetVersion();\r
+ Workbook wb = getTestDataProvider().createWorkbook();\r
+ Cell cell = wb.createSheet().createRow(0).createCell(0);\r
+\r
+ String fmla;\r
+ for (String name : func) {\r
+\r
+ fmla = createFunction(name, 5);\r
+ cell.setCellFormula(fmla);\r
+\r
+ fmla = createFunction(name, ssVersion.getMaxFunctionArgs());\r
+ cell.setCellFormula(fmla);\r
+\r
+ try {\r
+ fmla = createFunction(name, ssVersion.getMaxFunctionArgs() + 1);\r
+ cell.setCellFormula(fmla);\r
+ fail("Expected FormulaParseException");\r
+ } catch (RuntimeException e){\r
+ assertTrue(e.getMessage().startsWith("Too many arguments to function '"+name+"'"));\r
+ }\r
+ }\r
+ }\r
+\r
+ private String createFunction(String name, int maxArgs){\r
+ StringBuffer fmla = new StringBuffer();\r
+ fmla.append(name);\r
+ fmla.append("(");\r
+ for(int i=0; i < maxArgs; i++){\r
+ if(i > 0) fmla.append(',');\r
+ fmla.append("A1");\r
+ }\r
+ fmla.append(")");\r
+ return fmla.toString();\r
+ }\r
}
\ No newline at end of file