Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/dbaccess/source/ui/querydesign/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 148 kB image not shown  

Quelle  QueryDesignView.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <QueryDesignView.hxx>
#include <QueryTableView.hxx>
#include "QTableWindow.hxx"
#include <querycontroller.hxx>
#include <sqlbison.hxx>
#include <vcl/split.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/string_view.hxx>
#include <osl/diagnose.h>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <browserids.hxx>
#include "SelectionBrowseBox.hxx"
#include <strings.hrc>
#include <strings.hxx>
#include <comphelper/string.hxx>
#include <connectivity/dbtools.hxx>
#include <connectivity/dbexception.hxx>
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/sdbc/ColumnValue.hpp>
#include <connectivity/PColumn.hxx>
#include "QTableConnection.hxx"
#include <ConnectionLineData.hxx>
#include "QTableConnectionData.hxx"
#include <core_resource.hxx>
#include <UITools.hxx>
#include <querycontainerwindow.hxx>
#include <unotools/localedatawrapper.hxx>
#include <unotools/syslocale.hxx>
#include <memory>
#include <set>
#include <string_view>

using namespace ::dbaui;
using namespace ::connectivity;
using namespace ::dbtools;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;

// here we define our functions used in the anonymous namespace to get our header file smaller
// please look at the book LargeScale C++ to know why
namespace
{
    const char C_AND[] = " AND ";
    const char C_OR[] = " OR ";

    bool InsertJoin(    const OQueryDesignView* _pView,
                            const ::connectivity::OSQLParseNode *pNode);

    SqlParseError InstallFields(OQueryDesignView* _pView,
                                const ::connectivity::OSQLParseNode* pNode,
                                OJoinTableView::OTableWindowMap* pTabList );

    SqlParseError GetGroupCriteria( OQueryDesignView* _pView,
                                    OSelectionBrowseBox* _pSelectionBrw,
                                    const ::connectivity::OSQLParseNode* pSelectRoot );

    SqlParseError GetHavingCriteria(OQueryDesignView* _pView,
                                    OSelectionBrowseBox* _pSelectionBrw,
                                    const ::connectivity::OSQLParseNode* pSelectRoot,
                                    sal_uInt16& rLevel );

    SqlParseError GetOrderCriteria( OQueryDesignView* _pView,
                                    OSelectionBrowseBox* _pSelectionBrw,
                                    const ::connectivity::OSQLParseNode* pParseRoot );

    SqlParseError AddFunctionCondition(OQueryDesignView const * _pView,
                                    OSelectionBrowseBox* _pSelectionBrw,
                                    const ::connectivity::OSQLParseNode * pCondition,
                                    const sal_uInt16 nLevel,
                                    bool bHaving,
                                    bool _bAddOrOnOneLine);

    OUString quoteTableAlias(bool _bQuote, const OUString& _sAliasName, std::u16string_view _sQuote)
    {
        OUString sRet;
        if ( _bQuote && !_sAliasName.isEmpty() )
        {
            sRet = ::dbtools::quoteName(_sQuote,_sAliasName) + ".";
        }
        return sRet;
    }
    OUString getTableRange(const OQueryDesignView* _pView,const ::connectivity::OSQLParseNode* _pTableRef)
    {
        Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
        OUString sTableRange;
        if ( _pTableRef )
        {
            sTableRange = ::connectivity::OSQLParseNode::getTableRange(_pTableRef);
            if ( sTableRange.isEmpty() )
                _pTableRef->parseNodeToStr(sTableRange,xConnection,nullptr,false,false);
        }
        return sTableRange;
    }
    void insertConnection(const OQueryDesignView* _pView,const EJoinType& _eJoinType, const OTableFieldDescRef& _aDragLeft, const OTableFieldDescRef& _aDragRight, bool _bNatural = false)
    {
        OQueryTableView* pTableView = static_cast<OQueryTableView*>(_pView->getTableView());
        OQueryTableConnection* pConn = static_cast<OQueryTableConnection*>( pTableView->GetTabConn(static_cast<OTableWindow*>(_aDragLeft->GetTabWindow()),static_cast<OTableWindow*>(_aDragRight->GetTabWindow()),true));

        if ( !pConn )
        {
            auto xInfoData = std::make_shared<OQueryTableConnectionData>();
            xInfoData->InitFromDrag(_aDragLeft, _aDragRight);
            xInfoData->SetJoinType(_eJoinType);

            if ( _bNatural )
            {
                xInfoData->ResetConnLines();
                xInfoData->setNatural(_bNatural);
                try
                {
                    Reference<XNameAccess> xReferencedTableColumns(xInfoData->getReferencedTable()->getColumns());
                    for (auto& column : xInfoData->getReferencingTable()->getColumns()->getElementNames())
                    {
                        if (xReferencedTableColumns->hasByName(column))
                            xInfoData->AppendConnLine(column, column);
                    }
                }
                catchconst Exception& )
                {
                    DBG_UNHANDLED_EXCEPTION("dbaccess");
                }
            }

            ScopedVclPtrInstance< OQueryTableConnection > aInfo(pTableView, xInfoData);
            // Because OQueryTableConnection never takes ownership of the data passed to it, but only remembers the pointer,
            // this pointer to a local variable is not critical, as xInfoData and aInfo have the same lifetime
            pTableView->NotifyTabConnection( *aInfo );
        }
        else
        {
            OUString aSourceFieldName(_aDragLeft->GetField());
            OUString aDestFieldName(_aDragRight->GetField());
            // the connection could point on the other side
            if (pConn->GetSourceWin() == _aDragRight->GetTabWindow())
                std::swap(aSourceFieldName, aDestFieldName);
            pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName);
            pConn->UpdateLineList();
            // Modified-Flag
            //  SetModified();
            // and redraw
            pConn->RecalcLines();
                // for the following Invalidate, the new Connection must first be able
                // to determine its BoundingRect
            pConn->InvalidateConnection();
        }
    }
    OUString ParseCondition( OQueryController& rController
                                    ,const ::connectivity::OSQLParseNode* pCondition
                                    ,const OUString& _sDecimal
                                    ,const css::lang::Locale& _rLocale
                                    ,sal_uInt32 _nStartIndex)
    {
        OUString aCondition;
        Reference< XConnection> xConnection = rController.getConnection();
        if ( xConnection.is() )
        {
            sal_uInt32 nCount = pCondition->count();
            for(sal_uInt32 i = _nStartIndex ; i < nCount ; ++i)
                pCondition->getChild(i)->parseNodeToPredicateStr(aCondition,
                                xConnection,
                                rController.getNumberFormatter(),
                                _rLocale,
                                _sDecimal,
                                &rController.getParser().getContext());
        }
        return aCondition;
    }
    SqlParseError FillOuterJoins(OQueryDesignView const * _pView,
                                const ::connectivity::OSQLParseNode* pTableRefList)
    {
        SqlParseError eErrorCode = eOk;
        sal_uInt32 nCount = pTableRefList->count();
        bool bError = false;
        for (sal_uInt32 i=0; !bError && i < nCount; ++i)
        {
            const ::connectivity::OSQLParseNode* pParseNode = pTableRefList->getChild(i);
            const ::connectivity::OSQLParseNode* pJoinNode = nullptr;

            if ( SQL_ISRULE( pParseNode, qualified_join ) || SQL_ISRULE( pParseNode, joined_table ) || SQL_ISRULE( pParseNode, cross_union ) )
                pJoinNode = pParseNode;
            else if(    SQL_ISRULE(pParseNode,table_ref)
                    &&  pParseNode->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
                pJoinNode = pParseNode->getChild(2);

            if ( pJoinNode )
            {
                if ( !InsertJoin(_pView,pJoinNode) )
                    bError = true;
            }
        }
        // check if error occurred
        if ( bError )
            eErrorCode = eIllegalJoin;

        return eErrorCode;
    }

    /** FillDragInfo fills the field description out of the table
    */

    SqlParseError FillDragInfo( const OQueryDesignView* _pView,
                            const ::connectivity::OSQLParseNode* pColumnRef,
                            OTableFieldDescRef const & _rDragInfo)
    {
        SqlParseError eErrorCode = eOk;

        bool bErg = false;

        OUString aTableRange,aColumnName;
        ::connectivity::OSQLParseTreeIterator& rParseIter = static_cast<OQueryController&&gt;(_pView->getController()).getParseIterator();
        rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange );

        if ( !aTableRange.isEmpty() )
        {
            OQueryTableWindow*  pSTW = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( aTableRange );
            bErg = (pSTW && pSTW->ExistsField( aColumnName, _rDragInfo ) );
        }
        if ( !bErg )
        {
            sal_uInt16 nCntAccount;
            bErg = static_cast<OQueryTableView*>(_pView->getTableView())->FindTableFromField(aColumnName, _rDragInfo, nCntAccount);
            if ( !bErg )
                bErg = _pView->HasFieldByAliasName(aColumnName, _rDragInfo);
        }
        if ( !bErg )
        {
            eErrorCode = eColumnNotFound;
            OUString sError(DBA_RES(STR_QRY_COLUMN_NOT_FOUND));
            sError = sError.replaceFirst("$name$",aColumnName);
            _pView->getController().appendError( sError );

            try
            {
                Reference<XDatabaseMetaData> xMeta = _pView->getController().getConnection()->getMetaData();
                if ( xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() )
                    _pView->getController().appendError(DBA_RES(STR_QRY_CHECK_CASESENSITIVE));
            }
            catch(Exception&)
            {
            }
        }

        return eErrorCode;
    }
    OUString BuildJoinCriteria(  const Reference< XConnection>& _xConnection,
                                        const OConnectionLineDataVec* pLineDataList,
                                        const OQueryTableConnectionData* pData)
    {
        OUStringBuffer aCondition;
        if ( _xConnection.is() )
        {
            try
            {
                const Reference< XDatabaseMetaData >  xMetaData = _xConnection->getMetaData();
                const OUString aQuote = xMetaData->getIdentifierQuoteString();

                for (auto const& lineData : *pLineDataList)
                {
                    if(!aCondition.isEmpty())
                        aCondition.append(C_AND);
                    aCondition.append(
                        quoteTableAlias(true,pData->GetAliasName(JTCS_FROM),aQuote)
                        + ::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_FROM) )
                        + " = "
                        + quoteTableAlias(true,pData->GetAliasName(JTCS_TO),aQuote)
                        + ::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_TO) ));
                }
            }
            catch(SQLException&)
            {
                OSL_FAIL("Failure while building Join criteria!");
            }
        }

        return aCondition.makeStringAndClear();
    }
    /** JoinCycle looks for a join cycle and append it to the string
        @param  _xConnection    the connection
        @param  _pEntryConn     the table connection which holds the data
        @param  _pEntryTabTo    the corresponding table window
        @param  _rJoin          the String which will contain the resulting string
    */

    void JoinCycle( const Reference< XConnection>& _xConnection,
                    OQueryTableConnection* _pEntryConn,
                    const OQueryTableWindow* _pEntryTabTo,
                    OUString& _rJoin )
    {
        assert(_pEntryConn && "TableConnection can not be null!");

        OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pEntryConn->GetData().get());
        if ( !(pData->GetJoinType() != INNER_JOIN && _pEntryTabTo->ExistsAVisitedConn()) )
            return;

        bool bBrace = false;
        if(_rJoin.endsWith(")"))
        {
            bBrace = true;
            _rJoin = _rJoin.replaceAt(_rJoin.getLength()-1,1, u" ");
        }
        _rJoin += C_AND + BuildJoinCriteria(_xConnection,&pData->GetConnLineDataList(),pData);
        if(bBrace)
            _rJoin += ")";
        _pEntryConn->SetVisited(true);
    }
    OUString BuildTable( const Reference< XConnection>& _xConnection,
                                const OQueryTableWindow* pEntryTab,
                                bool _bForce = false
                                )
    {
        OUString aDBName(pEntryTab->GetComposedName());

        if( _xConnection.is() )
        {
            try
            {
                Reference< XDatabaseMetaData >  xMetaData = _xConnection->getMetaData();

                OUString sCatalog, sSchema, sTable;
                ::dbtools::qualifiedNameComponents( xMetaData, aDBName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
                OUString aTableListStr = ::dbtools::composeTableNameForSelect( _xConnection, sCatalog, sSchema, sTable );

                OUString aQuote = xMetaData->getIdentifierQuoteString();
                if ( _bForce || isAppendTableAliasEnabled( _xConnection ) || pEntryTab->GetAliasName() != aDBName )
                {
                    aTableListStr += " ";
                    if ( generateAsBeforeTableAlias( _xConnection ) )
                        aTableListStr += "AS ";
                    aTableListStr += ::dbtools::quoteName( aQuote, pEntryTab->GetAliasName() );
                }
                aDBName = aTableListStr;
            }
            catch(const SQLException&)
            {
                DBG_UNHANDLED_EXCEPTION("dbaccess");
            }
        }
        return aDBName;
    }
    OUString BuildJoin(  const Reference< XConnection>& _xConnection,
                                const OUString& rLh,
                                std::u16string_view rRh,
                                const OQueryTableConnectionData* pData)
    {

        OUString aErg(rLh);
        if ( pData->isNatural() && pData->GetJoinType() != CROSS_JOIN )
            aErg += " NATURAL ";
        switch(pData->GetJoinType())
        {
            case LEFT_JOIN:
                aErg += " LEFT OUTER ";
                break;
            case RIGHT_JOIN:
                aErg += " RIGHT OUTER ";
                break;
            case CROSS_JOIN:
                OSL_ENSURE(!pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!");
                aErg += " CROSS ";
                break;
            case INNER_JOIN:
                OSL_ENSURE(pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!");
                aErg += " INNER ";
                break;
            default:
                aErg += " FULL OUTER ";
                break;
        }
        aErg += OUString::Concat("JOIN ") + rRh;
        if ( CROSS_JOIN != pData->GetJoinType() && !pData->isNatural() )
        {
            aErg += " ON " + BuildJoinCriteria(_xConnection,&pData->GetConnLineDataList(),pData);
        }

        return aErg;
    }
    OUString BuildJoin(  const Reference< XConnection>& _xConnection,
                                const OQueryTableWindow* pLh,
                                const OQueryTableWindow* pRh,
                                const OQueryTableConnectionData* pData
                                )
    {
        bool bForce = pData->GetJoinType() == CROSS_JOIN || pData->isNatural();
        return BuildJoin(_xConnection,BuildTable(_xConnection,pLh,bForce),BuildTable(_xConnection,pRh,bForce),pData);
    }
    OUString BuildJoin(  const Reference< XConnection>& _xConnection,
                                const OUString &rLh,
                                const OQueryTableWindow* pRh,
                                const OQueryTableConnectionData* pData
                                )
    {
        return BuildJoin(_xConnection,rLh,BuildTable(_xConnection,pRh),pData);
    }
    OUString BuildJoin(  const Reference< XConnection>& _xConnection,
                                const OQueryTableWindow* pLh,
                                const OUString &rRh,
                                const OQueryTableConnectionData* pData
                                )
    {
        // strict ANSI SQL:
        // - does not support any bracketing of JOINS
        // - supports nested joins only in the LEFT HAND SIDE
        // In this case, we are trying to build a join with a nested join
        // in the right hand side.
        // So switch the direction of the join and both hand sides.
        OQueryTableConnectionData data(*pData);
        switch (data.GetJoinType())
        {
        case LEFT_JOIN:
            data.SetJoinType(RIGHT_JOIN);
            break;
        case RIGHT_JOIN:
            data.SetJoinType(LEFT_JOIN);
            break;
        default:
            // the other join types are symmetric, so nothing to change
            break;
        }
        return BuildJoin(_xConnection, rRh, BuildTable(_xConnection,pLh), &data);
    }
    void addConnectionTableNames( const Reference< XConnection>& _xConnection,
                                  const OQueryTableConnection* const pEntryConn,
                                  std::set<OUString> &_rTableNames )
    {
            // insert tables into table list to avoid double entries
            const OQueryTableWindow* const pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
            const OQueryTableWindow* const pEntryTabTo = static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin());
            _rTableNames.insert(BuildTable(_xConnection,pEntryTabFrom));
            _rTableNames.insert(BuildTable(_xConnection,pEntryTabTo));
    }
    void GetNextJoin(   const Reference< XConnection>& _xConnection,
                        OQueryTableConnection* pEntryConn,
                        OQueryTableWindow const * pEntryTabTo,
                        OUString &aJoin,
                        std::set<OUString> &_rTableNames)
    {
        OQueryTableConnectionData* pEntryConnData = static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get());
        if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() )
            return;

        if(aJoin.isEmpty())
        {
            addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
            OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
            aJoin = BuildJoin(_xConnection,pEntryTabFrom,pEntryTabTo,pEntryConnData);
        }
        else if(pEntryTabTo == pEntryConn->GetDestWin())
        {
            addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
            aJoin = BuildJoin(_xConnection,aJoin,pEntryTabTo,pEntryConnData);
        }
        else if(pEntryTabTo == pEntryConn->GetSourceWin())
        {
            addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
            aJoin = BuildJoin(_xConnection,pEntryTabTo,aJoin,pEntryConnData);
        }

        pEntryConn->SetVisited(true);

        // first search for the "to" window
        const auto& rConnections = pEntryConn->GetParent()->getTableConnections();
        bool bFound = false;
        for (auto const& connection : rConnections)
        {
            OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(connection.get());
            if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabTo || pNext->GetDestWin() == pEntryTabTo))
            {
                OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabTo ? static_cast<OQueryTableWindow*>(pNext->GetDestWin()) : static_cast<OQueryTableWindow*>(pNext->GetSourceWin());
                // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
                JoinCycle(_xConnection,pNext,pEntryTab,aJoin);
                if(!pNext->IsVisited())
                    GetNextJoin(_xConnection, pNext, pEntryTab, aJoin, _rTableNames);
                bFound = true;
            }
        }

        // when nothing found look for the "from" window
        if(bFound)
            return;

        OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
        for (auto const& connection : rConnections)
        {
            OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(connection.get());
            if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabFrom || pNext->GetDestWin() == pEntryTabFrom))
            {
                OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabFrom ? static_cast<OQueryTableWindow*>(pNext->GetDestWin()) : static_cast<OQueryTableWindow*>(pNext->GetSourceWin());
                // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
                JoinCycle(_xConnection,pNext,pEntryTab,aJoin);
                if(!pNext->IsVisited())
                    GetNextJoin(_xConnection, pNext, pEntryTab, aJoin, _rTableNames);
            }
        }
    }
    SqlParseError InsertJoinConnection( const OQueryDesignView* _pView,
                                    const ::connectivity::OSQLParseNode *pNode,
                                    const EJoinType& _eJoinType,
                                    const ::connectivity::OSQLParseNode *pLeftTable,
                                    const ::connectivity::OSQLParseNode *pRightTable)
    {
        SqlParseError eErrorCode = eOk;
        if (pNode->count() == 3 &&  // statement between brackets
            SQL_ISPUNCTUATION(pNode->getChild(0),"(") &&
            SQL_ISPUNCTUATION(pNode->getChild(2),")"))
        {
            eErrorCode = InsertJoinConnection(_pView,pNode->getChild(1), _eJoinType,pLeftTable,pRightTable);
        }
        else if (SQL_ISRULEOR2(pNode,search_condition,boolean_term) &&          // AND/OR-joints:
                 pNode->count() == 3)
        {
            // only allow AND joints
            if (!SQL_ISTOKEN(pNode->getChild(1),AND))
                eErrorCode = eIllegalJoinCondition;
            else if ( eOk == (eErrorCode = InsertJoinConnection(_pView,pNode->getChild(0), _eJoinType,pLeftTable,pRightTable)) )
                    eErrorCode = InsertJoinConnection(_pView,pNode->getChild(2), _eJoinType,pLeftTable,pRightTable);
        }
        else if (SQL_ISRULE(pNode,comparison_predicate))
        {
            // only the comparison of columns is allowed
            OSL_ENSURE(pNode->count() == 3,"OQueryDesignView::InsertJoinConnection: Error in Parse Tree");
            if (!(SQL_ISRULE(pNode->getChild(0),column_ref) &&
                  SQL_ISRULE(pNode->getChild(2),column_ref) &&
                   pNode->getChild(1)->getNodeType() == SQLNodeType::Equal))
            {
                OUString sError(DBA_RES(STR_QRY_JOIN_COLUMN_COMPARE));
                _pView->getController().appendError( sError );
                return eIllegalJoin;
            }

            OTableFieldDescRef aDragLeft  = new OTableFieldDesc();
            OTableFieldDescRef aDragRight = new OTableFieldDesc();
            eErrorCode = FillDragInfo(_pView,pNode->getChild(0),aDragLeft);
            if ( eOk != eErrorCode )
                return eErrorCode;
            eErrorCode = FillDragInfo(_pView,pNode->getChild(2),aDragRight);
            if ( eOk != eErrorCode )
                return eErrorCode;

            if ( pLeftTable )
            {
                OQueryTableWindow*  pLeftWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pLeftTable->getByRule(OSQLParseNode::table_ref) ));
                if ( pLeftWindow == aDragLeft->GetTabWindow() )
                    insertConnection(_pView,_eJoinType,aDragLeft,aDragRight);
                else
                    insertConnection(_pView,_eJoinType,aDragRight,aDragLeft);
            }
            else
                insertConnection(_pView,_eJoinType,aDragLeft,aDragRight);
        }
        else
            eErrorCode = eIllegalJoin;
        return eErrorCode;
    }
    bool GetInnerJoinCriteria(  const OQueryDesignView* _pView,
                                    const ::connectivity::OSQLParseNode *pCondition)
    {
        return InsertJoinConnection(_pView,pCondition, INNER_JOIN,nullptr,nullptr) != eOk;
    }
    OUString GenerateSelectList( const OQueryDesignView* _pView,
                                        OTableFields&   _rFieldList,
                                        bool bAlias)
    {
        Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
        if ( !xConnection.is() )
            return OUString();

        OUStringBuffer aTmpStr,aFieldListStr;

        bool bAsterisk = false;
        int nVis = 0;
        for (auto const& field : _rFieldList)
        {
            if ( field->IsVisible() )
            {
                if ( field->GetField().toChar() == '*' )
                    bAsterisk = true;
                ++nVis;
            }
        }
        if(nVis == 1)
            bAsterisk = false;

        try
        {
            const Reference< XDatabaseMetaData >  xMetaData = xConnection->getMetaData();
            const OUString aQuote = xMetaData->getIdentifierQuoteString();

            OJoinTableView::OTableWindowMap& rTabList = _pView->getTableView()->GetTabWinMap();

            for (auto const& field : _rFieldList)
            {
                OUString rFieldName = field->GetField();
                if ( !rFieldName.isEmpty() && field->IsVisible() )
                {
                    aTmpStr = "";
                    const OUString rAlias = field->GetAlias();
                    const OUString rFieldAlias = field->GetFieldAlias();

                    aTmpStr.append(quoteTableAlias((bAlias || bAsterisk),rAlias,aQuote));

                    // if we have a none numeric field, the table alias could be in the name
                    // otherwise we are not allowed to do this (e.g. 0.1 * PRICE )
                    if  ( !field->isOtherFunction() )
                    {
                        // we have to look if we have alias.* here but before we have to check if the column doesn't already exist
                        OTableFieldDescRef  aInfo = new OTableFieldDesc();
                        for (auto const& table : rTabList)
                        {
                            OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get());

                            if ( pTabWin->ExistsField( rFieldName, aInfo ) )
                            {
                                rFieldName = aInfo->GetField();
                                break;
                            }
                        }
                        if ( ( rFieldName.toChar() != '*' ) && ( rFieldName.indexOf( aQuote ) == -1 ) )
                        {
                            OSL_ENSURE(!field->GetTable().isEmpty(),"No table field name!");
                            aTmpStr.append(::dbtools::quoteName(aQuote, rFieldName));
                        }
                        else
                            aTmpStr.append(rFieldName);
                    }
                    else
                        aTmpStr.append(rFieldName);

                    if  ( field->isAggregateFunction() )
                    {
                        OSL_ENSURE(!field->GetFunction().isEmpty(),"Function name must not be empty! ;-(");
                        aTmpStr = field->GetFunction() + "(" + aTmpStr.makeStringAndClear() + ")";
                    }

                    if (!rFieldAlias.isEmpty()                         &&
                        (rFieldName.toChar() != '*'                     ||
                        field->isNumericOrAggregateFunction()      ||
                        field->isOtherFunction()))
                    {
                        aTmpStr.append(" AS " + ::dbtools::quoteName(aQuote, rFieldAlias));
                    }
                    aFieldListStr.append(aTmpStr);
                    aTmpStr.setLength(0);
                    aFieldListStr.append(", ");
                }
            }
            if(!aFieldListStr.isEmpty())
                aFieldListStr.setLength(aFieldListStr.getLength()-2);
        }
        catch(SQLException&)
        {
            OSL_FAIL("Failure while building select list!");
        }
        return aFieldListStr.makeStringAndClear();
    }
    bool GenerateCriterias( OQueryDesignView const * _pView,
                                OUStringBuffer& rRetStr,
                                OUStringBuffer& rHavingStr,
                                OTableFields& _rFieldList,
                                bool bMulti )
    {
        Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
        if(!xConnection.is())
            return false;

        OUString aFieldName,aCriteria,aWhereStr,aHavingStr,aWork/*,aOrderStr*/;
        // print line by line joined with AND
        sal_uInt16 nMaxCriteria = 0;
        for (auto const& field : _rFieldList)
        {
            nMaxCriteria = std::max<sal_uInt16>(nMaxCriteria,static_cast<sal_uInt16>(field->GetCriteria().size()));
        }
        try
        {
            const Reference< XDatabaseMetaData >  xMetaData = xConnection->getMetaData();
            const OUString aQuote = xMetaData->getIdentifierQuoteString();
            const IParseContext& rContext = static_cast<OQueryController&>(_pView->getController()).getParser().getContext();
            // * must not contain a filter : have I already shown the correct warning ?
            bool bCritsOnAsteriskWarning = false;        // ** TMFS **

            for (sal_uInt16 i=0 ; i < nMaxCriteria ; i++)
            {
                aHavingStr.clear();
                aWhereStr.clear();

                for (auto const& field : _rFieldList)
                {
                    aFieldName = field->GetField();

                    if (aFieldName.isEmpty())
                        continue;
                    aCriteria = field->GetCriteria( i );
                    if ( !aCriteria.isEmpty() )
                    {
                        // * is not allowed to contain any filter, only when used in combination an aggregate function
                        if ( aFieldName.toChar() == '*' && field->isNoneFunction() )
                        {
                            // only show the messagebox the first time
                            if (!bCritsOnAsteriskWarning)
                            {
                                std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(_pView->GetFrameWeld(),
                                                                          VclMessageType::Warning, VclButtonsType::Ok,
                                                                          DBA_RES(STR_QRY_CRITERIA_ON_ASTERISK)));
                                xBox->run();
                            }
                            bCritsOnAsteriskWarning = true;
                            continue;
                        }
                        aWork = quoteTableAlias(bMulti,field->GetAlias(),aQuote);

                        if ( (field->GetFunctionType() & (FKT_OTHER|FKT_NUMERIC)) || (aFieldName.toChar() == '*') )
                            aWork += aFieldName;
                        else
                            aWork += ::dbtools::quoteName(aQuote, aFieldName);

                        if ( field->isAggregateFunction() || field->IsGroupBy() )
                        {
                            if (aHavingStr.isEmpty())            // no more criteria
                                aHavingStr += "(";               // bracket
                            else
                                aHavingStr += C_AND;

                            if ( field->isAggregateFunction() )
                            {
                                OSL_ENSURE(!field->GetFunction().isEmpty(),"No function name for aggregate given!");
                                aHavingStr += field->GetFunction() + "(" + aWork + ")";       // bracket
                            }
                            else
                                aHavingStr += aWork;

                            OUString aErrorMsg;
                            Reference<XPropertySet> xColumn;
                            std::unique_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(field,aCriteria,aErrorMsg,xColumn));
                            if (pParseNode)
                            {
                                if (bMulti && !(field->isOtherFunction() || (aFieldName.toChar() == '*')))
                                    pParseNode->replaceNodeValue(field->GetAlias(),aFieldName);
                                OUString sHavingStr = aHavingStr;

                                sal_uInt32 nCount = pParseNode->count();
                                for( sal_uInt32 node = 1 ; node < nCount ; ++node)
                                    pParseNode->getChild(node)->parseNodeToStr( sHavingStr,
                                                                xConnection,
                                                                &rContext,
                                                                false,
                                                                !field->isOtherFunction());
                                aHavingStr = sHavingStr;
                            }
                            else
                                aHavingStr += aCriteria;
                        }
                        else
                        {
                            if ( aWhereStr.isEmpty() )           // no more criteria
                                aWhereStr += "(";                // bracket
                            else
                                aWhereStr += C_AND;

                            aWhereStr += " ";
                            // aCriteria could have some German numbers so I have to be sure here
                            OUString aErrorMsg;
                            Reference<XPropertySet> xColumn;
                            std::unique_ptr< ::connectivity::OSQLParseNode> pParseNode( _pView->getPredicateTreeFromEntry(field,aCriteria,aErrorMsg,xColumn));
                            if (pParseNode)
                            {
                                if (bMulti && !(field->isOtherFunction() || (aFieldName.toChar() == '*')))
                                    pParseNode->replaceNodeValue(field->GetAlias(),aFieldName);
                                OUString aWhere = aWhereStr;
                                pParseNode->parseNodeToStr( aWhere,
                                                            xConnection,
                                                            &rContext,
                                                            false,
                                                            !field->isOtherFunction() );
                                aWhereStr = aWhere;
                            }
                            else
                            {
                                aWhereStr += aWork + "=" + aCriteria;
                            }
                        }
                    }
                    // only once for each field
                    else if ( !i && field->isCondition() )
                    {
                        if (aWhereStr.isEmpty())         // no more criteria
                            aWhereStr += "(";            // bracket
                        else
                            aWhereStr += C_AND;
                        aWhereStr += field->GetField();
                    }
                }
                if (!aWhereStr.isEmpty())
                {
                    aWhereStr += ")";                          // close bracket for the AND branch
                    if (!rRetStr.isEmpty())                            // are there conditions on the field?
                        rRetStr.append(C_OR);
                    else                                        // open bracket for the OR branch
                        rRetStr.append('(');
                    rRetStr.append(aWhereStr);
                }
                if (!aHavingStr.isEmpty())
                {
                    aHavingStr +=  ")";                        // close bracket for the AND branch
                    if (!rHavingStr.isEmpty())                         // are there conditions on the field?
                        rHavingStr.append(C_OR);
                    else                                        // Open bracket for the OR branch
                        rHavingStr.append('(');
                    rHavingStr.append(aHavingStr);
                }
            }

            if (!rRetStr.isEmpty())
                rRetStr.append(')');                               // close bracket for the OR branch
            if (!rHavingStr.isEmpty())
                rHavingStr.append(')');                                // close bracket for the OR branch
        }
        catch(SQLException&)
        {
            OSL_FAIL("Failure while building where clause!");
        }
        return true;
    }
    SqlParseError GenerateOrder(    OQueryDesignView const * _pView,
                                    OTableFields& _rFieldList,
                                    bool bMulti,
                                    OUString& _rsRet)
    {
        const OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
        const Reference< XConnection>& xConnection = rController.getConnection();
        if ( !xConnection.is() )
            return eNoConnection;

        SqlParseError eErrorCode = eOk;

        OUString aColumnName;
        OUString aWorkStr;
        try
        {
            const bool bColumnAliasInOrderBy = rController.getSdbMetaData().supportsColumnAliasInOrderBy();
            Reference< XDatabaseMetaData >  xMetaData = xConnection->getMetaData();
            OUString aQuote = xMetaData->getIdentifierQuoteString();
            // * must not contain filter - have I already shown the warning?
            bool bCritsOnAsteriskWarning = false;        // ** TMFS **
            for (auto const& field : _rFieldList)
            {
                EOrderDir eOrder = field->GetOrderDir();
                // only create a sort expression when the table name and the sort criteria are defined
                // otherwise they will be built in GenerateCriteria
                if ( eOrder != ORDER_NONE )
                {
                    aColumnName = field->GetField();
                    if(aColumnName.toChar() == '*')
                    {
                        // only show the  MessageBox the first time
                        if (!bCritsOnAsteriskWarning)
                        {
                            std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(_pView->GetFrameWeld(),
                                                                      VclMessageType::Warning, VclButtonsType::Ok,
                                                                      DBA_RES(STR_QRY_ORDERBY_ON_ASTERISK)));
                            xBox->run();
                        }
                        bCritsOnAsteriskWarning = true;
                        continue;
                    }

                    if ( bColumnAliasInOrderBy && !field->GetFieldAlias().isEmpty() )
                    {
                        aWorkStr += ::dbtools::quoteName(aQuote, field->GetFieldAlias());
                    }
                    else if ( field->isNumericOrAggregateFunction() )
                    {
                        OSL_ENSURE(!field->GetFunction().isEmpty(),"Function name cannot be empty! ;-(");
                        aWorkStr += field->GetFunction() + "("
                            + quoteTableAlias(
                                bMulti, field->GetAlias(), aQuote);
                        // only quote column name when we don't have a numeric
                        if ( field->isNumeric() )
                            aWorkStr += aColumnName;
                        else
                            aWorkStr += ::dbtools::quoteName(aQuote, aColumnName);

                        aWorkStr += ")";
                    }
                    else if ( field->isOtherFunction() )
                    {
                        aWorkStr += aColumnName;
                    }
                    else
                    {
                        aWorkStr += quoteTableAlias(bMulti,field->GetAlias(),aQuote) + ::dbtools::quoteName(aQuote, aColumnName);
                    }
                    aWorkStr += OUString::Concat(" ") + o3tl::getToken( u";ASC;DESC"static_cast<sal_uInt16>(eOrder), ';' ) + ",";
                }
            }

            aWorkStr = comphelper::string::stripEnd(aWorkStr, ',');

            if ( !aWorkStr.isEmpty() )
            {
                const sal_Int32 nMaxOrder = xMetaData->getMaxColumnsInOrderBy();
                if ( nMaxOrder && nMaxOrder < comphelper::string::getTokenCount(aWorkStr, ',') )
                    eErrorCode = eStatementTooLong;
                else
                {
                    _rsRet = " ORDER BY " + aWorkStr;
                }
            }
        }
        catch(SQLException&)
        {
            OSL_FAIL("Failure while building group by!");
        }

        return eErrorCode;
    }

    void GenerateInnerJoinCriterias(const Reference< XConnection>& _xConnection,
                                    OUString& _rJoinCrit,
                                    const std::vector<VclPtr<OTableConnection> >& _rConnList)
    {
        for (auto const& connection : _rConnList)
        {
            const OQueryTableConnection* pEntryConn = static_cast<const OQueryTableConnection*>(connection.get());
            OQueryTableConnectionData* pEntryConnData = static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get());
            if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() )
            {
                if(!_rJoinCrit.isEmpty())
                    _rJoinCrit += C_AND;
                _rJoinCrit += BuildJoinCriteria(_xConnection,&pEntryConnData->GetConnLineDataList(),pEntryConnData);
            }
        }
    }
    void searchAndAppendName(const Reference< XConnection>& _xConnection,
                             const OQueryTableWindow* _pTableWindow,
                             std::set<OUString>& _rTableNames,
                             OUString& _rsTableListStr
                             )
    {
        OUString sTabName(BuildTable(_xConnection,_pTableWindow));

        if(_rTableNames.insert(sTabName).second)
        {
            _rsTableListStr += sTabName + ",";
        }
    }
    OUString GenerateFromClause( const Reference< XConnection>& _xConnection,
                                        const OQueryTableView::OTableWindowMap* pTabList,
                                        const std::vector<VclPtr<OTableConnection> >& rConnList
                                        )
    {

        OUString aTableListStr;
        // used to avoid putting a table twice in FROM clause
        std::set<OUString> aTableNames;

        // generate outer join clause in from
        if(!rConnList.empty())
        {
            std::map<OTableWindow*,sal_Int32> aConnectionCount;
            auto aEnd = rConnList.end();
            for (auto const& connection : rConnList)
            {
                static_cast<OQueryTableConnection*>(connection.get())->SetVisited(false);
                ++aConnectionCount[connection->GetSourceWin()];
                ++aConnectionCount[connection->GetDestWin()];
            }
            std::multimap<sal_Int32 , OTableWindow*> aMulti;
            for (auto const& elem : aConnectionCount)
            {
                aMulti.emplace(elem.second,elem.first);
            }

            const bool bUseEscape = ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_OUTERJOINESCAPE );
            std::multimap<sal_Int32 , OTableWindow*>::const_reverse_iterator aRIter = aMulti.rbegin();
            std::multimap<sal_Int32 , OTableWindow*>::const_reverse_iterator aREnd = aMulti.rend();
            for(;aRIter != aREnd;++aRIter)
            {
                auto aConIter = aRIter->second->getTableView()->getTableConnections(aRIter->second);
                for(;aConIter != aEnd;++aConIter)
                {
                    OQueryTableConnection* pEntryConn = static_cast<OQueryTableConnection*>((*aConIter).get());
                    if(!pEntryConn->IsVisited() && pEntryConn->GetSourceWin() == aRIter->second )
                    {
                        OUString aJoin;
                        GetNextJoin(_xConnection,
                                    pEntryConn,
                                    static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin()),
                                    aJoin,
                                    aTableNames);

                        if(!aJoin.isEmpty())
                        {
                            OUString aStr;
                            switch(static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get())->GetJoinType())
                            {
                                case LEFT_JOIN:
                                case RIGHT_JOIN:
                                case FULL_JOIN:
                                    {
                                        // create outer join
                                        if ( bUseEscape )
                                            aStr += "{ oj ";
                                        aStr += aJoin;
                                        if ( bUseEscape )
                                            aStr += " }";
                                    }
                                    break;
                                default:
                                    aStr += aJoin;
                                    break;
                            }
                            aStr += ",";
                            aTableListStr += aStr;
                        }
                    }
                }
            }

            // and now all inner joins
            // these are implemented as
            // "FROM tbl1, tbl2 WHERE tbl1.col1=tlb2.col2"
            // rather than
            // "FROM tbl1 INNER JOIN tbl2 ON tbl1.col1=tlb2.col2"
            for (auto const& connection : rConnList)
            {
                OQueryTableConnection* pEntryConn = static_cast<OQueryTableConnection*>(connection.get());
                if(!pEntryConn->IsVisited())
                {
                    searchAndAppendName(_xConnection,
                                        static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin()),
                                        aTableNames,
                                        aTableListStr);

                    searchAndAppendName(_xConnection,
                                        static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin()),
                                        aTableNames,
                                        aTableListStr);
                }
            }
        }
        // all tables that haven't a connection to anyone
        for (auto const& table : *pTabList)
        {
            const OQueryTableWindow* pEntryTab = static_cast<const OQueryTableWindow*>(table.second.get());
            if(!pEntryTab->ExistsAConn())
            {
                aTableListStr += BuildTable(_xConnection,pEntryTab) + ",";
            }
        }

        if(!aTableListStr.isEmpty())
            aTableListStr = aTableListStr.replaceAt(aTableListStr.getLength()-1,1, u"" );
        return aTableListStr;
    }
    OUString GenerateGroupBy(const OQueryDesignView* _pView,OTableFields& _rFieldList, bool bMulti )
    {
        OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
        const Reference< XConnection> xConnection = rController.getConnection();
        if(!xConnection.is())
            return OUString();

        std::map< OUString,bool> aGroupByNames;

        OUString aGroupByStr;
        try
        {
            const Reference< XDatabaseMetaData >  xMetaData = xConnection->getMetaData();
            const OUString aQuote = xMetaData->getIdentifierQuoteString();

            for (auto const& field : _rFieldList)
            {
                if ( field->IsGroupBy() )
                {
                    OSL_ENSURE(!field->GetField().isEmpty(),"No Field Name available!;-(");
                    OUString sGroupByPart = quoteTableAlias(bMulti,field->GetAlias(),aQuote);

                    // only quote the field name when it isn't calculated
                    if ( field->isNoneFunction() )
                    {
                        sGroupByPart += ::dbtools::quoteName(aQuote, field->GetField());
                    }
                    else
                    {
                        OUString aTmp = field->GetField();
                        OUString aErrorMsg;
                        Reference<XPropertySet> xColumn;
                        std::unique_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(field,aTmp,aErrorMsg,xColumn));
                        if (pParseNode)
                        {
                            OUString sGroupBy;
                            pParseNode->getChild(0)->parseNodeToStr(    sGroupBy,
                                                        xConnection,
                                                        &rController.getParser().getContext(),
                                                        false,
                                                        !field->isOtherFunction());
                            sGroupByPart += sGroupBy;
                        }
                        else
                            sGroupByPart += field->GetField();
                    }
                    if ( aGroupByNames.find(sGroupByPart) == aGroupByNames.end() )
                    {
                        aGroupByNames.emplace(sGroupByPart,true);
                        aGroupByStr += sGroupByPart + ",";
                    }
                }
            }
            if ( !aGroupByStr.isEmpty() )
            {
                aGroupByStr = aGroupByStr.replaceAt(aGroupByStr.getLength()-1,1, u" " );
                aGroupByStr = " GROUP BY " + aGroupByStr;
            }
        }
        catch(SQLException&)
        {
            OSL_FAIL("Failure while building group by!");
        }
        return aGroupByStr;
    }
    SqlParseError GetORCriteria(OQueryDesignView* _pView,
                                OSelectionBrowseBox* _pSelectionBrw,
                                const ::connectivity::OSQLParseNode * pCondition,
                                sal_uInt16& nLevel ,
                                bool bHaving = false,
                                bool bAddOrOnOneLine = false);
    SqlParseError GetSelectionCriteria( OQueryDesignView* _pView,
                                        OSelectionBrowseBox* _pSelectionBrw,
                                        const ::connectivity::OSQLParseNode* pNode,
                                        sal_uInt16& rLevel )
    {
        if (!pNode || !SQL_ISRULE(pNode, select_statement))
            return eNoSelectStatement;

        // nyi: more checking for the correct structure!
        pNode = pNode->getChild(3)->getChild(1);
        // no where clause found
        if (!pNode || pNode->isLeaf())
            return eOk;

        // Next free sentence...
        SqlParseError eErrorCode = eOk;
        ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1);
        if ( pCondition ) // no where clause
        {
            // now we have to check the other conditions
            // first make the logical easier
            ::connectivity::OSQLParseNode::negateSearchCondition(pCondition);
            ::connectivity::OSQLParseNode *pNodeTmp = pNode->getChild(1);

            ::connectivity::OSQLParseNode::disjunctiveNormalForm(pNodeTmp);
            pNodeTmp = pNode->getChild(1);
            ::connectivity::OSQLParseNode::absorptions(pNodeTmp);
            pNodeTmp = pNode->getChild(1);
            // compress sort the criteria @see https://bz.apache.org/ooo/show_bug.cgi?id=24079
            OSQLParseNode::compress(pNodeTmp);
            pNodeTmp = pNode->getChild(1);

            // first extract the inner joins conditions
            GetInnerJoinCriteria(_pView,pNodeTmp);
            // now simplify again, join are checked in ComparisonPredicate
            ::connectivity::OSQLParseNode::absorptions(pNodeTmp);
            pNodeTmp = pNode->getChild(1);

            // it could happen that pCondition is not more valid
            eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pNodeTmp, rLevel);
        }
        return eErrorCode;
    }
    SqlParseError GetANDCriteria(   OQueryDesignView* _pView,
                                    OSelectionBrowseBox* _pSelectionBrw,
                                    const  ::connectivity::OSQLParseNode * pCondition,
                                    sal_uInt16& nLevel,
                                    bool bHaving,
                                    bool bAddOrOnOneLine);
    SqlParseError ComparisonPredicate(OQueryDesignView const * _pView,
                            OSelectionBrowseBox* _pSelectionBrw,
                            const ::connectivity::OSQLParseNode * pCondition,
                            const sal_uInt16 nLevel,
                            bool bHaving,
                            bool bAddOrOnOneLine);
    SqlParseError GetORCriteria(OQueryDesignView* _pView,
                                OSelectionBrowseBox* _pSelectionBrw,
                                const ::connectivity::OSQLParseNode * pCondition,
                                sal_uInt16& nLevel ,
                                bool bHaving,
                                bool bAddOrOnOneLine)
    {
        SqlParseError eErrorCode = eOk;

        // round brackets around the printout
        if (pCondition->count() == 3 &&
            SQL_ISPUNCTUATION(pCondition->getChild(0),"(") &&
            SQL_ISPUNCTUATION(pCondition->getChild(2),")"))
        {
            eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pCondition->getChild(1),nLevel,bHaving,bAddOrOnOneLine);
        }
        // OR condition
        // a searchcondition can only look like this: search_condition SQL_TOKEN_OR boolean_term
        else if (SQL_ISRULE(pCondition,search_condition))
        {
            for (int i = 0; i < 3 && eErrorCode == eOk ; i+=2)
            {
                const  ::connectivity::OSQLParseNode* pChild = pCondition->getChild(i);
                if ( SQL_ISRULE(pChild,search_condition) )
                    eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pChild,nLevel,bHaving,bAddOrOnOneLine);
                else
                {
                    eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pChild, nLevel,bHaving, i != 0 && bAddOrOnOneLine);
                    if ( !bAddOrOnOneLine)
                        nLevel++;
                }
            }
        }
        else
            eErrorCode = GetANDCriteria( _pView,_pSelectionBrw,pCondition, nLevel, bHaving,bAddOrOnOneLine );

        return eErrorCode;
    }
    bool CheckOrCriteria(const ::connectivity::OSQLParseNode* _pCondition,::connectivity::OSQLParseNode* _pFirstColumnRef)
    {
        bool bRet = true;
        ::connectivity::OSQLParseNode* pFirstColumnRef = _pFirstColumnRef;
        for (size_t i = 0; bRet && i < _pCondition->count(); ++i)
        {
            const  ::connectivity::OSQLParseNode* pChild = _pCondition->getChild(i);
            if ( pChild->isToken() )
                continue;
            else if ( SQL_ISRULE(pChild,search_condition) )
                bRet = CheckOrCriteria(pChild,pFirstColumnRef);
            else
            {
                // this is a simple way to test columns are the same, may be we have to adjust this algo a little bit in future. :-)
                ::connectivity::OSQLParseNode* pSecondColumnRef = pChild->getByRule(::connectivity::OSQLParseNode::column_ref);
                if ( pFirstColumnRef && pSecondColumnRef )
                    bRet = *pFirstColumnRef == *pSecondColumnRef;
                else if ( !pFirstColumnRef )
                    pFirstColumnRef = pSecondColumnRef;
            }
        }
        return bRet;
    }
    SqlParseError GetANDCriteria(   OQueryDesignView* _pView,
                                    OSelectionBrowseBox* _pSelectionBrw,
                                    const  ::connectivity::OSQLParseNode * pCondition,
                                    sal_uInt16& nLevel,
                                    bool bHaving,
                                    bool bAddOrOnOneLine)
    {
        const css::lang::Locale    aLocale = _pView->getLocale();
        const OUString sDecimal = _pView->getDecimalSeparator();

        // I will need a cast pointer to my css::sdbcx::Container
        OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
        SqlParseError eErrorCode = eOk;

        // round brackets
        if (SQL_ISRULE(pCondition,boolean_primary))
        {
            // check if we have to put the or criteria on one line.
            const  ::connectivity::OSQLParseNode* pSearchCondition = pCondition->getChild(1);
            bool bMustAddOrOnOneLine = CheckOrCriteria(pSearchCondition,nullptr);
            if ( SQL_ISRULE( pSearchCondition, search_condition) ) // we have a or
            {
                _pSelectionBrw->DuplicateConditionLevel( nLevel);
                eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(0), nLevel,bHaving,bMustAddOrOnOneLine );
                if ( eErrorCode == eOk )
                {
                    ++nLevel;
                    eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(2), nLevel,bHaving,bMustAddOrOnOneLine );
                }
            }
            else
                eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition, nLevel,bHaving,bMustAddOrOnOneLine );
        }
        // The first element is (again) an AND condition
        else if ( SQL_ISRULE(pCondition,boolean_term) )
        {
            OSL_ENSURE(pCondition->count() == 3,"Illegal definition of boolean_term");
            eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pCondition->getChild(0), nLevel,bHaving,bAddOrOnOneLine );
            if ( eErrorCode == eOk )
                eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pCondition->getChild(2), nLevel,bHaving,bAddOrOnOneLine );
        }
        else if (SQL_ISRULE( pCondition, comparison_predicate))
        {
            eErrorCode = ComparisonPredicate(_pView,_pSelectionBrw,pCondition,nLevel,bHaving,bAddOrOnOneLine);
        }
        else if( SQL_ISRULE(pCondition,like_predicate) )
        {
            const  ::connectivity::OSQLParseNode* pValueExp = pCondition->getChild(0);
            if (SQL_ISRULE(pValueExp, column_ref ) )
            {
                OUString aCondition;
                Reference< XConnection> xConnection = rController.getConnection();
                if ( xConnection.is() )
                {
                    OUString aColumnName;
                    // the international doesn't matter I have a string
                    pCondition->parseNodeToPredicateStr(aCondition,
                                                        xConnection,
                                                        rController.getNumberFormatter(),
                                                        aLocale,
                                                        sDecimal,
                                                        &rController.getParser().getContext());

                    pValueExp->parseNodeToPredicateStr( aColumnName,
                                                        xConnection,
                                                        rController.getNumberFormatter(),
                                                        aLocale,
                                                        sDecimal,
                                                        &rController.getParser().getContext());

                    // don't display the column name
                    aCondition = aCondition.copy(aColumnName.getLength());
                    aCondition = aCondition.trim();
                }

                OTableFieldDescRef aDragLeft = new OTableFieldDesc();
                if ( eOk == ( eErrorCode = FillDragInfo(_pView,pValueExp,aDragLeft) ))
                {
                    if ( bHaving )
                        aDragLeft->SetGroupBy(true);
                    _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
                }
            }
            else if(SQL_ISRULEOR3(pValueExp, general_set_fct, set_fct_spec, position_exp)  ||
                      SQL_ISRULEOR3(pValueExp, extract_exp, fold, char_substring_fct)       ||
                      SQL_ISRULEOR2(pValueExp, length_exp, char_value_fct))
            {
                AddFunctionCondition(   _pView,
                                        _pSelectionBrw,
                                        pCondition,
                                        nLevel,
                                        bHaving,
                                        bAddOrOnOneLine);
            }
            else
            {
                eErrorCode = eNoColumnInLike;
                OUString sError(DBA_RES(STR_QRY_LIKE_LEFT_NO_COLUMN));
                _pView->getController().appendError( sError );
            }
        }
        else if(    SQL_ISRULEOR2(pCondition,test_for_null,in_predicate)
                ||  SQL_ISRULEOR2(pCondition,all_or_any_predicate,between_predicate))
        {
            if ( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , general_set_fct ) )
            {
                AddFunctionCondition(   _pView,
                                        _pSelectionBrw,
                                        pCondition,
                                        nLevel,
                                        bHaving,
                                        bAddOrOnOneLine);
            }
            else if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) )
            {
                // parse condition
                OUString sCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,1);
                OTableFieldDescRef  aDragLeft = new OTableFieldDesc();
                if ( eOk == ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(0),aDragLeft)) )
                {
                    if ( bHaving )
                        aDragLeft->SetGroupBy(true);
                    _pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine);
                }
            }
            else
            {
                // Parse the function condition
                OUString sCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,1);
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=91 H=95 G=92

¤ Dauer der Verarbeitung: 0.18 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.