This is an automated email from the ASF dual-hosted git repository. jimjag pushed a commit to branch openformula in repository https://gitbox.apache.org/repos/asf/openoffice.git
commit 8b480056113962bde68c71eaf956814a63b9ed7c Author: Jim Jagielski <[email protected]> AuthorDate: Fri Nov 13 10:17:12 2026 -0500 sc: do not count rows without content as records in DCOUNT and DCOUNTA Without a field, blank rows in the database range matched "=" and "<>x". --- main/sc/source/core/data/dociter.cxx | 27 ++++++++++++++++++++++++--- test/odf-validate/calcval-cases14.tsv | 5 +++++ test/odf-validate/calcval.py | 2 ++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/main/sc/source/core/data/dociter.cxx b/main/sc/source/core/data/dociter.cxx index 98d866e94f..7f23ae0ecf 100644 --- a/main/sc/source/core/data/dociter.cxx +++ b/main/sc/source/core/data/dociter.cxx @@ -688,10 +688,28 @@ SCSIZE ScDBQueryDataIterator::DataAccessInternal::countRecords() // getCurrent() only visits rows that have a cell in column nCol. ScQueryParam aParam(*mpParam); SCROW nFirstRow = mpParam->bHasHeader ? mpParam->nRow1 + 1 : mpParam->nRow1; + SCROW nLastRow = mpParam->nRow2; + if (nFirstRow > nLastRow) + return 0; + // A row without any content in the database columns is not a record. + ::std::vector<bool> aHasContent(nLastRow - nFirstRow + 1, false); + for (SCCOL nC = mpParam->nCol1; nC <= mpParam->nCol2; ++nC) + { + SCSIZE nCellCount = mpDoc->GetCellCount(nTab, nC); + for (SCSIZE i = ScDBQueryDataIterator::SearchColEntryIndex(*mpDoc, nTab, nFirstRow, nC); i < nCellCount; ++i) + { + SCROW nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nC, i); + if (nThisRow > nLastRow) + break; + ScBaseCell* pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nC, i); + if (nThisRow >= nFirstRow && pCell && pCell->GetCellType() != CELLTYPE_NOTE) + aHasContent[nThisRow - nFirstRow] = true; + } + } SCSIZE nCount = 0; - for (SCROW nR = nFirstRow; nR <= mpParam->nRow2; ++nR) + for (SCROW nR = nFirstRow; nR <= nLastRow; ++nR) { - if (ScDBQueryDataIterator::IsQueryValid(*mpDoc, aParam, nTab, nR, NULL)) + if (aHasContent[nR - nFirstRow] && ScDBQueryDataIterator::IsQueryValid(*mpDoc, aParam, nTab, nR, NULL)) ++nCount; } return nCount; @@ -758,7 +776,10 @@ SCSIZE ScDBQueryDataIterator::DataAccessMatrix::countRecords() SCSIZE nCount = 0; for (SCROW nR = mpParam->bHasHeader ? 1 : 0; nR < mnRows; ++nR) { - if (isValidQuery(nR, rMat)) + bool bHasContent = false; + for (SCCOL nC = 0; nC < mnCols && !bHasContent; ++nC) + bHasContent = !rMat.IsEmpty(nC, nR); + if (bHasContent && isValidQuery(nR, rMat)) ++nCount; } return nCount; diff --git a/test/odf-validate/calcval-cases14.tsv b/test/odf-validate/calcval-cases14.tsv index 9266fb4e6d..918bfea06e 100644 --- a/test/odf-validate/calcval-cases14.tsv +++ b/test/odf-validate/calcval-cases14.tsv @@ -181,6 +181,11 @@ DB.DCOUNT.nf.inline =DCOUNT({"Name";"Age";"Score"|"A";20;5|"B";30;"n/a"|"C";40;1 DB.DCOUNTA.nf.inline =DCOUNTA({"Name";"Age";"Score"|"A";20;5|"B";30;"n/a"|"C";40;15|"D";50;"x"|"E";60;25};;Y1:Y2) cell 1 6.9.4 Field omitted, inline array as the database: Name A matches one record DB.DCOUNT.nf.nocrit =DCOUNT(AX11:AY14;;AZ11:AZ12) cell - Field omitted, criteria cell empty (AZ12). 4.11.11 reads an empty criterion as 0 (no match); AOO ignores empty criteria (known deviation, see DCOUNT.emptycrit). Record only DB.DCOUNT.f.nocrit =DCOUNT(AX11:AY14;"V";AZ11:AZ12) cell - Same as DB.DCOUNT.nf.nocrit with field V. Record only +DB.DCOUNT.nf.ne.blank =DCOUNT(R1:T10;;AP1:AP2) cell 4 6.9.3 Field omitted; R1:T10 has four blank rows below the data; a row with no content is not a record: B,C,D,E +DB.DCOUNT.nf.eq.blank =DCOUNT(R1:T10;;AQ1:AQ2) cell 1 6.9.3 Field omitted; Score "=" matches D, not the blank rows +DB.DCOUNTA.nf.ne.blank =DCOUNTA(R1:T10;;AP1:AP2) cell 4 6.9.4 Field omitted; same record count with blank rows +DB.DCOUNT.nf.ne.col =DCOUNT(R1:T1048576;;AP1:AP2) cell 4 6.9.3 Field omitted; whole-column database range, the blank rows below the data are not records +DB.DCOUNT.nf.eq.gap =DCOUNT(BB1:BC5;;BD1:BD2) cell 1 6.9.3 Field omitted; K "="; row 3 has K empty and V 2 (a record), row 4 is blank (not a record) BITAND.3params =BITAND(6;3;1) cell #ERR 6.6.2 BITAND exactly 2 params enforced # OpenFormula Small Group: basic limits, syntax, operators and conversions (ODF 1.4 Part 4 sections 3.7, 5, 6.3, 6.4). diff --git a/test/odf-validate/calcval.py b/test/odf-validate/calcval.py index 64e7439416..dc322a1e2e 100644 --- a/test/odf-validate/calcval.py +++ b/test/odf-validate/calcval.py @@ -150,6 +150,8 @@ def setup_data(doc): put("AV1", [["Score", "Age"], ["25", None], [None, "50"]]) put("AX11", [["K", "V"], ["a", 1], ["b", 2], ["c", 3]]) put("AZ11", [["K"], [None]]) + put("BB1", [["K", "V"], ["a", 1], [None, 2], [None, None], ["c", 3]]) + put("BD1", [["K"], ["="]]) return sh
