View | Details | Raw Unified | Return to bug 43476
Collapse All | Expand All

(-)src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java (-14 / +64 lines)
Lines 21-30 Link Here
21
package org.apache.poi.hssf.usermodel;
21
package org.apache.poi.hssf.usermodel;
22
22
23
import java.lang.reflect.Constructor;
23
import java.lang.reflect.Constructor;
24
import java.util.Comparator;
24
import java.util.HashMap;
25
import java.util.HashMap;
26
import java.util.HashSet;
25
import java.util.List;
27
import java.util.List;
26
import java.util.Map;
28
import java.util.Map;
29
import java.util.Set;
27
import java.util.Stack;
30
import java.util.Stack;
31
import java.util.TreeSet;
28
32
29
import org.apache.poi.hssf.model.FormulaParser;
33
import org.apache.poi.hssf.model.FormulaParser;
30
import org.apache.poi.hssf.model.Workbook;
34
import org.apache.poi.hssf.model.Workbook;
Lines 152-159 Link Here
152
        OPERATION_EVALS_MAP.put(UnaryPlusPtg.class, UnaryPlusEval.class);
156
        OPERATION_EVALS_MAP.put(UnaryPlusPtg.class, UnaryPlusEval.class);
153
157
154
    }
158
    }
155
156
    
159
    
160
    /**
161
     * @author Pavel Krupets (pkrupets at palmtreebusiness dot com)
162
     */
163
    private static final class VisitedCellsSet extends HashSet {
164
        private static final long serialVersionUID = 1L;
165
    }
166
    
157
    protected HSSFRow row;
167
    protected HSSFRow row;
158
    protected HSSFSheet sheet;
168
    protected HSSFSheet sheet;
159
    protected HSSFWorkbook workbook;
169
    protected HSSFWorkbook workbook;
Lines 192-198 Link Here
192
                retval.setErrorValue(cell.getErrorCellValue());
202
                retval.setErrorValue(cell.getErrorCellValue());
193
                break;
203
                break;
194
            case HSSFCell.CELL_TYPE_FORMULA:
204
            case HSSFCell.CELL_TYPE_FORMULA:
195
                retval = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook));
205
                retval = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook, null));
196
                break;
206
                break;
197
            case HSSFCell.CELL_TYPE_NUMERIC:
207
            case HSSFCell.CELL_TYPE_NUMERIC:
198
                retval = new CellValue(HSSFCell.CELL_TYPE_NUMERIC);
208
                retval = new CellValue(HSSFCell.CELL_TYPE_NUMERIC);
Lines 223-229 Link Here
223
        if (cell != null) {
233
        if (cell != null) {
224
            switch (cell.getCellType()) {
234
            switch (cell.getCellType()) {
225
            case HSSFCell.CELL_TYPE_FORMULA:
235
            case HSSFCell.CELL_TYPE_FORMULA:
226
                CellValue cv = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook));
236
                CellValue cv = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook, null));
227
                switch (cv.getCellType()) {
237
                switch (cv.getCellType()) {
228
                case HSSFCell.CELL_TYPE_BOOLEAN:
238
                case HSSFCell.CELL_TYPE_BOOLEAN:
229
                	cell.setCellType(HSSFCell.CELL_TYPE_BOOLEAN);
239
                	cell.setCellType(HSSFCell.CELL_TYPE_BOOLEAN);
Lines 294-300 Link Here
294
     * @param sheet
304
     * @param sheet
295
     * @param workbook
305
     * @param workbook
296
     */
306
     */
297
    protected static ValueEval internalEvaluate(HSSFCell srcCell, HSSFRow srcRow, HSSFSheet sheet, HSSFWorkbook workbook) {
307
    protected static ValueEval internalEvaluate(HSSFCell srcCell, HSSFRow srcRow, HSSFSheet sheet, HSSFWorkbook workbook, Set/*<HSSFCell>*/ visitedCells) {
298
        int srcRowNum = srcRow.getRowNum();
308
        int srcRowNum = srcRow.getRowNum();
299
        short srcColNum = srcCell.getCellNum();
309
        short srcColNum = srcCell.getCellNum();
300
        
310
        
Lines 340-346 Link Here
340
                short rownum = ptg.getRow();
350
                short rownum = ptg.getRow();
341
                HSSFRow row = sheet.getRow(rownum);
351
                HSSFRow row = sheet.getRow(rownum);
342
                HSSFCell cell = (row != null) ? row.getCell(colnum) : null;
352
                HSSFCell cell = (row != null) ? row.getCell(colnum) : null;
343
                pushRef2DEval(ptg, stack, cell, row, sheet, workbook);
353
                
354
                if (visitedCells != null && visitedCells.contains(cell)) {
355
                    throw new RuntimeException("Fatal Error: circular dependency was found in '" + 
356
                                               srcCell.getCellFormula() + "' formula!");
357
                }
358
                
359
                Set vCells = visitedCells == null ? new VisitedCellsSet() : visitedCells;
360
                vCells.add(cell);
361
                
362
                pushRef2DEval(ptg, stack, cell, row, sheet, workbook, vCells);
344
            }
363
            }
345
            else if (token instanceof Ref3DPtg) {
364
            else if (token instanceof Ref3DPtg) {
346
                Ref3DPtg ptg = (Ref3DPtg) token;
365
                Ref3DPtg ptg = (Ref3DPtg) token;
Lines 350-356 Link Here
350
                HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(ptg.getExternSheetIndex()));
369
                HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(ptg.getExternSheetIndex()));
351
                HSSFRow row = xsheet.getRow(rownum);
370
                HSSFRow row = xsheet.getRow(rownum);
352
                HSSFCell cell = (row != null) ? row.getCell(colnum) : null;
371
                HSSFCell cell = (row != null) ? row.getCell(colnum) : null;
353
                pushRef3DEval(ptg, stack, cell, row, xsheet, workbook);
372
                
373
                if (visitedCells != null && visitedCells.contains(cell)) {
374
                    throw new RuntimeException("Fatal Error: circular dependency was found in '" + 
375
                                               srcCell.getCellFormula() + "' formula!");
376
                }
377
                
378
                Set vCells = visitedCells == null ? new VisitedCellsSet() : visitedCells;
379
                vCells.add(cell);
380
                
381
                pushRef3DEval(ptg, stack, cell, row, xsheet, workbook, vCells);
354
            }
382
            }
355
            else if (token instanceof AreaPtg) {
383
            else if (token instanceof AreaPtg) {
356
                AreaPtg ap = (AreaPtg) token;
384
                AreaPtg ap = (AreaPtg) token;
Lines 362-369 Link Here
362
                for (short x = row0; sheet != null && x < row1 + 1; x++) {
390
                for (short x = row0; sheet != null && x < row1 + 1; x++) {
363
                    HSSFRow row = sheet.getRow(x);
391
                    HSSFRow row = sheet.getRow(x);
364
                    for (short y = col0; row != null && y < col1 + 1; y++) {
392
                    for (short y = col0; row != null && y < col1 + 1; y++) {
393
                        HSSFCell cell = row.getCell(y);
394
                        
395
                        if (visitedCells != null && visitedCells.contains(cell)) {
396
                            throw new RuntimeException("Fatal Error: circular dependency was found in '" + 
397
                                                       srcCell.getCellFormula() + "' formula!");
398
                        }
399
                        
400
                        Set vCells = visitedCells == null ? new VisitedCellsSet() : visitedCells;
401
                        vCells.add(cell);
402
                        
365
                        values[(x - row0) * (col1 - col0 + 1) + (y - col0)] = 
403
                        values[(x - row0) * (col1 - col0 + 1) + (y - col0)] = 
366
                            getEvalForCell(row.getCell(y), row, sheet, workbook);
404
                            getEvalForCell(cell, row, sheet, workbook, vCells);
367
                    }
405
                    }
368
                }
406
                }
369
                AreaEval ae = new Area2DEval(ap, values);
407
                AreaEval ae = new Area2DEval(ap, values);
Lines 381-388 Link Here
381
                for (short x = row0; xsheet != null && x < row1 + 1; x++) {
419
                for (short x = row0; xsheet != null && x < row1 + 1; x++) {
382
                    HSSFRow row = xsheet.getRow(x);
420
                    HSSFRow row = xsheet.getRow(x);
383
                    for (short y = col0; row != null && y < col1 + 1; y++) {
421
                    for (short y = col0; row != null && y < col1 + 1; y++) {
422
                        HSSFCell cell = row.getCell(y);
423
                        
424
                        if (visitedCells != null && visitedCells.contains(cell)) {
425
                            throw new RuntimeException("Fatal Error: circular dependency was found in '" + 
426
                                                       srcCell.getCellFormula() + "' formula!");
427
                        }
428
                        
429
                        Set vCells = visitedCells == null ? new VisitedCellsSet() : visitedCells;
430
                        vCells.add(cell);
431
                        
384
                        values[(x - row0) * (col1 - col0 + 1) + (y - col0)] = 
432
                        values[(x - row0) * (col1 - col0 + 1) + (y - col0)] = 
385
                            getEvalForCell(row.getCell(y), row, xsheet, workbook);
433
                            getEvalForCell(cell, row, xsheet, workbook, vCells);
386
                    }
434
                    }
387
                }
435
                }
388
                AreaEval ae = new Area3DEval(a3dp, values);
436
                AreaEval ae = new Area3DEval(a3dp, values);
Lines 481-488 Link Here
481
     * @param cell
529
     * @param cell
482
     * @param sheet
530
     * @param sheet
483
     * @param workbook
531
     * @param workbook
532
     * @param object 
484
     */
533
     */
485
    protected static ValueEval getEvalForCell(HSSFCell cell, HSSFRow row, HSSFSheet sheet, HSSFWorkbook workbook) {
534
    protected static ValueEval getEvalForCell(HSSFCell cell, HSSFRow row, HSSFSheet sheet, HSSFWorkbook workbook, Set visitedCells) {
486
        ValueEval retval = BlankEval.INSTANCE;
535
        ValueEval retval = BlankEval.INSTANCE;
487
        if (cell != null) {
536
        if (cell != null) {
488
            switch (cell.getCellType()) {
537
            switch (cell.getCellType()) {
Lines 493-499 Link Here
493
                retval = new StringEval(cell.getRichStringCellValue().getString());
542
                retval = new StringEval(cell.getRichStringCellValue().getString());
494
                break;
543
                break;
495
            case HSSFCell.CELL_TYPE_FORMULA:
544
            case HSSFCell.CELL_TYPE_FORMULA:
496
                retval = internalEvaluate(cell, row, sheet, workbook);
545
                retval = internalEvaluate(cell, row, sheet, workbook, visitedCells);
497
                break;
546
                break;
498
            case HSSFCell.CELL_TYPE_BOOLEAN:
547
            case HSSFCell.CELL_TYPE_BOOLEAN:
499
                retval = cell.getBooleanCellValue() ? BoolEval.TRUE : BoolEval.FALSE;
548
                retval = cell.getBooleanCellValue() ? BoolEval.TRUE : BoolEval.FALSE;
Lines 517-525 Link Here
517
     * @param cell
566
     * @param cell
518
     * @param sheet
567
     * @param sheet
519
     * @param workbook
568
     * @param workbook
569
     * @param visitedCells 
520
     */
570
     */
521
    protected static void pushRef2DEval(ReferencePtg ptg, Stack stack, 
571
    protected static void pushRef2DEval(ReferencePtg ptg, Stack stack, 
522
            HSSFCell cell, HSSFRow row, HSSFSheet sheet, HSSFWorkbook workbook) {
572
            HSSFCell cell, HSSFRow row, HSSFSheet sheet, HSSFWorkbook workbook, Set visitedCells) {
523
        if (cell != null)
573
        if (cell != null)
524
            switch (cell.getCellType()) {
574
            switch (cell.getCellType()) {
525
            case HSSFCell.CELL_TYPE_NUMERIC:
575
            case HSSFCell.CELL_TYPE_NUMERIC:
Lines 529-535 Link Here
529
                stack.push(new Ref2DEval(ptg, new StringEval(cell.getRichStringCellValue().getString()), false));
579
                stack.push(new Ref2DEval(ptg, new StringEval(cell.getRichStringCellValue().getString()), false));
530
                break;
580
                break;
531
            case HSSFCell.CELL_TYPE_FORMULA:
581
            case HSSFCell.CELL_TYPE_FORMULA:
532
                stack.push(new Ref2DEval(ptg, internalEvaluate(cell, row, sheet, workbook), true));
582
                stack.push(new Ref2DEval(ptg, internalEvaluate(cell, row, sheet, workbook, visitedCells), true));
533
                break;
583
                break;
534
            case HSSFCell.CELL_TYPE_BOOLEAN:
584
            case HSSFCell.CELL_TYPE_BOOLEAN:
535
                stack.push(new Ref2DEval(ptg, cell.getBooleanCellValue() ? BoolEval.TRUE : BoolEval.FALSE, false));
585
                stack.push(new Ref2DEval(ptg, cell.getBooleanCellValue() ? BoolEval.TRUE : BoolEval.FALSE, false));
Lines 556-562 Link Here
556
     * @param workbook
606
     * @param workbook
557
     */
607
     */
558
    protected static void pushRef3DEval(Ref3DPtg ptg, Stack stack, HSSFCell cell, 
608
    protected static void pushRef3DEval(Ref3DPtg ptg, Stack stack, HSSFCell cell, 
559
            HSSFRow row, HSSFSheet sheet, HSSFWorkbook workbook) {
609
            HSSFRow row, HSSFSheet sheet, HSSFWorkbook workbook, Set visitedCells) {
560
        if (cell != null)
610
        if (cell != null)
561
            switch (cell.getCellType()) {
611
            switch (cell.getCellType()) {
562
            case HSSFCell.CELL_TYPE_NUMERIC:
612
            case HSSFCell.CELL_TYPE_NUMERIC:
Lines 566-572 Link Here
566
                stack.push(new Ref3DEval(ptg, new StringEval(cell.getRichStringCellValue().getString()), false));
616
                stack.push(new Ref3DEval(ptg, new StringEval(cell.getRichStringCellValue().getString()), false));
567
                break;
617
                break;
568
            case HSSFCell.CELL_TYPE_FORMULA:
618
            case HSSFCell.CELL_TYPE_FORMULA:
569
                stack.push(new Ref3DEval(ptg, internalEvaluate(cell, row, sheet, workbook), true));
619
                stack.push(new Ref3DEval(ptg, internalEvaluate(cell, row, sheet, workbook, visitedCells), true));
570
                break;
620
                break;
571
            case HSSFCell.CELL_TYPE_BOOLEAN:
621
            case HSSFCell.CELL_TYPE_BOOLEAN:
572
                stack.push(new Ref3DEval(ptg, cell.getBooleanCellValue() ? BoolEval.TRUE : BoolEval.FALSE, false));
622
                stack.push(new Ref3DEval(ptg, cell.getBooleanCellValue() ? BoolEval.TRUE : BoolEval.FALSE, false));
(-)src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestCircularDependencies.java (+103 lines)
Line 0 Link Here
1
/*
2
 * Created on Sep 25, 2007
3
 * 
4
 * The Copyright statements and Licenses for the commons application may be
5
 * found in the file LICENSE.txt
6
 */
7
8
package org.apache.poi.hssf.usermodel;
9
10
import junit.framework.TestCase;
11
12
/**
13
 * @author Pavel Krupets (pkrupets at palmtreebusiness dot com)
14
 */
15
public class TestCircularDependencies extends TestCase {
16
    /**
17
     * @see junit.framework.TestCase#setUp()
18
     */
19
    protected void setUp() throws Exception {
20
        super.setUp();
21
        
22
        HSSFWorkbook wb = new HSSFWorkbook();
23
        HSSFSheet sheet = wb.createSheet("new sheet");
24
        HSSFRow row1 = sheet.createRow((short) 0);
25
        
26
        this.cell11 = row1.createCell((short) 0);
27
        this.cell12 = row1.createCell((short) 1);
28
        this.cell13 = row1.createCell((short) 2);
29
        this.cell14 = row1.createCell((short) 3);
30
        
31
        this.evaluator = new HSSFFormulaEvaluator(sheet, wb);
32
        this.evaluator.setCurrentRow(row1);
33
    }
34
    
35
    public void testSimpleRef() throws Exception {
36
        this.cell11.setCellFormula("B1");
37
        this.cell12.setCellFormula("A1");
38
        
39
        try {
40
            this.evaluator.evaluate(this.cell11);
41
            fail();
42
        } catch (RuntimeException e) {
43
            e.printStackTrace();
44
        }
45
    }
46
    
47
    public void testComplexRef() throws Exception {
48
        this.cell11.setCellFormula("B1 + C1");
49
        this.cell12.setCellValue(10.0);
50
        this.cell13.setCellFormula("A1");
51
        
52
        try {
53
            this.evaluator.evaluate(this.cell11);
54
            fail();
55
        } catch (RuntimeException e) {
56
            e.printStackTrace();
57
        }
58
        
59
        this.cell11.setCellFormula("B1 + C1");
60
        this.cell12.setCellFormula("D1");
61
        this.cell13.setCellFormula("B1");
62
        this.cell14.setCellFormula("D1");
63
        
64
        try {
65
            this.evaluator.evaluate(this.cell11);
66
            fail();
67
        } catch (RuntimeException e) {
68
            e.printStackTrace();
69
        }
70
    }
71
    
72
    public void testSimpleArea() throws Exception {
73
        this.cell11.setCellFormula("SUM(A1:B1)");
74
        this.cell12.setCellFormula("10");
75
        
76
        try {
77
            this.evaluator.evaluate(this.cell11);
78
            fail();
79
        } catch (RuntimeException e) {
80
            e.printStackTrace();
81
        }
82
    }
83
    
84
    public void testComplexArea() throws Exception {
85
        this.cell11.setCellFormula("SUM(B1:D1)");
86
        this.cell12.setCellValue(10.0);
87
        this.cell13.setCellFormula("SUM(A1:B1)");
88
        this.cell14.setCellValue(12.2);
89
        
90
        try {
91
            this.evaluator.evaluate(this.cell11);
92
            fail();
93
        } catch (RuntimeException e) {
94
            e.printStackTrace();
95
        }
96
    }
97
    
98
    private HSSFCell cell11;
99
    private HSSFCell cell12;
100
    private HSSFCell cell13;
101
    private HSSFCell cell14;
102
    private HSSFFormulaEvaluator evaluator;
103
}

Return to bug 43476