tdf#50916 Makes numbers of columns dynamic.

With this commit we are making numbers of columns
dynamic, but the number of maximum supported
columns will be the same (1024).
Such approach will allow us to check issues
(eg. performance, LO format etc.), and improve it.

Increasing number of maximum columns, will be done
in separate commit.

Change-Id: Ibac4101e9ffc05e3548eca1c198f6319ac7ff9aa
Reviewed-on: https://gerrit.libreoffice.org/44802
Tested-by: Jenkins
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx
index 766135d..e04e0d5 100644
--- a/sc/inc/address.hxx
+++ b/sc/inc/address.hxx
@@ -67,6 +67,7 @@
// Count values
const SCROW       MAXROWCOUNT    = MAXROWCOUNT_DEFINE;
const SCCOL       MAXCOLCOUNT    = MAXCOLCOUNT_DEFINE;
const SCCOL       INITIALCOLCOUNT = 64;
/// limiting to 10000 for now, problem with 32 bit builds for now
const SCTAB       MAXTABCOUNT    = 10000;
const SCCOLROW    MAXCOLROWCOUNT = MAXROWCOUNT;
diff --git a/sc/inc/colcontainer.hxx b/sc/inc/colcontainer.hxx
index e6dbf0e..c7b72e0 100644
--- a/sc/inc/colcontainer.hxx
+++ b/sc/inc/colcontainer.hxx
@@ -28,10 +28,9 @@

class ScColContainer
{
    typedef std::vector<std::unique_ptr<ScColumn>> ScColumnVector;
    ScColumnVector    aCols;

public:
    typedef std::vector<std::unique_ptr<ScColumn>> ScColumnVector;

    ScColContainer( const size_t nSize );
    ~ScColContainer() COVERITY_NOEXCEPT_FALSE;

@@ -73,6 +72,9 @@

    ScColumnVector::const_iterator begin() const { return aCols.begin(); }
    ScColumnVector::const_iterator end() const { return aCols.end(); }

private:
    ScColumnVector    aCols;
};


diff --git a/sc/inc/dociter.hxx b/sc/inc/dociter.hxx
index 5bb9570..8604abc 100644
--- a/sc/inc/dociter.hxx
+++ b/sc/inc/dociter.hxx
@@ -370,7 +370,7 @@
private:
    ScDocument*     pDoc;
    SCTAB           nTab;
    SCCOL const     nEndCol;
    SCCOL           nEndCol;
    SCROW const     nStartRow;
    SCROW const     nEndRow;
    SCCOL           nCol;
@@ -391,7 +391,7 @@
private:
    ScDocument*     pDoc;
    SCTAB           nTab;
    SCCOL const     nEndCol;
    SCCOL           nEndCol;
    SCROW const     nStartRow;
    SCROW const     nEndRow;
    SCCOL           nIterStartCol;
@@ -423,7 +423,7 @@
    ScDocument*     pDoc;
    SCTAB           mnTab;
    SCCOL const           nStartCol;
    SCCOL const           nEndCol;
    SCCOL                 nEndCol;
    SCROW const           nStartRow;
    SCROW const           nEndRow;
    SCCOL           mnCol;
@@ -482,7 +482,7 @@
    SCTAB                   nTab;
    SCCOL const             nStartCol;
    SCROW const             nStartRow;
    SCCOL const             nEndCol;
    SCCOL                   nEndCol;
    SCROW const             nEndRow;

    std::unique_ptr<SCROW[]>  pNextEnd;
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index c587229..7d05066 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -786,6 +786,8 @@
    ScRangePairListRef& GetColNameRangesRef() { return xColNameRanges; }
    ScRangePairListRef& GetRowNameRangesRef() { return xRowNameRanges; }

    SC_DLLPUBLIC SCCOL ClampToAllocatedColumns(SCTAB nTab, SCCOL nCol) const;

    SC_DLLPUBLIC ScDBCollection* GetDBCollection() const { return pDBCollection.get();}
    void                         SetDBCollection( std::unique_ptr<ScDBCollection> pNewDBCollection,
                                                  bool bRemoveAutoFilter = false );
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index a4dd113..e9b1e3f 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -20,6 +20,7 @@
#ifndef INCLUDED_SC_INC_TABLE_HXX
#define INCLUDED_SC_INC_TABLE_HXX

#include <algorithm>
#include <vector>
#include <tools/gen.hxx>
#include <tools/color.hxx>
@@ -151,7 +152,7 @@
private:
    typedef ::std::vector< ScRange > ScRangeVec;

    ScColContainer  aCol;
    mutable ScColContainer aCol;

    OUString aName;
    OUString aCodeName;
@@ -273,14 +274,14 @@

    ScOutlineTable* GetOutlineTable()               { return pOutlineTable.get(); }

    ScColumn& CreateColumnIfNotExists( const SCCOL nScCol )
    ScColumn& CreateColumnIfNotExists( const SCCOL nScCol ) const
    {
        if ( nScCol >= aCol.size() )
            CreateColumnIfNotExistsImpl(nScCol);
        return aCol[nScCol];
    }
    // out-of-line the cold part of the function
    void CreateColumnIfNotExistsImpl( const SCCOL nScCol );
    void CreateColumnIfNotExistsImpl( const SCCOL nScCol ) const;
    sal_uLong       GetCellCount() const;
    sal_uLong       GetWeightedCount() const;
    sal_uLong       GetWeightedCount(SCROW nStartRow, SCROW nEndRow) const;
@@ -443,9 +444,11 @@

    CellType    GetCellType( const ScAddress& rPos ) const
                    {
                        return ValidColRow(rPos.Col(),rPos.Row()) ?
                            aCol[rPos.Col()].GetCellType( rPos.Row() ) :
                            CELLTYPE_NONE;
                        if (!ValidColRow(rPos.Col(),rPos.Row()))
                            return CELLTYPE_NONE;
                        if (rPos.Col() >= aCol.size())
                            return CELLTYPE_NONE;
                        return aCol[rPos.Col()].GetCellType( rPos.Row() );
                    }
    CellType    GetCellType( SCCOL nCol, SCROW nRow ) const;
    ScRefCellValue GetCellValue( SCCOL nCol, SCROW nRow ) const;
@@ -1072,6 +1075,8 @@
    static void UpdateSearchItemAddressForReplace( const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow );

    ScColumnsRange GetColumnsRange(SCCOL begin, SCCOL end) const;
    SCCOL ClampToAllocatedColumns(SCCOL nCol) const { return std::min(nCol, static_cast<SCCOL>(aCol.size() - 1)); }
    SCCOL GetAllocatedColumnsCount() const { return aCol.size(); }

private:

diff --git a/sc/source/core/data/columnspanset.cxx b/sc/source/core/data/columnspanset.cxx
index 1098ce3..89805a7 100644
--- a/sc/source/core/data/columnspanset.cxx
+++ b/sc/source/core/data/columnspanset.cxx
@@ -131,6 +131,7 @@
    if (!pTab)
        return;

    nCol2 = pTab->ClampToAllocatedColumns(nCol2);
    for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
    {
        ColumnType& rCol = getColumn(nTab, nCol);
@@ -181,7 +182,7 @@
            continue;

        const TableType& rTab = *maTables[nTab];
        for (size_t nCol = 0; nCol < rTab.size(); ++nCol)
        for (SCCOL nCol = 0; nCol < static_cast<SCCOL>(rTab.size()); ++nCol)
        {
            if (!rTab[nCol])
                continue;
@@ -190,7 +191,7 @@
            if (!pTab)
                continue;

            if (!ValidCol(nCol))
            if (!ValidCol(nCol) || nCol >= pTab->GetAllocatedColumnsCount())
            {
                // End the loop.
                nCol = rTab.size();
@@ -357,12 +358,13 @@
{
    for (SCTAB nTab = range.aStart.Tab(); nTab <= range.aEnd.Tab(); ++nTab)
    {
        for (SCCOL nCol = range.aStart.Col(); nCol <= range.aEnd.Col(); ++nCol)
        {
            ScTable* pTab = rDoc.FetchTable(nTab);
            if (!pTab)
                continue;
        ScTable* pTab = rDoc.FetchTable(nTab);
        if (!pTab)
            continue;

        SCCOL nEndCol = pTab->ClampToAllocatedColumns(range.aEnd.Col());
        for (SCCOL nCol = range.aStart.Col(); nCol <= nEndCol; ++nCol)
        {
            if (!ValidCol(nCol))
                break;

diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx
index 6cd02b5..174ff54 100644
--- a/sc/source/core/data/dociter.cxx
+++ b/sc/source/core/data/dociter.cxx
@@ -166,7 +166,7 @@
            do
            {
                ++mnCol;
                if (mnCol > maEndPos.Col())
                if (mnCol > maEndPos.Col() || mnCol >= pDoc->maTabs[mnTab]->GetAllocatedColumnsCount())
                {
                    mnCol = maStartPos.Col();
                    ++mnTab;
@@ -829,6 +829,7 @@
    maEndPos(rRange.aEnd),
    mnSubTotalFlags(nSubTotalFlags)
{
    maEndPos.SetCol( pDoc->ClampToAllocatedColumns(maStartPos.Tab(), maEndPos.Col()) );
    init();
}

@@ -1922,7 +1923,9 @@
    if (mnTab >= pDoc->GetTableCount())
        OSL_FAIL("try to access index out of bounds, FIX IT");

    maColPositions.reserve( nCol2-nCol1+1 );
    nEndCol = pDoc->maTabs[mnTab]->ClampToAllocatedColumns(nEndCol);

    maColPositions.reserve( nEndCol-nStartCol+1 );

    SetTab( mnTab );
}
@@ -2233,6 +2236,8 @@
        OSL_FAIL("try to access index out of bounds, FIX IT");
    OSL_ENSURE( pDoc->maTabs[nTab], "Table does not exist" );

    nEndCol = pDoc->maTabs[nTab]->ClampToAllocatedColumns(nEndCol);

    nRow = nStartRow;
    nCol = nStartCol;
    bRowEmpty = false;
@@ -2482,8 +2487,12 @@
    nEndRow( nRow2 ),
    nCol( nCol1 )
{
    if ( ValidTab(nTab) && nTab < pDoc->GetTableCount() && pDoc->maTabs[nTab] )
    if ( ValidTab(nTab) && nTab < pDoc->GetTableCount() && pDoc->maTabs[nTab]
        && nCol < pDoc->maTabs[nTab]->GetAllocatedColumnsCount())
    {
        nEndCol = pDoc->maTabs[nTab]->ClampToAllocatedColumns(nEndCol);
        pColIter = pDoc->maTabs[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
    }
}

ScDocAttrIterator::~ScDocAttrIterator()
@@ -2610,8 +2619,10 @@
    nIterStartCol( nCol1 ),
    nIterEndCol( nCol1 )
{
    if ( ValidTab(nTab) && nTab < pDoc->GetTableCount() && pDoc->maTabs[nTab] )
    if ( ValidTab(nTab) && nTab < pDoc->GetTableCount() && pDoc->maTabs[nTab]
        && nCol1 < pDoc->maTabs[nTab]->GetAllocatedColumnsCount())
    {
        nEndCol = pDoc->maTabs[nTab]->ClampToAllocatedColumns(nEndCol);
        pColIter = pDoc->maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
        while ( nIterEndCol < nEndCol &&
                pDoc->maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index a0c0bcd..75f1cdab 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -2098,4 +2098,9 @@
    mSheetSortParams[ nTab ] = rParam;
}

SCCOL ScDocument::ClampToAllocatedColumns(SCTAB nTab, SCCOL nCol) const
{
    return maTabs[nTab]->ClampToAllocatedColumns(nCol);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx
index c90353b..af0100f 100644
--- a/sc/source/core/data/documen8.cxx
+++ b/sc/source/core/data/documen8.cxx
@@ -578,6 +578,7 @@
    sal_uInt16 nZoom = getScaleValue(*pStyle, ATTR_PAGE_SCALE);
    Fraction aZoomFract(nZoom, 100);

    aScope.setCol(pTab->ClampToAllocatedColumns(aScope.Col()));
    // Start at specified cell position (nCol, nRow, nTab).
    ScColumn* pCol  = &pTab->aCol[aScope.Col()];
    std::unique_ptr<ScColumnTextWidthIterator> pColIter(new ScColumnTextWidthIterator(*pCol, aScope.Row(), MAXROW));
@@ -646,6 +647,8 @@
                bNewTab = true;
            }

            aScope.setCol(pTab->ClampToAllocatedColumns(aScope.Col()));

            if ( nRestart < 2 )
            {
                if ( bNewTab )
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 7538690..a3df463 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -4720,7 +4720,8 @@

const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
{
    if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
    if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] &&
         nCol < maTabs[nTab]->GetAllocatedColumnsCount())
    {
        const SfxPoolItem* pTemp = maTabs[nTab]->GetAttr( nCol, nRow, nWhich );
        if (pTemp)
@@ -6511,7 +6512,8 @@

ScPostIt* ScDocument::GetNote(SCCOL nCol, SCROW nRow, SCTAB nTab)
{
    if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
    if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) &&
        nCol < maTabs[nTab]->GetAllocatedColumnsCount())
        return maTabs[nTab]->aCol[nCol].GetCellNote(nRow);
    else
        return nullptr;
@@ -6542,6 +6544,9 @@
    if (!pTab)
        return false;

    if (nCol >= pTab->GetAllocatedColumnsCount())
        return false;

    const ScPostIt* pNote = pTab->aCol[nCol].GetCellNote(nRow);
    return pNote != nullptr;
}
diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index ecdcfd6..6c17020 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -442,7 +442,7 @@
    {
        SCCOL nX = (nArrCol>0) ? nArrCol-1 : MAXCOL+1;                    // negative -> invalid

        if ( ValidCol(nX) )
        if ( ValidCol(nX) && nX < maTabs[nTab]->GetAllocatedColumnsCount() )
        {
            // #i58049#, #i57939# Hidden columns must be skipped here, or their attributes
            // will disturb the output
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 6fb4538..d964642 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -237,7 +237,7 @@

ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const OUString& rNewName,
                    bool bColInfo, bool bRowInfo ) :
    aCol( MAXCOLCOUNT ),
    aCol( INITIALCOLCOUNT ),
    aName( rNewName ),
    aCodeName( rNewName ),
    nLinkRefreshDelay( 0 ),
@@ -1705,7 +1705,7 @@
        mpRangeName->UpdateReference(rCxt, nTab);

    for ( ; i<=iMax; i++)
        bUpdated |= aCol[i].UpdateReference(rCxt, pUndoDoc);
        bUpdated |= CreateColumnIfNotExists(i).UpdateReference(rCxt, pUndoDoc);

    if ( bIncludeDraw )
        UpdateDrawRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz, bUpdateNoteCaptionPos );
@@ -2434,11 +2434,12 @@
{
    size_t nMatCol = 0;
    for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nMatCol)
        aCol[nCol].FillMatrix(rMat, nMatCol, nRow1, nRow2, pPool);
        CreateColumnIfNotExists(nCol).FillMatrix(rMat, nMatCol, nRow1, nRow2, pPool);
}

void ScTable::InterpretDirtyCells( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
{
    nCol2 = ClampToAllocatedColumns(nCol2);
    for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
        aCol[nCol].InterpretDirtyCells(nRow1, nRow2);
}
@@ -2509,32 +2510,33 @@

ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const
{
    // Because the range is inclusive, some code will pass nColEnd<nColBegin to
    // indicate an empty range. Ensure that we create only valid iterators for
    // the range, limit columns to bounds.
    SCCOL nEffBegin, nEffEnd;
    if (nColBegin <= nColEnd)
    ScColContainer::ScColumnVector::const_iterator beginIter;
    ScColContainer::ScColumnVector::const_iterator endIter;

    // because the range is inclusive, some code will pass nColEnd<nColBegin to indicate an empty range
    if (nColEnd < nColBegin)
    {
        if (nColBegin < 0)
            nEffBegin = 0;
        else
            nEffBegin = std::min<SCCOL>( nColBegin, aCol.size());
        if (nColEnd < 0)
            nEffEnd = 0;
        else
            nEffEnd = std::min<SCCOL>( nColEnd + 1, aCol.size());
        beginIter = aCol.end();
        endIter = aCol.end();
    }
    else if (nColBegin >= aCol.size())
    {
        beginIter = aCol.end();
        endIter = aCol.end();
    }
    else
    {
        // Any empty will do.
        nEffBegin = nEffEnd = 0;
        // clamp end of range to available columns
        if (nColEnd >= aCol.size())
            nColEnd = aCol.size() - 1;
        beginIter = aCol.begin() + nColBegin;
        endIter = aCol.begin() + nColEnd + 1;
    }
    return ScColumnsRange( ScColumnsRange::Iterator( aCol.begin() + nEffBegin),
                           ScColumnsRange::Iterator( aCol.begin() + nEffEnd));
    return ScColumnsRange(ScColumnsRange::Iterator(beginIter), ScColumnsRange::Iterator(endIter));
}

// out-of-line the cold part of the CreateColumnIfNotExists function
void ScTable::CreateColumnIfNotExistsImpl( const SCCOL nScCol )
void ScTable::CreateColumnIfNotExistsImpl( const SCCOL nScCol ) const
{
    const SCCOL aOldColSize = aCol.size();
    aCol.resize( static_cast< size_t >( nScCol + 1 ) );
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index bc2293f..a74fc3a 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -136,7 +136,7 @@
        bTest = pOutlineTable->TestInsertRow(nSize);

    for (SCCOL i=nStartCol; (i<=nEndCol) && bTest; i++)
        bTest = aCol[i].TestInsertRow(nStartRow, nSize);
        bTest = CreateColumnIfNotExists(i).TestInsertRow(nStartRow, nSize);

    return bTest;
}
@@ -487,10 +487,10 @@
    if (!pTable->mpRangeName && mpRangeName)
        pTable->mpRangeName.reset( new ScRangeName(*mpRangeName) );

    SCCOL i;
    nCol2 = ClampToAllocatedColumns(nCol2);

    for ( i = nCol1; i <= nCol2; i++)
        aCol[i].CopyToClip(rCxt, nRow1, nRow2, pTable->aCol[i]);  // notes are handled at column level
    for ( SCCOL i = nCol1; i <= nCol2; i++)
        aCol[i].CopyToClip(rCxt, nRow1, nRow2, pTable->CreateColumnIfNotExists(i));  // notes are handled at column level

    //  copy widths/heights, and only "hidden", "filtered" and "manual" flags
    //  also for all preceding columns/rows, to have valid positions for drawing objects
@@ -515,7 +515,7 @@
    // If necessary replace formulas with values

    if ( IsProtected() )
        for (i = nCol1; i <= nCol2; i++)
        for (SCCOL i = nCol1; i <= nCol2; i++)
            pTable->aCol[i].RemoveProtected(nRow1, nRow2);

    pTable->mpCondFormatList.reset(new ScConditionalFormatList(pTable->pDocument, *mpCondFormatList));
@@ -665,7 +665,7 @@
    if (!ValidCol(nCol))
        return false;

    aCol[nCol].InitBlockPosition(rBlockPos);
    CreateColumnIfNotExists(nCol).InitBlockPosition(rBlockPos);
    return true;
}

@@ -681,7 +681,10 @@
    if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
    {
        for ( SCCOL i = nCol1; i <= nCol2; i++)
        {
            pTable->CreateColumnIfNotExists(i - nDx);
            aCol[i].CopyFromClip(rCxt, nRow1, nRow2, nDy, pTable->aCol[i - nDx]); // notes are handles at column level
        }

        if (rCxt.getInsertFlag() & InsertDeleteFlags::ATTRIB)
        {
@@ -1043,7 +1046,7 @@
    if (!ValidCol(nCol))
        return nullptr;

    return &aCol[nCol];
    return &CreateColumnIfNotExists(nCol);
}

const ScColumn* ScTable::FetchColumn( SCCOL nCol ) const
@@ -1124,9 +1127,9 @@
    {
        InsertDeleteFlags nTempFlags( nFlags &
                ~InsertDeleteFlags( InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES));
        for (SCCOL i = nCol1; i <= nCol2; i++)
        for (SCCOL i = nCol1; i <= ClampToAllocatedColumns(nCol2); i++)
            aCol[i].CopyToColumn(rCxt, nRow1, nRow2, bIsUndoDoc ? nFlags : nTempFlags, bMarked,
                                pDestTab->aCol[i], pMarkData, bAsLink, bGlobalNamesToLocal);
                                 pDestTab->CreateColumnIfNotExists(i), pMarkData, bAsLink, bGlobalNamesToLocal);
    }

    if (!bColRowFlags)      // Column widths/Row heights/Flags
@@ -1253,9 +1256,10 @@
    if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
        return;

    nCol2 = ClampToAllocatedColumns(nCol2);
    for (SCCOL i = nCol1; i <= nCol2; i++)
    {
        aCol[i].CopyCellNotesToDocument(nRow1, nRow2, pDestTab->aCol[i], bCloneCaption);
        aCol[i].CopyCellNotesToDocument(nRow1, nRow2, pDestTab->CreateColumnIfNotExists(i), bCloneCaption);
        pDestTab->aCol[i].UpdateNoteCaptions(nRow1, nRow2);
    }
}
@@ -1298,6 +1302,8 @@

void ScTable::CopyUpdated( const ScTable* pPosTab, ScTable* pDestTab ) const
{
    pPosTab->CreateColumnIfNotExists(aCol.size()-1);
    pDestTab->CreateColumnIfNotExists(aCol.size()-1);
    for (SCCOL i=0; i < aCol.size(); i++)
        aCol[i].CopyUpdated( pPosTab->aCol[i], pDestTab->aCol[i] );
}
@@ -1317,14 +1323,16 @@
    OSL_ENSURE( bScenario, "bScenario == FALSE" );

    for (SCCOL i=0; i < aCol.size(); i++)
        aCol[i].CopyScenarioTo( pDestTab->aCol[i] );
        aCol[i].CopyScenarioTo( pDestTab->CreateColumnIfNotExists(i) );
}

void ScTable::CopyScenarioFrom( const ScTable* pSrcTab )
{
    OSL_ENSURE( bScenario, "bScenario == FALSE" );

    for (SCCOL i=0; i < aCol.size(); i++)
    SCCOL nEndCol = pSrcTab->aCol.size();
    CreateColumnIfNotExists(nEndCol);
    for (SCCOL i=0; i < nEndCol; i++)
        aCol[i].CopyScenarioFrom( pSrcTab->aCol[i] );
}

@@ -1411,7 +1419,7 @@
        return false;
    }

    aCol[nCol].SetEditText(nRow, std::move(pEditText));
    CreateColumnIfNotExists(nCol).SetEditText(nRow, std::move(pEditText));
    return true;
}

@@ -1472,7 +1480,7 @@
    if (!ValidColRow(nCol, nRow))
        return;

    aCol[nCol].SetFormula(nRow, rFormula, eGram);
    CreateColumnIfNotExists(nCol).SetFormula(nRow, rFormula, eGram);
}

ScFormulaCell* ScTable::SetFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* pCell )
@@ -1516,7 +1524,7 @@

void ScTable::GetString( SCCOL nCol, SCROW nRow, OUString& rString, const ScInterpreterContext* pContext ) const
{
    if (ValidColRow(nCol,nRow))
    if (ValidColRow(nCol,nRow) && nCol < GetAllocatedColumnsCount())
        aCol[nCol].GetString( nRow, rString, pContext );
    else
        rString.clear();
@@ -1581,8 +1589,7 @@
{
    if (!ValidColRow(nCol, nRow))
        return nullptr;

    return aCol[nCol].GetFormulaCell(nRow);
    return CreateColumnIfNotExists(nCol).GetFormulaCell(nRow);
}

std::unique_ptr<ScPostIt> ScTable::ReleaseNote( SCCOL nCol, SCROW nRow )
@@ -1793,6 +1800,7 @@
    bool bOldAutoCalc = pDocument->GetAutoCalc();
    pDocument->SetAutoCalc( false );    // avoid multiple recalculations
    SCCOL nCol2 = rRange.aEnd.Col();
    nCol2 = ClampToAllocatedColumns(nCol2);
    for (SCCOL i=rRange.aStart.Col(); i<=nCol2; i++)
        aCol[i].SetDirty(rRange.aStart.Row(), rRange.aEnd.Row(), eMode);
    pDocument->SetAutoCalc( bOldAutoCalc );
@@ -1913,7 +1921,7 @@
{
    SCCOL nStartCol = rRange.aStart.Col();
    SCROW nStartRow = rRange.aStart.Row();
    SCCOL nEndCol = rRange.aEnd.Col();
    SCCOL nEndCol = ClampToAllocatedColumns(rRange.aEnd.Col());
    SCROW nEndRow = rRange.aEnd.Row();

    for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
@@ -1964,7 +1972,7 @@
const ScPatternAttr* ScTable::GetPattern( SCCOL nCol, SCROW nRow ) const
{
    if (ValidColRow(nCol,nRow))
        return aCol[nCol].GetPattern( nRow );
        return CreateColumnIfNotExists(nCol).GetPattern( nRow );
    else
    {
        OSL_FAIL("wrong column or row");
@@ -1974,7 +1982,8 @@

const ScPatternAttr* ScTable::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const
{
    if ( ValidColRow( nCol, nStartRow ) && ValidRow( nEndRow ) && (nStartRow <= nEndRow) )
    if ( ValidColRow( nCol, nStartRow ) && ValidRow( nEndRow ) && (nStartRow <= nEndRow)
        && nCol < GetAllocatedColumnsCount())
        return aCol[nCol].GetMostUsedPattern( nStartRow, nEndRow );
    else
        return nullptr;
@@ -2052,6 +2061,7 @@
        OSL_FAIL("ScTable::IsBlockEmpty: invalid column number");
        return false;
    }
    nCol2 = ClampToAllocatedColumns(nCol2);
    bool bEmpty = true;
    for (SCCOL i=nCol1; i<=nCol2 && bEmpty; i++)
    {
@@ -2300,7 +2310,8 @@

    for (sc::ColRowSpan & aSpan : aSpans)
    {
        for ( SCCOLROW j=aSpan.mnStart; j<=aSpan.mnEnd; j++ )
        SCCOL nEndCol = ClampToAllocatedColumns(aSpan.mnEnd);
        for ( SCCOLROW j=aSpan.mnStart; j<=nEndCol; j++ )
        {
            if ( aCol[j].HasSelectionMatrixFragment(rMark) )
                return true;
@@ -2319,6 +2330,8 @@
            *pOnlyNotBecauseOfMatrix = false;
        return false;
    }
    nCol1 = ClampToAllocatedColumns(nCol1);
    nCol2 = ClampToAllocatedColumns(nCol2);

    bool bIsEditable = true;
    if ( nLockCount )
@@ -2495,7 +2508,8 @@

    for (const sc::ColRowSpan & rSpan : aSpans)
    {
        for (SCCOLROW i = rSpan.mnStart; i <= rSpan.mnEnd; ++i)
        SCCOL nEnd = ClampToAllocatedColumns(rSpan.mnEnd);
        for (SCCOLROW i = rSpan.mnStart; i <= nEnd; ++i)
        {
            aCol[i].MergeSelectionPattern( rState, rMark, bDeep );
        }
@@ -2505,6 +2519,7 @@
void ScTable::MergePatternArea( ScMergePatternState& rState, SCCOL nCol1, SCROW nRow1,
                                                    SCCOL nCol2, SCROW nRow2, bool bDeep ) const
{
    nCol2 = ClampToAllocatedColumns(nCol2);
    for (SCCOL i=nCol1; i<=nCol2; i++)
        aCol[i].MergePatternArea( rState, nRow1, nRow2, bDeep );
}
@@ -2550,7 +2565,7 @@
        PutInOrder(nStartCol, nEndCol);
        PutInOrder(nStartRow, nEndRow);
        for (SCCOL i = nStartCol; i <= nEndCol; i++)
            aCol[i].ApplyPatternArea(nStartRow, nEndRow, rAttr, pDataArray, pIsChanged);
            CreateColumnIfNotExists(i).ApplyPatternArea(nStartRow, nEndRow, rAttr, pDataArray, pIsChanged);
    }
}

@@ -2576,7 +2591,7 @@
        SCROW nRowEnd = rRange.aEnd.Row();
        for(SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol)
        {
            aCol[nCol].AddCondFormat(nRowStart, nRowEnd, nIndex);
            CreateColumnIfNotExists(nCol).AddCondFormat(nRowStart, nRowEnd, nIndex);
        }
    }
}
@@ -2588,7 +2603,7 @@
    {
        const ScRange & rRange = rRangeList[i];
        SCCOL nColStart = rRange.aStart.Col();
        SCCOL nColEnd = rRange.aEnd.Col();
        SCCOL nColEnd = ClampToAllocatedColumns(rRange.aEnd.Col());
        SCROW nRowStart = rRange.aStart.Row();
        SCROW nRowEnd = rRange.aEnd.Row();
        for(SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol)
@@ -2698,7 +2713,7 @@

    const ScStyleSheet* pStyle = nullptr;
    const ScStyleSheet* pNewStyle;

    nCol2 = ClampToAllocatedColumns(nCol2);
    for (SCCOL i=nCol1; i<=nCol2 && bEqual; i++)
    {
        pNewStyle = aCol[i].GetAreaStyle(bColFound, nRow1, nRow2);
@@ -2761,17 +2776,19 @@
    bool bChanged = false;
    if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
        for (SCCOL i = nStartCol; i <= nEndCol; i++)
            bChanged |= aCol[i].ApplyFlags(nStartRow, nEndRow, nFlags);
            bChanged |= CreateColumnIfNotExists(i).ApplyFlags(nStartRow, nEndRow, nFlags);
    return bChanged;
}

bool ScTable::RemoveFlags( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
                           ScMF nFlags )
{
    if (!ValidColRow(nStartCol, nStartRow) || !ValidColRow(nEndCol, nEndRow))
        return false;
    bool bChanged = false;
    if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
        for (SCCOL i = nStartCol; i <= nEndCol; i++)
            bChanged |= aCol[i].RemoveFlags(nStartRow, nEndRow, nFlags);
    nEndCol = ClampToAllocatedColumns(nEndCol);
    for (SCCOL i = nStartCol; i <= nEndCol; i++)
        bChanged |= aCol[i].RemoveFlags(nStartRow, nEndRow, nFlags);
    return bChanged;
}

@@ -2784,7 +2801,7 @@
void ScTable::ApplyAttr( SCCOL nCol, SCROW nRow, const SfxPoolItem& rAttr )
{
    if (ValidColRow(nCol,nRow))
        aCol[nCol].ApplyAttr( nRow, rAttr );
        CreateColumnIfNotExists(nCol).ApplyAttr( nRow, rAttr );
}

void ScTable::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark,
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 4e9f074..819bfa6 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -17,7 +17,6 @@
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <rtl/math.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/random.hxx>
#include <unotools/textsearch.hxx>
@@ -1825,7 +1824,7 @@
{
    SCCOL nStartCol = rParam.nCol1;
    SCROW nStartRow = rParam.nRow1 + 1;     // Header
    SCCOL nEndCol   = rParam.nCol2;
    SCCOL nEndCol   = ClampToAllocatedColumns(rParam.nCol2);
    SCROW nEndRow    = rParam.nRow2;

    for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol)
@@ -1859,7 +1858,7 @@
{
    SCCOL nStartCol = rParam.nCol1;
    SCROW nStartRow = rParam.nRow1 + 1;     // Header
    SCCOL nEndCol   = rParam.nCol2;
    SCCOL nEndCol   = ClampToAllocatedColumns(rParam.nCol2);
    SCROW nEndRow    = rParam.nRow2;        // will change

    RemoveSubTotalsHandler aFunc;
@@ -3541,7 +3540,7 @@
        aMarkArea.aEnd.SetCol(MAXCOL);
    }
    const SCCOL nStartCol = aMarkArea.aStart.Col();
    const SCCOL nEndCol = aMarkArea.aEnd.Col();
    const SCCOL nEndCol = ClampToAllocatedColumns(aMarkArea.aEnd.Col());
    for (SCCOL nCol = nStartCol; nCol <= nEndCol && !rData.getError(); ++nCol)
    {
        if (mpColFlags && ColHidden(nCol))
diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index 91201f0..4175459 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -1638,6 +1638,8 @@
    {
        rInner = nISource;

        CreateColumnIfNotExists(nCol);

        // Source cell value. We need to clone the value since it may be inserted repeatedly.
        ScCellValue aSrcCell = aCol[nCol].GetCellValue(static_cast<SCROW>(nRow));

diff --git a/sc/source/core/data/table5.cxx b/sc/source/core/data/table5.cxx
index 4d3c99f..5a50a7c 100644
--- a/sc/source/core/data/table5.cxx
+++ b/sc/source/core/data/table5.cxx
@@ -1082,7 +1082,7 @@
    if (!ValidCol(rAddress.Col()))
        return;

    aCol[rAddress.Col()].StartListening( *pListener, rAddress.Row() );
    CreateColumnIfNotExists(rAddress.Col()).StartListening( *pListener, rAddress.Row() );
}

void ScTable::EndListening( const ScAddress& rAddress, SvtListener* pListener )
@@ -1090,7 +1090,8 @@
    if (!ValidCol(rAddress.Col()))
        return;

    aCol[rAddress.Col()].EndListening( *pListener, rAddress.Row() );
    if (rAddress.Col() < aCol.size())
        aCol[rAddress.Col()].EndListening( *pListener, rAddress.Row() );
}

void ScTable::StartListening( sc::StartListeningContext& rCxt, const ScAddress& rAddress, SvtListener& rListener )
diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx
index 30f869a..e0ed0c9 100644
--- a/sc/source/core/data/table7.cxx
+++ b/sc/source/core/data/table7.cxx
@@ -21,7 +21,7 @@

bool ScTable::IsMerged( SCCOL nCol, SCROW nRow ) const
{
    if (!ValidCol(nCol))
    if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount() )
        return false;

    return aCol[nCol].IsMerged(nRow);
@@ -128,7 +128,7 @@
        SCCOL nColOffset = nCol - nCol1;
        nColOffset = nColOffset % nSrcColSize;
        assert(nColOffset >= 0);
        aCol[nCol].CopyOneCellFromClip(rCxt, nRow1, nRow2, nColOffset);
        CreateColumnIfNotExists(nCol).CopyOneCellFromClip(rCxt, nRow1, nRow2, nColOffset);

        if (rCxt.getInsertFlag() & InsertDeleteFlags::ATTRIB)
        {
@@ -318,9 +318,7 @@
    if (nCol2 < nCol1 || !IsColValid(nCol1) || !ValidCol(nCol2))
        return;

    const SCCOL nMaxCol2 = std::min<SCCOL>( nCol2, aCol.size() - 1 );

    for (SCCOL nCol = nCol1; nCol <= nMaxCol2; ++nCol)
    for (SCCOL nCol : GetColumnsRange(nCol1, nCol2))
        aCol[nCol].EndListeningIntersectedGroups(rCxt, nRow1, nRow2, pGroupPos);
}

@@ -345,7 +343,7 @@
{
    if (!IsProtected())
    {
        SCCOL nCol1 = 0, nCol2 = MAXCOL;
        SCCOL nCol1 = 0, nCol2 = aCol.size() - 1;
        SCROW nRow1 = 0, nRow2 = MAXROW;

        switch (eAction)
diff --git a/sc/source/ui/dbgui/tpsort.cxx b/sc/source/ui/dbgui/tpsort.cxx
index 9b6c72e..04bb7d6 100644
--- a/sc/source/ui/dbgui/tpsort.cxx
+++ b/sc/source/ui/dbgui/tpsort.cxx
@@ -340,7 +340,7 @@
            if ( bSortByRows )
            {
                OUString  aFieldName;
                SCCOL   nMaxCol = aSortData.nCol2;
                SCCOL   nMaxCol = pDoc->ClampToAllocatedColumns(nTab, aSortData.nCol2);
                SCCOL   col;

                for ( col=nFirstSortCol; col<=nMaxCol && i<SC_MAXFIELDS; col++ )