/**************************************************************
 * 
 * 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
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dbaccess.hxx"
#ifndef DBAUI_QUERYDESIGNVIEW_HXX
#include "QueryDesignView.hxx"
#endif
#ifndef DBAUI_QUERYTABLEVIEW_HXX
#include "QueryTableView.hxx"
#endif
#ifndef DBAUI_QUERY_TABLEWINDOW_HXX
#include "QTableWindow.hxx"
#endif
#ifndef _SV_TOOLBOX_HXX
#include <vcl/toolbox.hxx>
#endif
#ifndef DBAUI_QUERYCONTROLLER_HXX
#include "querycontroller.hxx"
#endif
#ifndef _SV_SPLIT_HXX
#include <vcl/split.hxx>
#endif
#ifndef _UNDO_HXX
#include <svl/undo.hxx>
#endif
#ifndef TOOLS_DIAGNOSE_EX_H
#include <tools/diagnose_ex.h>
#endif
#ifndef DBAUI_QYDLGTAB_HXX
#include "adtabdlg.hxx"
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _SV_COMBOBOX_HXX
#include <vcl/combobox.hxx>
#endif
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif
#ifndef DBACCESS_UI_BROWSER_ID_HXX
#include "browserids.hxx"
#endif
#ifndef DBAUI_QUERYDESIGN_OSELECTIONBROWSEBOX_HXX
#include "SelectionBrowseBox.hxx"
#endif
#ifndef _DBU_QRY_HRC_
#include "dbu_qry.hrc"
#endif
#ifndef _UTL_CONFIGMGR_HXX_
#include <unotools/configmgr.hxx>
#endif
#ifndef _COMPHELPER_TYPES_HXX_
#include <comphelper/types.hxx>
#endif
#ifndef _CONNECTIVITY_DBTOOLS_HXX_
#include <connectivity/dbtools.hxx>
#endif
#ifndef _DBHELPER_DBEXCEPTION_HXX_
#include <connectivity/dbexception.hxx>
#endif
#ifndef _COM_SUN_STAR_I18N_XLOCALEDATA_HPP_
#include <com/sun/star/i18n/XLocaleData.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_DATATYPE_HPP_
#include <com/sun/star/sdbc/DataType.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_
#include <com/sun/star/container/XNameAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_COLUMNVALUE_HPP_
#include <com/sun/star/sdbc/ColumnValue.hpp>
#endif
#ifndef _CONNECTIVITY_PCOLUMN_HXX_
#include <connectivity/PColumn.hxx>
#endif
#ifndef DBAUI_QUERYTABLECONNECTION_HXX
#include "QTableConnection.hxx"
#endif
#ifndef DBAUI_CONNECTIONLINE_HXX
#include "ConnectionLine.hxx"
#endif
#ifndef DBAUI_CONNECTIONLINEDATA_HXX
#include "ConnectionLineData.hxx"
#endif
#ifndef DBAUI_QTABLECONNECTIONDATA_HXX
#include "QTableConnectionData.hxx"
#endif
#ifndef DBACCESS_SHARED_DBUSTRINGS_HRC
#include "dbustrings.hrc"
#endif
#ifndef _COMPHELPER_EXTRACT_HXX_
#include <comphelper/extract.hxx>
#endif
#ifndef DBAUI_TOOLS_HXX
#include "UITools.hxx"
#endif
#ifndef DBAUI_QUERYCONTAINERWINDOW_HXX
#include "querycontainerwindow.hxx"
#endif
#ifndef DBAUI_QUERYTABLEVIEW_HXX
#include "QueryTableView.hxx"
#endif
#ifndef _DBAUI_SQLMESSAGE_HXX_
#include "sqlmessage.hxx"
#endif
#ifndef INCLUDED_SVTOOLS_SYSLOCALE_HXX
#include <unotools/syslocale.hxx>
#endif

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

#define SQL_ISRULEOR2(pParseNode, e1,e2) 	((pParseNode)->isRule() && (\
											(pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e1) || \
											(pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e2)))

// 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
{
	static const ::rtl::OUString C_AND = ::rtl::OUString::createFromAscii(" AND ");
	static const ::rtl::OUString C_OR  = ::rtl::OUString::createFromAscii(" OR ");

	// forward declarations
	sal_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* _pView,
									OSelectionBrowseBox* _pSelectionBrw,
									const ::connectivity::OSQLParseNode * pCondition,
									const sal_uInt16 nLevel,
									sal_Bool bHaving,
                                    bool _bAddOrOnOneLine);

	//------------------------------------------------------------------------------
	::rtl::OUString quoteTableAlias(sal_Bool _bQuote, const ::rtl::OUString& _sAliasName, const ::rtl::OUString& _sQuote)
	{
		::rtl::OUString sRet;
		if ( _bQuote && _sAliasName.getLength() )
		{
			sRet = ::dbtools::quoteName(_sQuote,_sAliasName);
			const static ::rtl::OUString sTableSeparater('.');
			sRet += sTableSeparater;
		}
		return sRet;
	}
    //------------------------------------------------------------------------------
    ::rtl::OUString getTableRange(const OQueryDesignView* _pView,const ::connectivity::OSQLParseNode* _pTableRef)
    {
        Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
        ::rtl::OUString sTableRange;
        if ( _pTableRef )
        {
            sTableRange = ::connectivity::OSQLParseNode::getTableRange(_pTableRef);
            if ( !sTableRange.getLength() )
                _pTableRef->parseNodeToStr(sTableRange,xConnection,NULL,sal_False,sal_False);
        }
        return sTableRange;
    }
    //------------------------------------------------------------------------------
    void insertConnection(const OQueryDesignView* _pView,const EJoinType& _eJoinType,OTableFieldDescRef _aDragLeft,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 )
		{
			OQueryTableConnectionData* pInfoData = new OQueryTableConnectionData();
            TTableConnectionData::value_type aInfoData(pInfoData);
			pInfoData->InitFromDrag(_aDragLeft, _aDragRight);
			pInfoData->SetJoinType(_eJoinType);

            if ( _bNatural )
            {
                aInfoData->ResetConnLines();
                pInfoData->setNatural(_bNatural);
                try
                {
                    Reference<XNameAccess> xReferencedTableColumns(aInfoData->getReferencedTable()->getColumns());
                    Sequence< ::rtl::OUString> aSeq = aInfoData->getReferencingTable()->getColumns()->getElementNames();
                    const ::rtl::OUString* pIter = aSeq.getConstArray();
                    const ::rtl::OUString* pEnd	  = pIter + aSeq.getLength();
                    for(;pIter != pEnd;++pIter)
                    {
                        if ( xReferencedTableColumns->hasByName(*pIter) )
                            aInfoData->AppendConnLine(*pIter,*pIter);
                    }            
                }
                catch( const Exception& )
                {
                    DBG_UNHANDLED_EXCEPTION();
                }
            }

			OQueryTableConnection aInfo(pTableView, aInfoData);
			// da ein OQueryTableConnection-Objekt nie den Besitz der uebergebenen Daten uebernimmt, sondern sich nur den Zeiger merkt,
			// ist dieser Zeiger auf eine lokale Variable hier unkritisch, denn aInfoData und aInfo haben die selbe Lebensdauer
			pTableView->NotifyTabConnection( aInfo );
		}
		else
		{
			::rtl::OUString aSourceFieldName(_aDragLeft->GetField());
			::rtl::OUString aDestFieldName(_aDragRight->GetField());
			// the connection could point on the other side
			if(pConn->GetSourceWin() == _aDragRight->GetTabWindow())
			{
				::rtl::OUString aTmp(aSourceFieldName);
				aSourceFieldName = aDestFieldName;
				aDestFieldName = aTmp;
			}
			pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName);
			pConn->UpdateLineList();
			// Modified-Flag
			//	SetModified();
			// und neu zeichnen
			pConn->RecalcLines();
				// fuer das unten folgende Invalidate muss ich dieser neuen Connection erst mal die Moeglichkeit geben,
				// ihr BoundingRect zu ermitteln
			pConn->InvalidateConnection();
		}
    }
	//------------------------------------------------------------------------------
	::rtl::OUString ParseCondition(	OQueryController& rController
									,const ::connectivity::OSQLParseNode* pCondition
									,const ::rtl::OUString _sDecimal
									,const ::com::sun::star::lang::Locale& _rLocale
									,sal_uInt32 _nStartIndex)
	{
		::rtl::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,
								static_cast<sal_Char>(_sDecimal.toChar()),
								&rController.getParser().getContext());
		}
		return aCondition;
	}
	//------------------------------------------------------------------------------
	SqlParseError FillOuterJoins(OQueryDesignView* _pView,
								const ::connectivity::OSQLParseNode* pTableRefList)
	{
		SqlParseError eErrorCode = eOk;
		sal_uInt32 nCount = pTableRefList->count();
		sal_Bool bError = sal_False;
		for (sal_uInt32 i=0; !bError && i < nCount; ++i)
		{
			const ::connectivity::OSQLParseNode* pParseNode = pTableRefList->getChild(i);
			const ::connectivity::OSQLParseNode* pJoinNode = NULL;

			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 = sal_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& _rDragInfo)
	{
		SqlParseError eErrorCode = eOk;

		sal_Bool bErg = sal_False;

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

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

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

		return eErrorCode;
	}
	//------------------------------------------------------------------------------
	::rtl::OUString BuildJoinCriteria(	const Reference< XConnection>& _xConnection,
										OConnectionLineDataVec* pLineDataList,
										OQueryTableConnectionData* pData)
	{
		::rtl::OUStringBuffer aCondition;
		if ( _xConnection.is() )
        {
		    OConnectionLineDataVec::iterator aIter = pLineDataList->begin();
            OConnectionLineDataVec::iterator aEnd = pLineDataList->end();
		    try
		    {
			    const Reference< XDatabaseMetaData >  xMetaData = _xConnection->getMetaData();
			    const ::rtl::OUString aQuote = xMetaData->getIdentifierQuoteString();
                const ::rtl::OUString sEqual(RTL_CONSTASCII_USTRINGPARAM(" = "));

			    for(;aIter != aEnd;++aIter)
			    {
				    OConnectionLineDataRef pLineData = *aIter;
				    if(aCondition.getLength())
					    aCondition.append(C_AND);
				    aCondition.append(quoteTableAlias(sal_True,pData->GetAliasName(JTCS_FROM),aQuote));
				    aCondition.append(::dbtools::quoteName(aQuote, pLineData->GetFieldName(JTCS_FROM) ));
				    aCondition.append(sEqual);
				    aCondition.append(quoteTableAlias(sal_True,pData->GetAliasName(JTCS_TO),aQuote));
				    aCondition.append(::dbtools::quoteName(aQuote, pLineData->GetFieldName(JTCS_TO) ));
			    }
		    }
		    catch(SQLException&)
		    {
			    OSL_ASSERT(!"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,
					::rtl::OUString& _rJoin )
	{
		OSL_ENSURE(_pEntryConn,"TableConnection can not be null!");

		OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pEntryConn->GetData().get());
		if ( pData->GetJoinType() != INNER_JOIN && _pEntryTabTo->ExistsAVisitedConn() )
		{
			sal_Bool bBrace = sal_False;
			if(_rJoin.getLength() && _rJoin.lastIndexOf(')') == (_rJoin.getLength()-1))
			{
				bBrace = sal_True;
				_rJoin = _rJoin.replaceAt(_rJoin.getLength()-1,1,::rtl::OUString(' '));
			}
			(_rJoin += C_AND) += BuildJoinCriteria(_xConnection,pData->GetConnLineDataList(),pData);
			if(bBrace)
				_rJoin += ::rtl::OUString(')');
			_pEntryConn->SetVisited(sal_True);
		}
	}
	//------------------------------------------------------------------------------
	::rtl::OUString BuildTable(	const Reference< XConnection>& _xConnection,
								const OQueryTableWindow* pEntryTab,
                                bool _bForce = false
								)
	{
		::rtl::OUString aDBName(pEntryTab->GetComposedName());

		//	Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
		if( _xConnection.is() )
		{
			try
			{
				Reference< XDatabaseMetaData >  xMetaData = _xConnection->getMetaData();

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

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

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

		return aErg;
	}
	//------------------------------------------------------------------------------
	::rtl::OUString BuildJoin(	const Reference< XConnection>& _xConnection,
								OQueryTableWindow* pLh,
								OQueryTableWindow* pRh,
								OQueryTableConnectionData* pData
								)
	{
        bool bForce = pData->GetJoinType() == CROSS_JOIN || pData->isNatural();
		return BuildJoin(_xConnection,BuildTable(_xConnection,pLh,bForce),BuildTable(_xConnection,pRh,bForce),pData);
	}
	//------------------------------------------------------------------------------
	::rtl::OUString BuildJoin(	const Reference< XConnection>& _xConnection,
								const ::rtl::OUString &rLh,
								OQueryTableWindow* pRh,
								OQueryTableConnectionData* pData
								)
	{
		return BuildJoin(_xConnection,rLh,BuildTable(_xConnection,pRh),pData);
	}
	//------------------------------------------------------------------------------
	::rtl::OUString BuildJoin(	const Reference< XConnection>& _xConnection,
								OQueryTableWindow* pLh,
								const ::rtl::OUString &rRh,
								OQueryTableConnectionData* pData
								)
	{
		return BuildJoin(_xConnection,BuildTable(_xConnection,pLh),rRh,pData);
	}
	//------------------------------------------------------------------------------
	void GetNextJoin(	const Reference< XConnection>& _xConnection,
						OQueryTableConnection* pEntryConn,
						OQueryTableWindow* pEntryTabTo,
						::rtl::OUString &aJoin)
	{
		OQueryTableConnectionData* pEntryConnData = static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get());
        if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() )
			return;

		//	Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();

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

		pEntryConn->SetVisited(sal_True);

		// first search for the "to" window
		const ::std::vector<OTableConnection*>* pConnections = pEntryConn->GetParent()->getTableConnections();
		::std::vector<OTableConnection*>::const_iterator aIter = pConnections->begin();
        ::std::vector<OTableConnection*>::const_iterator aEnd = pConnections->end();
		for(;aIter != aEnd;++aIter)
		{
			OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(*aIter);
			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);
			}
		}

		// when nothing found found look for the "from" window
		if(aIter == aEnd)
		{
			OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
			aIter = pConnections->begin();
			for(;aIter != aEnd;++aIter)
			{
				OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(*aIter);
				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);
				}
			}
		}
	}
	//------------------------------------------------------------------------------
	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 &&	// Ausdruck is geklammert
			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-Verknuepfung:
				 pNode->count() == 3)
		{
			// nur AND Verknüpfung zulassen
			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
			DBG_ASSERT(pNode->count() == 3,"OQueryDesignView::InsertJoinConnection: Fehler im Parse Tree");
			if (!(SQL_ISRULE(pNode->getChild(0),column_ref) &&
				  SQL_ISRULE(pNode->getChild(2),column_ref) &&
				   pNode->getChild(1)->getNodeType() == SQL_NODE_EQUAL))
			{
				String sError(ModuleRes(STR_QRY_JOIN_COLUMN_COMPARE));
				_pView->getController().appendError( sError );
				return eIllegalJoin;
			}

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

            if ( pLeftTable )
            {
                OQueryTableWindow*	pLeftWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pLeftTable->getByRule(OSQLParseNode::table_ref) ));
                // OQueryTableWindow*	pRightWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pRightTable->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;
	}
	//------------------------------------------------------------------------------
	sal_Bool GetInnerJoinCriteria(	const OQueryDesignView* _pView,
									const ::connectivity::OSQLParseNode *pCondition)
	{
		return InsertJoinConnection(_pView,pCondition, INNER_JOIN,NULL,NULL) != eOk;
	}
	//------------------------------------------------------------------------------
	::rtl::OUString GenerateSelectList(	const OQueryDesignView* _pView,
										OTableFields&	_rFieldList,
										sal_Bool bAlias)
	{
        Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
		if ( !xConnection.is() )
			return ::rtl::OUString();

		::rtl::OUStringBuffer aTmpStr,aFieldListStr;

		sal_Bool bAsterix = sal_False;
		int nVis = 0;
		OTableFields::iterator aIter = _rFieldList.begin();
        OTableFields::iterator aEnd = _rFieldList.end();
		for(;aIter != aEnd;++aIter)
		{
			OTableFieldDescRef pEntryField = *aIter;
			if ( pEntryField->IsVisible() )
			{
				if ( pEntryField->GetField().toChar() == '*' )
					bAsterix = sal_True;
				++nVis;
			}
		}
		if(nVis == 1)
			bAsterix = sal_False;

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

			OJoinTableView::OTableWindowMap* pTabList = _pView->getTableView()->GetTabWinMap();

			const static ::rtl::OUString sFieldSeparator(RTL_CONSTASCII_USTRINGPARAM(", "));
            const static ::rtl::OUString s_sAs(RTL_CONSTASCII_USTRINGPARAM(" AS "));

			aIter = _rFieldList.begin();
		    for(;aIter != aEnd;++aIter)
			{
				OTableFieldDescRef pEntryField = *aIter;
				::rtl::OUString rFieldName = pEntryField->GetField();
				if ( rFieldName.getLength() && pEntryField->IsVisible() )
				{
					aTmpStr = ::rtl::OUString();
					const ::rtl::OUString rAlias = pEntryField->GetAlias();
					const ::rtl::OUString rFieldAlias = pEntryField->GetFieldAlias();

					aTmpStr.append(quoteTableAlias((bAlias || bAsterix),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  ( !pEntryField->isOtherFunction() )
					{
						// we have to look if we have alias.* here but before we have to check if the column doesn't already exist
						String sTemp = rFieldName;
						OTableFieldDescRef	aInfo = new OTableFieldDesc();
						OJoinTableView::OTableWindowMap::iterator tableIter = pTabList->begin();
                        OJoinTableView::OTableWindowMap::iterator tableEnd = pTabList->end();
						sal_Bool bFound = sal_False;
						for(;!bFound && tableIter != tableEnd ;++tableIter)
						{
							OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(tableIter->second);

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

					if  ( pEntryField->isAggreateFunction() )
					{
						DBG_ASSERT(pEntryField->GetFunction().getLength(),"Functionname darf hier nicht leer sein! ;-(");
						::rtl::OUStringBuffer aTmpStr2( pEntryField->GetFunction());
						aTmpStr2.appendAscii("(");
						aTmpStr2.append(aTmpStr.makeStringAndClear());
						aTmpStr2.appendAscii(")");
						aTmpStr = aTmpStr2;
					}

					if (rFieldAlias.getLength()							&&
						(rFieldName.toChar() != '*'						||
						pEntryField->isNumericOrAggreateFunction()		||
						pEntryField->isOtherFunction()))
					{
						aTmpStr.append(s_sAs);
						aTmpStr.append(::dbtools::quoteName(aQuote, rFieldAlias));
					}
					aFieldListStr.append(aTmpStr.makeStringAndClear());
					aFieldListStr.append(sFieldSeparator);
				}
			}
			if(aFieldListStr.getLength())
				aFieldListStr.setLength(aFieldListStr.getLength()-2);
		}
		catch(SQLException&)
		{
			OSL_ASSERT(!"Failure while building select list!");
		}
		return aFieldListStr.makeStringAndClear();
	}
	//------------------------------------------------------------------------------
	sal_Bool GenerateCriterias(	OQueryDesignView* _pView,
								::rtl::OUStringBuffer& rRetStr,
								::rtl::OUStringBuffer& rHavingStr,
								OTableFields& _rFieldList,
								sal_Bool bMulti )
	{
		// * darf keine Filter enthalten : habe ich die entsprechende Warnung schon angezeigt ?
		sal_Bool bCritsOnAsterikWarning = sal_False;		// ** TMFS **

		::rtl::OUString aFieldName,aCriteria,aWhereStr,aHavingStr,aWork/*,aOrderStr*/;
		// Zeilenweise werden die Ausdr"ucke mit AND verknuepft
		sal_uInt16 nMaxCriteria = 0;
		OTableFields::iterator aIter = _rFieldList.begin();
		OTableFields::iterator aEnd = _rFieldList.end();
		for(;aIter != aEnd;++aIter)
		{
			nMaxCriteria = ::std::max<sal_uInt16>(nMaxCriteria,(sal_uInt16)(*aIter)->GetCriteria().size());
		}
		Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
		if(!xConnection.is())
			return sal_False;
		try
		{
			const Reference< XDatabaseMetaData >  xMetaData = xConnection->getMetaData();
			const ::rtl::OUString aQuote = xMetaData->getIdentifierQuoteString();
			const IParseContext& rContext = static_cast<OQueryController&>(_pView->getController()).getParser().getContext();

			for (sal_uInt16 i=0 ; i < nMaxCriteria ; i++)
			{
				aHavingStr = aWhereStr = ::rtl::OUString();

				for(aIter = _rFieldList.begin();aIter != aEnd;++aIter)
				{
					OTableFieldDescRef	pEntryField = *aIter;
					aFieldName = pEntryField->GetField();

					if (!aFieldName.getLength())
						continue;
					aCriteria = pEntryField->GetCriteria( i );
					if ( aCriteria.getLength() )
					{
						// * is not allowed to contain any filter, only when used in combination an aggregate function
						if ( aFieldName.toChar() == '*' && pEntryField->isNoneFunction() )
						{
							// only show the messagebox the first time
							if (!bCritsOnAsterikWarning)
								ErrorBox(_pView, ModuleRes( ERR_QRY_CRITERIA_ON_ASTERISK)).Execute();
							bCritsOnAsterikWarning = sal_True;
							continue;
						}
						aWork = ::rtl::OUString();


						aWork += quoteTableAlias(bMulti,pEntryField->GetAlias(),aQuote);

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

						if ( pEntryField->isAggreateFunction() || pEntryField->IsGroupBy() )
						{
							if (!aHavingStr.getLength())			// noch keine Kriterien
								aHavingStr += ::rtl::OUString('(');			// Klammern
							else
								aHavingStr += C_AND;

							if ( pEntryField->isAggreateFunction() )
							{
								OSL_ENSURE(pEntryField->GetFunction().getLength(),"No function name for aggregate given!");
								aHavingStr += pEntryField->GetFunction();
								aHavingStr += ::rtl::OUString('(');			// Klammern
								aHavingStr += aWork;
								aHavingStr += ::rtl::OUString(')');			// Klammern
							}
							else
								aHavingStr += aWork;

							::rtl::OUString aTmp = aCriteria;
							::rtl::OUString aErrorMsg;
							Reference<XPropertySet> xColumn;
                            ::std::auto_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(pEntryField,aTmp,aErrorMsg,xColumn));
							if (pParseNode.get())
							{
								if (bMulti && !(pEntryField->isOtherFunction() || (aFieldName.toChar() == '*')))
									pParseNode->replaceNodeValue(pEntryField->GetAlias(),aFieldName);
								::rtl::OUString sHavingStr = aHavingStr;
								
								sal_uInt32 nCount = pParseNode->count();
								for( sal_uInt32 node = 1 ; node < nCount ; ++node)
									pParseNode->getChild(node)->parseNodeToStr(	sHavingStr,
																xConnection,
																&rContext,
																sal_False,
																!pEntryField->isOtherFunction());
								aHavingStr = sHavingStr;
							}
							else
								aHavingStr += aCriteria;
						}
						else
						{
							if ( !aWhereStr.getLength() )			// noch keine Kriterien
								aWhereStr += ::rtl::OUString('(');			// Klammern
							else
								aWhereStr += C_AND;

							aWhereStr += ::rtl::OUString(' ');
							// aCriteria could have some german numbers so I have to be sure here
							::rtl::OUString aTmp = aCriteria;
							::rtl::OUString aErrorMsg;
							Reference<XPropertySet> xColumn;
							::std::auto_ptr< ::connectivity::OSQLParseNode> pParseNode( _pView->getPredicateTreeFromEntry(pEntryField,aTmp,aErrorMsg,xColumn));
							if (pParseNode.get())
							{
								if (bMulti && !(pEntryField->isOtherFunction() || (aFieldName.toChar() == '*')))
									pParseNode->replaceNodeValue(pEntryField->GetAlias(),aFieldName);
								::rtl::OUString aWhere = aWhereStr;
								pParseNode->parseNodeToStr(	aWhere,
															xConnection,
															&rContext,
															sal_False,
															!pEntryField->isOtherFunction() );
								aWhereStr = aWhere;
							}
							else
							{
								aWhereStr += aWork;
								aWhereStr += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("="));
								aWhereStr += aCriteria;
							}
						}
					}
					// nur einmal für jedes Feld
					else if ( !i && pEntryField->isCondition() )
					{
						if (!aWhereStr.getLength())			// noch keine Kriterien
							aWhereStr += ::rtl::OUString('(');			// Klammern
						else
							aWhereStr += C_AND;
						aWhereStr += pEntryField->GetField();
					}
				}
				if (aWhereStr.getLength())
				{
					aWhereStr += ::rtl::OUString(')');						// Klammern zu fuer 'AND' Zweig
					if (rRetStr.getLength())							// schon Feldbedingungen ?
						rRetStr.append(C_OR);
					else										// Klammern auf fuer 'OR' Zweig
						rRetStr.append(sal_Unicode('('));
					rRetStr.append(aWhereStr);
				}
				if (aHavingStr.getLength())
				{
					aHavingStr += ::rtl::OUString(')');						// Klammern zu fuer 'AND' Zweig
					if (rHavingStr.getLength())							// schon Feldbedingungen ?
						rHavingStr.append(C_OR);
					else										// Klammern auf fuer 'OR' Zweig
						rHavingStr.append(sal_Unicode('('));
					rHavingStr.append(aHavingStr);
				}
			}

			if (rRetStr.getLength())
				rRetStr.append(sal_Unicode(')'));								// Klammern zu fuer 'OR' Zweig
			if (rHavingStr.getLength())
				rHavingStr.append(sal_Unicode(')'));								// Klammern zu fuer 'OR' Zweig
		}
		catch(SQLException&)
		{
			OSL_ASSERT(!"Failure while building where clause!");
		}
		return sal_True;
	}
	//------------------------------------------------------------------------------
	SqlParseError GenerateOrder(	OQueryDesignView* _pView,
									OTableFields& _rFieldList,
									sal_Bool bMulti,
									::rtl::OUString& _rsRet)
	{
        const OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
		Reference< XConnection> xConnection = rController.getConnection();
		if ( !xConnection.is() )
			return eNoConnection;

		SqlParseError eErrorCode = eOk;

		::rtl::OUString aColumnName;
		::rtl::OUString aWorkStr;
		try
		{
            const bool bColumnAliasInOrderBy = rController.getSdbMetaData().supportsColumnAliasInOrderBy();
			Reference< XDatabaseMetaData >  xMetaData = xConnection->getMetaData();
			::rtl::OUString aQuote = xMetaData->getIdentifierQuoteString();
			// * darf keine Filter enthalten : habe ich die entsprechende Warnung schon angezeigt ?
			sal_Bool bCritsOnAsterikWarning = sal_False;		// ** TMFS **
			OTableFields::iterator aIter = _rFieldList.begin();
			OTableFields::iterator aEnd = _rFieldList.end();
		    for(;aIter != aEnd;++aIter)
			{
				OTableFieldDescRef	pEntryField = *aIter;
				EOrderDir eOrder = pEntryField->GetOrderDir();

				// nur wenn eine Sortierung und ein Tabellenname vorhanden ist-> erzeugen
				// sonst werden die Expressions vom Order By im GenerateCriteria mit erzeugt
				if ( eOrder != ORDER_NONE )
				{
					aColumnName = pEntryField->GetField();
					if(aColumnName.toChar() == '*')
					{
						// die entsprechende MessageBox nur beim ersten mal anzeigen
						if (!bCritsOnAsterikWarning)
							ErrorBox(_pView, ModuleRes( ERR_QRY_ORDERBY_ON_ASTERISK)).Execute();
						bCritsOnAsterikWarning = sal_True;
						continue;
					}

					if ( bColumnAliasInOrderBy && pEntryField->GetFieldAlias().getLength() )
					{
						aWorkStr += ::dbtools::quoteName(aQuote, pEntryField->GetFieldAlias());
					}
					else if ( pEntryField->isNumericOrAggreateFunction() )
					{
						DBG_ASSERT(pEntryField->GetFunction().getLength(),"Functionname darf hier nicht leer sein! ;-(");
						aWorkStr += pEntryField->GetFunction();
						aWorkStr +=  ::rtl::OUString('(');
						aWorkStr += quoteTableAlias(bMulti,pEntryField->GetAlias(),aQuote);
						// only quote column name when we don't have a numeric
						if ( pEntryField->isNumeric() )
							aWorkStr += aColumnName;
						else
							aWorkStr += ::dbtools::quoteName(aQuote, aColumnName);

						aWorkStr +=  ::rtl::OUString(')');
					}
                    else if ( pEntryField->isOtherFunction() )
                    {
                        aWorkStr += aColumnName;
                    }
					else
					{
						aWorkStr += quoteTableAlias(bMulti,pEntryField->GetAlias(),aQuote);
						aWorkStr += ::dbtools::quoteName(aQuote, aColumnName);
					}
					aWorkStr += ::rtl::OUString(' ');
					aWorkStr += String::CreateFromAscii( ";ASC;DESC" ).GetToken( (sal_uInt16)eOrder );
					aWorkStr += ::rtl::OUString(',');
				}
			}

			{
				String sTemp(aWorkStr);
				sTemp.EraseTrailingChars( ',' );
				aWorkStr = sTemp;
			}

			if ( aWorkStr.getLength() )
			{
				const sal_Int32 nMaxOrder = xMetaData->getMaxColumnsInOrderBy();
				String sToken(aWorkStr);
				if ( nMaxOrder && nMaxOrder < sToken.GetTokenCount(',') )
					eErrorCode = eStatementTooLong;
				else
				{
					_rsRet = ::rtl::OUString::createFromAscii(" ORDER BY ");
					_rsRet += aWorkStr;
				}
			}
		}
		catch(SQLException&)
		{
			OSL_ASSERT(!"Failure while building group by!");
		}

		return eErrorCode;
	}

	//------------------------------------------------------------------------------
	void GenerateInnerJoinCriterias(const Reference< XConnection>& _xConnection,
									::rtl::OUString& _rJoinCrit,
									const ::std::vector<OTableConnection*>* _pConnList)
	{
		::std::vector<OTableConnection*>::const_iterator aIter = _pConnList->begin();
        ::std::vector<OTableConnection*>::const_iterator aEnd = _pConnList->end();
		for(;aIter != aEnd;++aIter)
		{
			const OQueryTableConnection* pEntryConn = static_cast<const OQueryTableConnection*>(*aIter);
			OQueryTableConnectionData* pEntryConnData = static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get());
            if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() )
			{
				if(_rJoinCrit.getLength())
					_rJoinCrit += C_AND;
				_rJoinCrit += BuildJoinCriteria(_xConnection,pEntryConnData->GetConnLineDataList(),pEntryConnData);
			}
		}
	}
	//------------------------------------------------------------------------------
	void searchAndAppendName(const Reference< XConnection>& _xConnection,
							 const OQueryTableWindow* _pTableWindow,
							 ::std::map< ::rtl::OUString,sal_Bool,::comphelper::UStringMixLess>& _rTableNames,
							 ::rtl::OUString& _rsTableListStr
							 )
	{
		::rtl::OUString sTabName(BuildTable(_xConnection,_pTableWindow));

		if(_rTableNames.find(sTabName) == _rTableNames.end())
		{
			_rTableNames[sTabName] = sal_True;
			_rsTableListStr += sTabName;
			_rsTableListStr += ::rtl::OUString(',');
		}
	}
	//------------------------------------------------------------------------------
	::rtl::OUString GenerateFromClause(	const Reference< XConnection>& _xConnection,
										const OQueryTableView::OTableWindowMap*	pTabList,
										const ::std::vector<OTableConnection*>*	pConnList
										)
	{

		::rtl::OUString aTableListStr;
		// wird gebraucht um sicher zustelllen das eine Tabelle nicht doppelt vorkommt
		::std::map< ::rtl::OUString,sal_Bool,::comphelper::UStringMixLess> aTableNames;

		// generate outer join clause in from
		if(!pConnList->empty())
		{
			::std::vector<OTableConnection*>::const_iterator aIter = pConnList->begin();
            ::std::vector<OTableConnection*>::const_iterator aEnd = pConnList->end();
            ::std::map<OTableWindow*,sal_Int32> aConnectionCount;
			for(;aIter != aEnd;++aIter)
            {
				static_cast<OQueryTableConnection*>(*aIter)->SetVisited(sal_False);
                if ( aConnectionCount.find((*aIter)->GetSourceWin()) == aConnectionCount.end() )
                    aConnectionCount.insert(::std::map<OTableWindow*,sal_Int32>::value_type((*aIter)->GetSourceWin(),0));
                else
                    aConnectionCount[(*aIter)->GetSourceWin()]++;
                if ( aConnectionCount.find((*aIter)->GetDestWin()) == aConnectionCount.end() )
                    aConnectionCount.insert(::std::map<OTableWindow*,sal_Int32>::value_type((*aIter)->GetDestWin(),0));
                else
                    aConnectionCount[(*aIter)->GetDestWin()]++;
            }
            ::std::multimap<sal_Int32 , OTableWindow*> aMulti;
            ::std::map<OTableWindow*,sal_Int32>::iterator aCountIter = aConnectionCount.begin();
            ::std::map<OTableWindow*,sal_Int32>::iterator aCountEnd = aConnectionCount.end();
            for(;aCountIter != aCountEnd;++aCountIter)
            {
                aMulti.insert(::std::multimap<sal_Int32 , OTableWindow*>::value_type(aCountIter->second,aCountIter->first));
            }

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

					    if(aJoin.getLength())
					    {
						    // insert tables into table list to avoid double entries
						    OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
						    OQueryTableWindow* pEntryTabTo = static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin());

						    ::rtl::OUString sTabName(BuildTable(_xConnection,pEntryTabFrom));
						    if(aTableNames.find(sTabName) == aTableNames.end())
							    aTableNames[sTabName] = sal_True;
						    sTabName = BuildTable(_xConnection,pEntryTabTo);
						    if(aTableNames.find(sTabName) == aTableNames.end())
							    aTableNames[sTabName] = sal_True;

                            ::rtl::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 += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("{ OJ "));
						                aStr += aJoin;
						                if ( bUseEscape )
							                aStr += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" }"));
                                    }
                                    break;
                                default:
                                    aStr += aJoin;
                                    break;
                            }
						    aStr += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(","));
						    aTableListStr += aStr;
					    }
				    }
			    }
            }

			// and now all inner joins
			aIter = pConnList->begin();
			for(;aIter != aEnd;++aIter)
			{
				OQueryTableConnection* pEntryConn = static_cast<OQueryTableConnection*>(*aIter);
				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
		OQueryTableView::OTableWindowMap::const_iterator aTabIter = pTabList->begin();
        OQueryTableView::OTableWindowMap::const_iterator aTabEnd = pTabList->end();
		for(;aTabIter != aTabEnd;++aTabIter)
		{
			const OQueryTableWindow* pEntryTab = static_cast<const OQueryTableWindow*>(aTabIter->second);
			if(!pEntryTab->ExistsAConn())
			{
				aTableListStr += BuildTable(_xConnection,pEntryTab);
				aTableListStr += ::rtl::OUString(',');
			}
		}

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

        ::std::map< rtl::OUString,bool> aGroupByNames;

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

			OTableFields::iterator aIter = _rFieldList.begin();
			OTableFields::iterator aEnd = _rFieldList.end();
		    for(;aIter != aEnd;++aIter)
			{
				OTableFieldDescRef	pEntryField = *aIter;
				if ( pEntryField->IsGroupBy() )
				{
					DBG_ASSERT(pEntryField->GetField().getLength(),"Kein FieldName vorhanden!;-(");
					::rtl::OUString sGroupByPart = quoteTableAlias(bMulti,pEntryField->GetAlias(),aQuote);

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

		// nyi: mehr Pruefung auf korrekte Struktur!
		pNode = pNode ? pNode->getChild(3)->getChild(1) : NULL;
		// no where clause found
		if (!pNode || pNode->isLeaf())
			return eOk;

		// Naechster freier Satz ...
		SqlParseError eErrorCode = eOk;
		::connectivity::OSQLParseNode * pCondition = pNode->getChild(1);
		if ( pCondition ) // no where clause
		{
			// now we have to chech 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 http://www.openoffice.org/issues/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,
									sal_Bool bHaving,
                                    bool bAddOrOnOneLine);
	//------------------------------------------------------------------------------
	SqlParseError ComparisonPredicate(OQueryDesignView* _pView,
							OSelectionBrowseBox* _pSelectionBrw,
							const ::connectivity::OSQLParseNode * pCondition,
							const sal_uInt16 nLevel,
							sal_Bool bHaving,
                            bool bAddOrOnOneLine);
	//------------------------------------------------------------------------------
	SqlParseError GetORCriteria(OQueryDesignView* _pView,
								OSelectionBrowseBox* _pSelectionBrw,
								const ::connectivity::OSQLParseNode * pCondition,
								sal_uInt16& nLevel ,
								sal_Bool bHaving,
                                bool bAddOrOnOneLine)
	{
		SqlParseError eErrorCode = eOk;

		// Runde Klammern um den Ausdruck
		if (pCondition->count() == 3 &&
			SQL_ISPUNCTUATION(pCondition->getChild(0),"(") &&
			SQL_ISPUNCTUATION(pCondition->getChild(2),")"))
		{
			eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pCondition->getChild(1),nLevel,bHaving,bAddOrOnOneLine);
		}
		// oder Verknuepfung
		// 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 ? false : 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 (int i = 0; i < 3 && bRet; i+=2)
		{
            const  ::connectivity::OSQLParseNode* pChild = _pCondition->getChild(i);
            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,
									sal_Bool bHaving,
                                    bool bAddOrOnOneLine)
	{
		const ::com::sun::star::lang::Locale	aLocale = _pView->getLocale();
		const ::rtl::OUString sDecimal = _pView->getDecimalSeparator();

		// ich werde ein paar Mal einen gecasteten Pointer auf meinen ::com::sun::star::sdbcx::Container brauchen
		OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
		SqlParseError eErrorCode = eOk;

		// Runde Klammern
		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,NULL);
			if ( SQL_ISRULE( pSearchCondition, search_condition) ) // we have a or
			{
				_pSelectionBrw->DuplicateConditionLevel( nLevel);
				eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(0), nLevel,bHaving,bMustAddOrOnOneLine );				
				++nLevel;
				eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(2), nLevel,bHaving,bMustAddOrOnOneLine );
			}
			else
				eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition, nLevel,bHaving,bMustAddOrOnOneLine );
		}
		// Das erste Element ist (wieder) eine AND-Verknuepfung
		else if ( SQL_ISRULE(pCondition,boolean_term) )
		{
            OSL_ENSURE(pCondition->count() == 3,"Illegal definifiton 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 ) )
			{
				::rtl::OUString aColumnName;
				::rtl::OUString	aCondition;
				Reference< XConnection> xConnection = rController.getConnection();
				if ( xConnection.is() )
				{
					Reference< XDatabaseMetaData >  xMetaData = xConnection->getMetaData();
					// the international doesn't matter I have a string
					pCondition->parseNodeToPredicateStr(aCondition,
														xConnection,
														rController.getNumberFormatter(),
														aLocale,
														static_cast<sal_Char>(sDecimal.toChar()),
														&rController.getParser().getContext());

					pValueExp->parseNodeToPredicateStr(	aColumnName,
														xConnection,
														rController.getNumberFormatter(),
														aLocale,
														static_cast<sal_Char>(sDecimal.toChar()),
														&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(sal_True);
					_pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
                }
			}
            else if(SQL_ISRULEOR2(pValueExp,general_set_fct ,set_fct_spec)	        ||
							SQL_ISRULEOR2(pValueExp,position_exp,extract_exp)	||
							SQL_ISRULEOR2(pValueExp,fold,char_substring_fct)	||
							SQL_ISRULEOR2(pValueExp,length_exp,char_value_fct))
		    {
			    AddFunctionCondition(	_pView,
									    _pSelectionBrw,
									    pCondition,
									    nLevel,
									    bHaving,
                                        bAddOrOnOneLine);
		    }
			else
			{
				eErrorCode = eNoColumnInLike;
				String sError(ModuleRes(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
				::rtl::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(sal_True);
					_pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine);
                }
			}
			else
			{
				// Funktions-Bedingung parsen
				::rtl::OUString	sCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,1);
				Reference< XConnection> xConnection = rController.getConnection();
				Reference< XDatabaseMetaData >  xMetaData = xConnection->getMetaData();
					// the international doesn't matter I have a string
				::rtl::OUString sName;
				pCondition->getChild(0)->parseNodeToPredicateStr(sName,
													xConnection,
													rController.getNumberFormatter(),
													aLocale,
													static_cast<sal_Char>(sDecimal.toChar()),
													&rController.getParser().getContext());

				OTableFieldDescRef aDragLeft = new OTableFieldDesc();
				aDragLeft->SetField(sName);
				aDragLeft->SetFunctionType(FKT_OTHER);

				if ( bHaving )
					aDragLeft->SetGroupBy(sal_True);
				_pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine);
			}
		}
		else if( SQL_ISRULEOR2(pCondition,existence_test,unique_test) )
		{
			// Funktions-Bedingung parsen
			::rtl::OUString	aCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,0);

			OTableFieldDescRef aDragLeft = new OTableFieldDesc();
			aDragLeft->SetField(aCondition);
			aDragLeft->SetFunctionType(FKT_CONDITION);

			eErrorCode = _pSelectionBrw->InsertField(aDragLeft,BROWSER_INVALIDID,sal_False,sal_True).isValid() ? eOk : eTooManyColumns;
		}
		else //! TODO not supported yet
			eErrorCode = eStatementTooComplex;
		// Fehler einfach weiterreichen.
		return eErrorCode;
	}
	//------------------------------------------------------------------------------
	SqlParseError AddFunctionCondition(OQueryDesignView* _pView,
							OSelectionBrowseBox* _pSelectionBrw,
							const ::connectivity::OSQLParseNode * pCondition,
							const sal_uInt16 nLevel,
							sal_Bool bHaving,
                            bool bAddOrOnOneLine)
	{
		SqlParseError eErrorCode = eOk;
		OQueryController& rController = static_cast<OQueryController&>(_pView->getController());

        OSQLParseNode* pFunction = pCondition->getChild(0);

        OSL_ENSURE(SQL_ISRULEOR2(pFunction,general_set_fct ,set_fct_spec)	        ||
							SQL_ISRULEOR2(pFunction,position_exp,extract_exp)	||
							SQL_ISRULEOR2(pFunction,fold,char_substring_fct)	||
							SQL_ISRULEOR2(pFunction,length_exp,char_value_fct),"Illegal call!");
		::rtl::OUString	aCondition;
		OTableFieldDescRef aDragLeft = new OTableFieldDesc();

		::rtl::OUString aColumnName;
		Reference< XConnection> xConnection = rController.getConnection();
		if(xConnection.is())
		{
			Reference< XDatabaseMetaData >  xMetaData = xConnection->getMetaData();
			pCondition->parseNodeToPredicateStr(aCondition,
												xConnection,
												rController.getNumberFormatter(),
												_pView->getLocale(),
												static_cast<sal_Char>(_pView->getDecimalSeparator().toChar()),
												&rController.getParser().getContext());

            pFunction->parseNodeToStr(	aColumnName,
										xConnection,
										&rController.getParser().getContext(),
										sal_True,
										sal_True); // quote is to true because we need quoted elements inside the function
            // i75557
			//pFunction->parseNodeToPredicateStr(aColumnName,
			//									xConnection,
			//									rController.getNumberFormatter(),
			//									_pView->getLocale(),
			//									static_cast<sal_Char>(_pView->getDecimalSeparator().toChar()),
			//									&rController.getParser().getContext());
			// don't display the column name
			aCondition = aCondition.copy(aColumnName.getLength());
			aCondition = aCondition.trim();
			if ( aCondition.indexOf('=',0) == 0 ) // ignore the equal sign
				aCondition = aCondition.copy(1);


			if ( SQL_ISRULE(pFunction, general_set_fct ) )
			{
				sal_Int32 nFunctionType = FKT_AGGREGATE;
				OSQLParseNode* pParamNode = pFunction->getChild(pFunction->count()-2);
				if ( pParamNode && pParamNode->getTokenValue().toChar() == '*' )
				{
					OJoinTableView::OTableWindowMap* pTabList = _pView->getTableView()->GetTabWinMap();
					OJoinTableView::OTableWindowMap::iterator aIter = pTabList->begin();
                    OJoinTableView::OTableWindowMap::iterator aTabEnd = pTabList->end();
					for(;aIter != aTabEnd;++aIter)
					{
						OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(aIter->second);
						if (pTabWin->ExistsField( ::rtl::OUString::createFromAscii("*"), aDragLeft ))
						{
							aDragLeft->SetAlias(String());
							aDragLeft->SetTable(String());
							break;
						}
					}
				}
				else if( eOk != ( eErrorCode = FillDragInfo(_pView,pParamNode,aDragLeft))
						&& SQL_ISRULE(pParamNode,num_value_exp) )
				{
					::rtl::OUString sParameterValue;
					pParamNode->parseNodeToStr(	sParameterValue,
												xConnection,
												&rController.getParser().getContext());
					nFunctionType |= FKT_NUMERIC;
					aDragLeft->SetField(sParameterValue);
					eErrorCode = eOk;
				}
				aDragLeft->SetFunctionType(nFunctionType);
				if ( bHaving )
					aDragLeft->SetGroupBy(sal_True);
				sal_Int32 nIndex = 0;
				aDragLeft->SetFunction(aColumnName.getToken(0,'(',nIndex));
			}
			else
			{
				// bei unbekannten Funktionen wird der gesamte Text in das Field gechrieben
				aDragLeft->SetField(aColumnName);
				if(bHaving)
					aDragLeft->SetGroupBy(sal_True);
				aDragLeft->SetFunctionType(FKT_OTHER|FKT_NUMERIC);
			}
			_pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
		}

		return eErrorCode;
	}
	//------------------------------------------------------------------------------
	SqlParseError ComparisonPredicate(OQueryDesignView* _pView,
							OSelectionBrowseBox* _pSelectionBrw,
							const ::connectivity::OSQLParseNode * pCondition,
							const sal_uInt16 nLevel,
							sal_Bool bHaving 
                            ,bool bAddOrOnOneLine)
	{
		SqlParseError eErrorCode = eOk;
		OQueryController& rController = static_cast<OQueryController&>(_pView->getController());

		DBG_ASSERT(SQL_ISRULE( pCondition, comparison_predicate),"ComparisonPredicate: pCondition ist kein ComparisonPredicate");
		if ( SQL_ISRULE(pCondition->getChild(0), column_ref )
			|| SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref) )
		{
			::rtl::OUString	aCondition;
			OTableFieldDescRef aDragLeft = new OTableFieldDesc();

			if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) && SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref ) )
			{
				OTableFieldDescRef aDragRight = new OTableFieldDesc();
				if (eOk != ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(0),aDragLeft)) ||
					eOk != ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(2),aDragRight)))
					return eErrorCode;

                OQueryTableConnection* pConn = static_cast<OQueryTableConnection*>(
                                                    _pView->getTableView()->GetTabConn(static_cast<OQueryTableWindow*>(aDragLeft->GetTabWindow()),
																					   static_cast<OQueryTableWindow*>(aDragRight->GetTabWindow()),
                                                                                       true));
				if ( pConn )
				{
					OConnectionLineDataVec* pLineDataList = pConn->GetData()->GetConnLineDataList();
					OConnectionLineDataVec::iterator aIter = pLineDataList->begin();
                    OConnectionLineDataVec::iterator aEnd = pLineDataList->end();
					for(;aIter != aEnd;++aIter)
					{
						if((*aIter)->GetSourceFieldName() == aDragLeft->GetField() ||
						   (*aIter)->GetDestFieldName() == aDragLeft->GetField() )
							break;
					}
					if(aIter != aEnd)
						return eOk;
				}
			}

			sal_uInt32 nPos = 0;
			if(SQL_ISRULE(pCondition->getChild(0), column_ref ))
			{
				nPos = 0;
				sal_uInt32 i=1;

				// don't display the equal
				if (pCondition->getChild(i)->getNodeType() == SQL_NODE_EQUAL)
					i++;

				// Bedingung parsen
				aCondition = ParseCondition(rController
											,pCondition
											,_pView->getDecimalSeparator()
											,_pView->getLocale()
											,i);
			}
			else if( SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref ) )
			{
				nPos = pCondition->count()-1;

				sal_Int32 i = static_cast<sal_Int32>(pCondition->count() - 2);
				switch (pCondition->getChild(i)->getNodeType())
				{
					case SQL_NODE_EQUAL:
						// don't display the equal
						i--;
						break;
					case SQL_NODE_LESS:
						// take the opposite as we change the order
						i--;
						aCondition = aCondition + ::rtl::OUString::createFromAscii(">");
						break;
					case SQL_NODE_LESSEQ:
						// take the opposite as we change the order
						i--;
						aCondition = aCondition + ::rtl::OUString::createFromAscii(">=");
						break;
					case SQL_NODE_GREAT:
						// take the opposite as we change the order
						i--;
						aCondition = aCondition + ::rtl::OUString::createFromAscii("<");
						break;
					case SQL_NODE_GREATEQ:
						// take the opposite as we change the order
						i--;
						aCondition = aCondition + ::rtl::OUString::createFromAscii("<=");
						break;
                    default:
                        break;
				}

				// go backward
				Reference< XConnection> xConnection = rController.getConnection();
				if(xConnection.is())
				{
					Reference< XDatabaseMetaData >  xMetaData = xConnection->getMetaData();
					for (; i >= 0; i--)
						pCondition->getChild(i)->parseNodeToPredicateStr(aCondition,
												xConnection,
												rController.getNumberFormatter(),
												_pView->getLocale(),
												static_cast<sal_Char>(_pView->getDecimalSeparator().toChar()),
												&rController.getParser().getContext());
				}
			}
			// else ???

			
			if( eOk == ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(nPos),aDragLeft)))
			{
				if(bHaving)
					aDragLeft->SetGroupBy(sal_True);
				_pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
			}
		}
		else if( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , general_set_fct ) )
		{
			AddFunctionCondition(	_pView,
									_pSelectionBrw,
									pCondition,
									nLevel,
									bHaving,
                                    bAddOrOnOneLine);
		}
		else // kann sich nur um einen Expr. Ausdruck handeln
		{
			::rtl::OUString aName,aCondition;

			::connectivity::OSQLParseNode *pLhs = pCondition->getChild(0);
			::connectivity::OSQLParseNode *pRhs = pCondition->getChild(2);
			// Feldnamen
			Reference< XConnection> xConnection = rController.getConnection();
			if(xConnection.is())
			{
				pLhs->parseNodeToStr(aName,
									 xConnection,
									 &rController.getParser().getContext(),
									 sal_True);
				// Kriterium
				aCondition = pCondition->getChild(1)->getTokenValue();
				pRhs->parseNodeToPredicateStr(aCondition,
															xConnection,
															rController.getNumberFormatter(),
															_pView->getLocale(),
															static_cast<sal_Char>(_pView->getDecimalSeparator().toChar()),
															&rController.getParser().getContext());
			}

			OTableFieldDescRef aDragLeft = new OTableFieldDesc();
			aDragLeft->SetField(aName);
			aDragLeft->SetFunctionType(FKT_OTHER|FKT_NUMERIC);
			// und anh"angen
			_pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
		}
		return eErrorCode;
	}

    //------------------------------------------------------------------------------
    namespace
    {
        OQueryTableWindow* lcl_findColumnInTables( const ::rtl::OUString& _rColumName, const OJoinTableView::OTableWindowMap& _rTabList, OTableFieldDescRef& _rInfo )
        {
			OJoinTableView::OTableWindowMap::const_iterator aIter = _rTabList.begin();
            OJoinTableView::OTableWindowMap::const_iterator aEnd = _rTabList.end();
			for ( ; aIter != aEnd; ++aIter )
			{
				OQueryTableWindow* pTabWin = static_cast< OQueryTableWindow* >( aIter->second );
				if ( pTabWin && pTabWin->ExistsField( _rColumName, _rInfo ) )
					return pTabWin;
			}
            return NULL;
        }
    }

    //------------------------------------------------------------------------------
	void InsertColumnRef(const OQueryDesignView* _pView,
						const ::connectivity::OSQLParseNode * pColumnRef,
						::rtl::OUString& aColumnName,
						const ::rtl::OUString& aColumnAlias,
						::rtl::OUString& aTableRange,
						OTableFieldDescRef& _raInfo,
						OJoinTableView::OTableWindowMap* pTabList)
	{

		// Tabellennamen zusammen setzen
		::connectivity::OSQLParseTreeIterator& rParseIter = static_cast<OQueryController&>(_pView->getController()).getParseIterator();
		rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange );

		sal_Bool bFound(sal_False);
		DBG_ASSERT(aColumnName.getLength(),"Columnname darf nicht leer sein");
		if (!aTableRange.getLength())
		{
			// SELECT column, ...
            bFound = NULL != lcl_findColumnInTables( aColumnName, *pTabList, _raInfo );
			if ( bFound && ( aColumnName.toChar() != '*' ) )
				_raInfo->SetFieldAlias(aColumnAlias);
		}
		else
		{
			// SELECT range.column, ...
			OQueryTableWindow* pTabWin = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable(aTableRange);

			if (pTabWin && pTabWin->ExistsField(aColumnName, _raInfo))
			{
				if(aColumnName.toChar() != '*')
					_raInfo->SetFieldAlias(aColumnAlias);
				bFound = sal_True;
			}
		}
		if (!bFound)
		{
			_raInfo->SetTable(::rtl::OUString());
			_raInfo->SetAlias(::rtl::OUString());
			_raInfo->SetField(aColumnName);
			_raInfo->SetFieldAlias(aColumnAlias);	// nyi : hier ein fortlaufendes Expr_1, Expr_2 ...
			_raInfo->SetFunctionType(FKT_OTHER);
		}
	}
	//-----------------------------------------------------------------------------
	sal_Bool checkJoinConditions(	const OQueryDesignView* _pView,
									const ::connectivity::OSQLParseNode* _pNode )
	{
		const ::connectivity::OSQLParseNode* pJoinNode = NULL;
		sal_Bool bRet = sal_True;
		if (SQL_ISRULE(_pNode,qualified_join))
			pJoinNode = _pNode;
        else if (SQL_ISRULE(_pNode,table_ref) 
                &&  _pNode->count() == 3 
                &&  SQL_ISPUNCTUATION(_pNode->getChild(0),"(") 
                &&  SQL_ISPUNCTUATION(_pNode->getChild(2),")") ) // '(' joined_table ')'
			pJoinNode = _pNode->getChild(1);
		else if (! ( SQL_ISRULE(_pNode, table_ref) && _pNode->count() == 2) ) // table_node table_primary_as_range_column
			bRet = sal_False;

		if (pJoinNode && !InsertJoin(_pView,pJoinNode))
			bRet = sal_False;
		return bRet;
	}
	//-----------------------------------------------------------------------------
	sal_Bool InsertJoin(const OQueryDesignView* _pView,
						const ::connectivity::OSQLParseNode *pNode)
	{
		DBG_ASSERT( SQL_ISRULE( pNode, qualified_join ) || SQL_ISRULE( pNode, joined_table ) || SQL_ISRULE( pNode, cross_union ),
			"OQueryDesignView::InsertJoin: Fehler im Parse Tree");

        if (SQL_ISRULE(pNode,joined_table))
            return InsertJoin(_pView,pNode->getChild(1));

		// first check the left and right side
        const ::connectivity::OSQLParseNode* pRightTableRef = pNode->getChild(3); // table_ref
        if ( SQL_ISRULE(pNode, qualified_join) && SQL_ISTOKEN(pNode->getChild(1),NATURAL) )
            pRightTableRef = pNode->getChild(4); // table_ref

		if ( !checkJoinConditions(_pView,pNode->getChild(0)) || !checkJoinConditions(_pView,pRightTableRef))
			return sal_False;

		// named column join wird später vieleicht noch implementiert
		// SQL_ISRULE(pNode->getChild(4),named_columns_join)
        EJoinType eJoinType = INNER_JOIN;
        bool bNatural = false;
		if ( SQL_ISRULE(pNode, qualified_join) )
		{
			::connectivity::OSQLParseNode* pJoinType = pNode->getChild(1); // join_type
            if ( SQL_ISTOKEN(pJoinType,NATURAL) )
            {
                bNatural = true;
                pJoinType = pNode->getChild(2);
            }

			if (SQL_ISRULE(pJoinType,join_type) && (!pJoinType->count() || SQL_ISTOKEN(pJoinType->getChild(0),INNER)))
			{
				eJoinType = INNER_JOIN;
			}
			else
			{
				if (SQL_ISRULE(pJoinType,join_type))	   // eine Ebene tiefer
					pJoinType = pJoinType->getChild(0);

				if (SQL_ISTOKEN(pJoinType->getChild(0),LEFT))
					eJoinType = LEFT_JOIN;
				else if(SQL_ISTOKEN(pJoinType->getChild(0),RIGHT))
					eJoinType = RIGHT_JOIN;
				else
					eJoinType = FULL_JOIN;
			}
            if ( SQL_ISRULE(pNode->getChild(4),join_condition) )
            {
			    if ( InsertJoinConnection(_pView,pNode->getChild(4)->getChild(1), eJoinType,pNode->getChild(0),pRightTableRef) != eOk )
				    return sal_False;
            }
		}
        else if ( SQL_ISRULE(pNode, cross_union) )
        {
            eJoinType = CROSS_JOIN;
            pRightTableRef = pNode->getChild(pNode->count() - 1);
        }
        else
			return sal_False;

        if ( eJoinType == CROSS_JOIN || bNatural )
        {

            OQueryTableWindow*	pLeftWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pNode->getChild(0)) );
            OQueryTableWindow*	pRightWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pRightTableRef) );
            OSL_ENSURE(pLeftWindow && pRightWindow,"Table Windows could not be found!");
            if ( !pLeftWindow || !pRightWindow )
                return sal_False;

            OTableFieldDescRef aDragLeft  = new OTableFieldDesc();
            aDragLeft->SetTabWindow(pLeftWindow);
            aDragLeft->SetTable(pLeftWindow->GetTableName());
            aDragLeft->SetAlias(pLeftWindow->GetAliasName());

			OTableFieldDescRef aDragRight = new OTableFieldDesc();
            aDragRight->SetTabWindow(pRightWindow);
            aDragRight->SetTable(pRightWindow->GetTableName());
            aDragRight->SetAlias(pRightWindow->GetAliasName());

            insertConnection(_pView,eJoinType,aDragLeft,aDragRight,bNatural);
        }
		

		return sal_True;
	}
	//------------------------------------------------------------------------------
	void insertUnUsedFields(OQueryDesignView* _pView,OSelectionBrowseBox* _pSelectionBrw)
	{
		// now we have to insert the fields which aren't in the statement
		OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
		OTableFields& rUnUsedFields = rController.getUnUsedFields();
        OTableFields::iterator aEnd = rUnUsedFields.end();
		for(OTableFields::iterator aIter = rUnUsedFields.begin();aIter != aEnd;++aIter)
			if(_pSelectionBrw->InsertField(*aIter,BROWSER_INVALIDID,sal_False,sal_False).isValid())
				(*aIter) = NULL;
		OTableFields().swap( rUnUsedFields );
	}

	//------------------------------------------------------------------------------
	SqlParseError InitFromParseNodeImpl(OQueryDesignView* _pView,OSelectionBrowseBox* _pSelectionBrw)
	{
		SqlParseError eErrorCode = eOk;

		OQueryController& rController = static_cast<OQueryController&>(_pView->getController());

		_pSelectionBrw->PreFill();
		_pSelectionBrw->SetReadOnly(rController.isReadOnly());
		_pSelectionBrw->Fill();


		::connectivity::OSQLParseTreeIterator& aIterator = rController.getParseIterator();
		const ::connectivity::OSQLParseNode* pParseTree = aIterator.getParseTree();

        do
        {
            if ( !pParseTree )
            {
			    // now we have to insert the fields which aren't in the statement
			    insertUnUsedFields(_pView,_pSelectionBrw);
                break;
            }

            if ( !rController.isEsacpeProcessing() ) // not allowed in this mode
            {
			    eErrorCode = eNativeMode;
                break;
            }

			if ( !( SQL_ISRULE( pParseTree, select_statement ) ) )
            {
				eErrorCode = eNoSelectStatement;
                break;
            }

            const OSQLParseNode* pTableExp = pParseTree->getChild(3);
            if ( pTableExp->getChild(6)->count() > 0 || pTableExp->getChild(7)->count() > 0 || pTableExp->getChild(8)->count() > 0)
            {
				eErrorCode = eStatementTooComplex;
                break;
            }

			Reference< XConnection> xConnection = rController.getConnection();
			if ( !xConnection.is() )
            {
                DBG_ERROR( "InitFromParseNodeImpl: no connection? no connection!" );
                break;
            }

			const OSQLTables& aMap = aIterator.getTables();
			::comphelper::UStringMixLess aTmp(aMap.key_comp());
			::comphelper::UStringMixEqual aKeyComp( aTmp.isCaseSensitive() );

			Reference< XDatabaseMetaData >  xMetaData = xConnection->getMetaData();
			try
			{
			    sal_Int32 nMax = xMetaData->getMaxTablesInSelect();
                if ( nMax && nMax < (sal_Int32)aMap.size() )
                {
					eErrorCode = eTooManyTables;
                    break;
                }

				::rtl::OUString sComposedName;
				::rtl::OUString aQualifierName;
				::rtl::OUString sAlias;

				OQueryTableView* pTableView = static_cast<OQueryTableView*>(_pView->getTableView());
                pTableView->clearLayoutInformation();
				OSQLTables::const_iterator aIter = aMap.begin();
                OSQLTables::const_iterator aEnd = aMap.end();
				for(;aIter != aEnd;++aIter)
				{
					OSQLTable xTable = aIter->second;
                    Reference< XPropertySet > xTableProps( xTable, UNO_QUERY_THROW );

					sAlias = aIter->first;

                    // check whether this is a query
                    Reference< XPropertySetInfo > xPSI = xTableProps->getPropertySetInfo();
                    bool bIsQuery = xPSI.is() && xPSI->hasPropertyByName( PROPERTY_COMMAND );

                    if ( bIsQuery )
                        OSL_VERIFY( xTableProps->getPropertyValue( PROPERTY_NAME ) >>= sComposedName );
                    else
                    {
                        sComposedName = ::dbtools::composeTableName( xMetaData, xTableProps, ::dbtools::eInDataManipulation, false, false, false );

                        // if the alias is the complete (composed) table, then shorten it
                        if ( aKeyComp( sComposedName, aIter->first ) )
					    {
						    ::rtl::OUString sCatalog, sSchema, sTable;
						    ::dbtools::qualifiedNameComponents( xMetaData, sComposedName, sCatalog, sSchema, sTable, ::dbtools::eInDataManipulation );
						    sAlias = sTable;
					    }
                    }

                    // find the existent window for this alias
					OQueryTableWindow* pExistentWin	= pTableView->FindTable( sAlias );
					if ( !pExistentWin )
					{
						pTableView->AddTabWin( sComposedName, sAlias, sal_False );  // don't create data here
					}
					else
					{
						// there already exists a window for this alias ....
						if ( !aKeyComp( pExistentWin->GetData()->GetComposedName(), sComposedName ) )
							// ... but for another complete table name -> new window
							pTableView->AddTabWin(sComposedName, sAlias);
					}
				}

				// now delete the data for which we haven't any tablewindow
				OJoinTableView::OTableWindowMap aTableMap(*pTableView->GetTabWinMap());
				OJoinTableView::OTableWindowMap::iterator aIterTableMap = aTableMap.begin();
                OJoinTableView::OTableWindowMap::iterator aIterTableEnd = aTableMap.end();
				for(;aIterTableMap != aIterTableEnd;++aIterTableMap)
				{
					if(aMap.find(aIterTableMap->second->GetComposedName())	== aMap.end() &&
						aMap.find(aIterTableMap->first)						== aMap.end())
						pTableView->RemoveTabWin(aIterTableMap->second);
				}

				if ( eOk == (eErrorCode = FillOuterJoins(_pView,pTableExp->getChild(0)->getChild(1))) )
				{
					// check if we have a distinct statement
					if(SQL_ISTOKEN(pParseTree->getChild(1),DISTINCT))
					{
						rController.setDistinct(sal_True);
						rController.InvalidateFeature(SID_QUERY_DISTINCT_VALUES);
					}
					if ( (eErrorCode = InstallFields(_pView,pParseTree, pTableView->GetTabWinMap())) == eOk )
					{
						// GetSelectionCriteria must be called before GetHavingCriteria
						sal_uInt16 nLevel=0;

						if ( eOk == (eErrorCode = GetSelectionCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) )
						{
							if ( eOk == (eErrorCode = GetGroupCriteria(_pView,_pSelectionBrw,pParseTree)) )
							{
								if ( eOk == (eErrorCode = GetHavingCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) )
								{
									if ( eOk == (eErrorCode = GetOrderCriteria(_pView,_pSelectionBrw,pParseTree)) )
										insertUnUsedFields(_pView,_pSelectionBrw);
								}
							}
						}
					}
				}
			}
			catch(SQLException&)
			{
				OSL_ASSERT(!"getMaxTablesInSelect!");
			}
		}
        while ( false );

		// Durch das Neuerzeugen wurden wieder Undo-Actions in den Manager gestellt
		rController.ClearUndoManager();
		_pSelectionBrw->Invalidate();
		return eErrorCode;
	}
	//------------------------------------------------------------------------------
	/** fillSelectSubList
		@return
			<TRUE/> when columns could be inserted otherwise <FALSE/>
	*/
	//------------------------------------------------------------------------------
	SqlParseError fillSelectSubList(	OQueryDesignView* _pView,
								OJoinTableView::OTableWindowMap* _pTabList)
	{
		SqlParseError eErrorCode = eOk;
		sal_Bool bFirstField = sal_True;
		::rtl::OUString sAsterix(RTL_CONSTASCII_USTRINGPARAM("*"));
		OJoinTableView::OTableWindowMap::iterator aIter = _pTabList->begin();
        OJoinTableView::OTableWindowMap::iterator aEnd = _pTabList->end();
		for(;aIter != aEnd && eOk == eErrorCode ;++aIter)
		{
			OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(aIter->second);
            OTableFieldDescRef	aInfo = new OTableFieldDesc();
			if (pTabWin->ExistsField( sAsterix, aInfo ))
			{
				eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField);
				bFirstField = sal_False;
			}
		}
		return eErrorCode;
	}
	//------------------------------------------------------------------------------
	SqlParseError InstallFields(OQueryDesignView* _pView,
								const ::connectivity::OSQLParseNode* pNode,
								OJoinTableView::OTableWindowMap* pTabList )
	{
		if( pNode==0 || !SQL_ISRULE(pNode,select_statement))
			return eNoSelectStatement;

		::connectivity::OSQLParseNode* pParseTree = pNode->getChild(2); // selection
		sal_Bool bFirstField = sal_True;	// bei der Initialisierung muß auf alle Faelle das erste Feld neu aktiviert werden

		SqlParseError eErrorCode = eOk;

		if ( pParseTree->isRule() && SQL_ISPUNCTUATION(pParseTree->getChild(0),"*") )
		{
			// SELECT * ...
			eErrorCode = fillSelectSubList(_pView,pTabList);
		}
		else if (SQL_ISRULE(pParseTree,scalar_exp_commalist) )
		{
			// SELECT column, ...
			OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
			Reference< XConnection> xConnection = rController.getConnection();

			::rtl::OUString aColumnName,aTableRange;
			for (sal_uInt32 i = 0; i < pParseTree->count() && eOk == eErrorCode ; ++i)
			{
				::connectivity::OSQLParseNode * pColumnRef = pParseTree->getChild(i);

                do {

                if ( SQL_ISRULE(pColumnRef,select_sublist) )
				{
					 eErrorCode = fillSelectSubList(_pView,pTabList);
                     break;
				}

                if ( SQL_ISRULE(pColumnRef,derived_column) )
				{
					::rtl::OUString aColumnAlias(rController.getParseIterator().getColumnAlias(pColumnRef)); // kann leer sein
					pColumnRef = pColumnRef->getChild(0);
					OTableFieldDescRef aInfo = new OTableFieldDesc();

					if (	pColumnRef->count() == 3 &&
							SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") &&
							SQL_ISPUNCTUATION(pColumnRef->getChild(2),")")
						)
						pColumnRef = pColumnRef->getChild(1);

					if (SQL_ISRULE(pColumnRef,column_ref))
					{
						InsertColumnRef(_pView,pColumnRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList);
						eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField);
						bFirstField = sal_False;
					}
					else if(SQL_ISRULEOR2(pColumnRef,general_set_fct ,set_fct_spec)	||
							SQL_ISRULEOR2(pColumnRef,position_exp,extract_exp)		||
							SQL_ISRULEOR2(pColumnRef,fold,char_substring_fct)		||
							SQL_ISRULEOR2(pColumnRef,length_exp,char_value_fct))
					{
						::rtl::OUString aColumns;
                        pColumnRef->parseNodeToPredicateStr(aColumns,
												            xConnection,
												            rController.getNumberFormatter(),
												            _pView->getLocale(),
												            static_cast<sal_Char>(_pView->getDecimalSeparator().toChar()),
												            &rController.getParser().getContext());
						//pColumnRef->parseNodeToStr(	aColumns,
						//							xConnection,
						//							&rController.getParser().getContext(),
						//							sal_True,
						//							sal_True); // quote is to true because we need quoted elements inside the function

						sal_Int32 nFunctionType = FKT_NONE;
						::connectivity::OSQLParseNode* pParamRef = NULL;
						sal_Int32 nColumnRefPos = pColumnRef->count() - 2;
						if ( nColumnRefPos >= 0 && static_cast<sal_uInt32>(nColumnRefPos) < pColumnRef->count() )
							pParamRef = pColumnRef->getChild(nColumnRefPos);

						if (	SQL_ISRULE(pColumnRef,general_set_fct)
							&&	SQL_ISRULE(pParamRef,column_ref) )
						{
							// Parameter auf Columnref pr"ufen
							InsertColumnRef(_pView,pParamRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList);
						}
						else if ( SQL_ISRULE(pColumnRef,general_set_fct) )
						{
							if ( pParamRef && pParamRef->getTokenValue().toChar() == '*' )
							{
								OJoinTableView::OTableWindowMap::iterator aIter = pTabList->begin();
                                OJoinTableView::OTableWindowMap::iterator aEnd  = pTabList->end();
								for(;aIter != aEnd;++aIter)
								{
									OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(aIter->second);
									if (pTabWin->ExistsField( ::rtl::OUString::createFromAscii("*"), aInfo ))
									{
										aInfo->SetAlias(String());
										aInfo->SetTable(String());
										break;
									}
								}
							}
							else
							{
								::rtl::OUString sFieldName = aColumns;
								if ( pParamRef )
								{	// we got an aggregate function but without column name inside
									// so we set the whole argument of the function as field name
									nFunctionType |= FKT_NUMERIC;
									sFieldName = ::rtl::OUString();
									pParamRef->parseNodeToStr(	sFieldName,
														xConnection,
														&rController.getParser().getContext(),
														sal_True,
														sal_True); // quote is to true because we need quoted elements inside the function
								}
								aInfo->SetDataType(DataType::DOUBLE);
								aInfo->SetFieldType(TAB_NORMAL_FIELD);
								aInfo->SetField(sFieldName);
							}
							aInfo->SetTabWindow(NULL);
							aInfo->SetFieldAlias(aColumnAlias);
						}
						else
						{
                            _pView->fillFunctionInfo(pColumnRef,aColumns,aInfo);
							aInfo->SetFieldAlias(aColumnAlias);
						}

						if ( SQL_ISRULE(pColumnRef,general_set_fct) )
						{
							aInfo->SetFunctionType(nFunctionType|FKT_AGGREGATE);
							String aCol(aColumns);
							aInfo->SetFunction(aCol.GetToken(0,'(').EraseTrailingChars(' '));
						}
						else
							aInfo->SetFunctionType(nFunctionType|FKT_OTHER);

						eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField);
						bFirstField = sal_False;
					}
					else //if(SQL_ISRULE(pColumnRef,num_value_exp)	|| SQL_ISRULE(pColumnRef,term))
					{
						::rtl::OUString aColumns;
						pColumnRef->parseNodeToStr(	aColumns,
													xConnection,
													&rController.getParser().getContext(),
													sal_True,
													sal_True); // quote is to true because we need quoted elements inside the function

                        aInfo->SetTabWindow( NULL );

                        // since we support queries in queries, the thingie might belong to an existing "table"
                        OQueryTableWindow* pExistingTable = lcl_findColumnInTables( aColumns, *pTabList, aInfo );
                        if ( pExistingTable )
                        {
                            aInfo->SetTabWindow( pExistingTable );
					        aInfo->SetTable( pExistingTable->GetTableName() );
					        aInfo->SetAlias( pExistingTable->GetAliasName() );
                        }

                        aInfo->SetDataType(DataType::DOUBLE);
						aInfo->SetFieldType(TAB_NORMAL_FIELD);
						aInfo->SetField(aColumns);
						aInfo->SetFieldAlias(aColumnAlias);
						aInfo->SetFunctionType(FKT_NUMERIC | FKT_OTHER);

						eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField);
						bFirstField = sal_False;
					}

                    break;
				}

                DBG_ERROR( "InstallFields: don't know how to interpret this parse node!" );

                } while ( false );
			}
		}
		else
			eErrorCode = eStatementTooComplex;

		return eErrorCode;
	}
	//------------------------------------------------------------------------------
	SqlParseError GetOrderCriteria(	OQueryDesignView* _pView,
							OSelectionBrowseBox* _pSelectionBrw,
							const ::connectivity::OSQLParseNode* pParseRoot )
	{
		SqlParseError eErrorCode = eOk;
		if (!pParseRoot->getChild(3)->getChild(ORDER_BY_CHILD_POS)->isLeaf())
		{
			::connectivity::OSQLParseNode* pNode = pParseRoot->getChild(3)->getChild(ORDER_BY_CHILD_POS)->getChild(2);
			::connectivity::OSQLParseNode* pParamRef = NULL;

            OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
			EOrderDir eOrderDir;
			OTableFieldDescRef aDragLeft = new OTableFieldDesc();
			for( sal_uInt32 i=0 ; i<pNode->count() ; i++ )
			{
				eOrderDir = ORDER_ASC;
				::connectivity::OSQLParseNode*	pChild = pNode->getChild( i );

				if (SQL_ISTOKEN( pChild->getChild(1), DESC ) )
					eOrderDir = ORDER_DESC;

                ::connectivity::OSQLParseNode* pArgument = pChild->getChild(0);
                
				if(SQL_ISRULE(pArgument,column_ref))
				{
					if( eOk == FillDragInfo(_pView,pArgument,aDragLeft))
						_pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i);
					else // it could be a alias name for a field
					{
						::rtl::OUString aTableRange,aColumnName;
						::connectivity::OSQLParseTreeIterator& rParseIter = rController.getParseIterator();
						rParseIter.getColumnRange( pArgument, aColumnName, aTableRange );

						OTableFields& aList = rController.getTableFieldDesc();
						OTableFields::iterator aIter = aList.begin();
                        OTableFields::iterator aEnd = aList.end();
						for(;aIter != aEnd;++aIter)
						{
							OTableFieldDescRef pEntry = *aIter;
							if(pEntry.isValid() && pEntry->GetFieldAlias() == aColumnName)
								pEntry->SetOrderDir( eOrderDir );
						}
					}
				}
				else if(SQL_ISRULE(pArgument, general_set_fct ) &&
						SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref) &&
						eOk == FillDragInfo(_pView,pParamRef,aDragLeft))
					_pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i );
                else if( SQL_ISRULE(pArgument, set_fct_spec ) )
                {
                    
		            Reference< XConnection> xConnection = rController.getConnection();
		            if(xConnection.is())
		            {
                        ::rtl::OUString sCondition;
			            pArgument->parseNodeToPredicateStr(sCondition,
												            xConnection,
												            rController.getNumberFormatter(),
												            _pView->getLocale(),
												            static_cast<sal_Char>(_pView->getDecimalSeparator().toChar()),
												            &rController.getParser().getContext());
                        _pView->fillFunctionInfo(pArgument,sCondition,aDragLeft);
                        aDragLeft->SetFunctionType(FKT_OTHER);
                        aDragLeft->SetOrderDir(eOrderDir);
                        aDragLeft->SetVisible(sal_False);
                        _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i );
                    }
                    else
                        eErrorCode = eColumnNotFound;
                }
				else
					eErrorCode = eColumnNotFound;
			}
		}
		return eErrorCode;
	}
	//------------------------------------------------------------------------------
	SqlParseError GetHavingCriteria(	OQueryDesignView* _pView,
							OSelectionBrowseBox* _pSelectionBrw,
							const ::connectivity::OSQLParseNode* pSelectRoot,
							sal_uInt16& rLevel )
	{
		SqlParseError eErrorCode = eOk;
		if (!pSelectRoot->getChild(3)->getChild(3)->isLeaf())
			eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSelectRoot->getChild(3)->getChild(3)->getChild(1),rLevel, sal_True);
		return eErrorCode;
	}
	//------------------------------------------------------------------------------
	SqlParseError GetGroupCriteria(	OQueryDesignView* _pView,
							OSelectionBrowseBox* _pSelectionBrw,
							const ::connectivity::OSQLParseNode* pSelectRoot )
	{
		SqlParseError eErrorCode = eOk;
		if (!pSelectRoot->getChild(3)->getChild(2)->isLeaf()) // opt_group_by_clause
		{
            OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
			::connectivity::OSQLParseNode* pGroupBy = pSelectRoot->getChild(3)->getChild(2)->getChild(2);
			
			for( sal_uInt32 i=0 ; i < pGroupBy->count() && eOk == eErrorCode; ++i )
			{
                OTableFieldDescRef aDragInfo = new OTableFieldDesc();
                ::connectivity::OSQLParseNode* pParamRef = NULL;
				::connectivity::OSQLParseNode* pArgument = pGroupBy->getChild( i );
				if(SQL_ISRULE(pArgument,column_ref))
				{
					if ( eOk == (eErrorCode = FillDragInfo(_pView,pArgument,aDragInfo)) )
					{
						aDragInfo->SetGroupBy(sal_True);
						_pSelectionBrw->AddGroupBy(aDragInfo,i);
					}
				}
                else if(SQL_ISRULE(pArgument, general_set_fct ) &&
						SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref) &&
						eOk == FillDragInfo(_pView,pParamRef,aDragInfo))
                {
                    aDragInfo->SetGroupBy(sal_True);
					_pSelectionBrw->AddGroupBy( aDragInfo, i );
                }
                else if( SQL_ISRULE(pArgument, set_fct_spec ) )
                {                    
		            Reference< XConnection> xConnection = rController.getConnection();
		            if(xConnection.is())
		            {
                        ::rtl::OUString sGroupByExpression;
			            pArgument->parseNodeToStr(	sGroupByExpression,
													xConnection,
													&rController.getParser().getContext(),
													sal_True,
													sal_True); // quote is to true because we need quoted elements inside the function
                        _pView->fillFunctionInfo(pArgument,sGroupByExpression,aDragInfo);
                        aDragInfo->SetFunctionType(FKT_OTHER);
                        aDragInfo->SetGroupBy(sal_True);
                        aDragInfo->SetVisible(sal_False);
                        _pSelectionBrw->AddGroupBy( aDragInfo, i );
                    }
                    else
                        eErrorCode = eColumnNotFound;
                }
			}
		}
		return eErrorCode;
	}

    //------------------------------------------------------------------------------
	String getParseErrorMessage( SqlParseError _eErrorCode )
	{
		sal_uInt16 nResId;
		switch(_eErrorCode)
		{
			case eIllegalJoin:
				nResId = STR_QRY_ILLEGAL_JOIN;
				break;
			case eStatementTooLong:
				nResId = STR_QRY_TOO_LONG_STATEMENT;
				break;
			case eNoConnection:
				nResId = STR_QRY_SYNTAX;
				break;
			case eNoSelectStatement:
				nResId = STR_QRY_NOSELECT;
				break;
			case eColumnInLikeNotFound:
				nResId = STR_QRY_SYNTAX;
				break;
			case eNoColumnInLike:
				nResId = STR_QRY_SYNTAX;
				break;
			case eColumnNotFound:
				nResId = STR_QRY_SYNTAX;
				break;
			case eNativeMode:
				nResId = STR_QRY_NATIVE;
				break;
			case eTooManyTables:
				nResId = STR_QRY_TOO_MANY_TABLES;
				break;
			case eTooManyConditions:
				nResId = STR_QRY_TOOMANYCOND;
				break;
			case eTooManyColumns:
				nResId = STR_QRY_TOO_MANY_COLUMNS;
				break;
			case eStatementTooComplex:
				nResId = STR_QRY_TOOCOMPLEX;
				break;
			default:
				nResId = STR_QRY_SYNTAX;
				break;
		}
		;
        return String( ModuleRes( nResId ) );
	}

	//------------------------------------------------------------------------------
	//------------------------------------------------------------------------------
}
// end of anonymouse namespace
DBG_NAME(OQueryDesignView)

OQueryDesignView::OQueryDesignView(	OQueryContainerWindow* _pParent,
									OQueryController& _rController,
									const Reference< XMultiServiceFactory >& _rFactory)
	:OQueryView( _pParent, _rController, _rFactory )
	,m_aSplitter( this )
	,m_eChildFocus(NONE)
	,m_bInKeyEvent(sal_False)
	,m_bInSplitHandler( sal_False )
{
    DBG_CTOR(OQueryDesignView,NULL);

	try
	{
		SvtSysLocale aSysLocale;
		m_aLocale = aSysLocale.GetLocaleData().getLocale();
		m_sDecimalSep = aSysLocale.GetLocaleData().getNumDecimalSep();
	}
	catch(Exception&)
	{
	}

	m_pSelectionBox = new OSelectionBrowseBox(this);

	setNoneVisbleRow(static_cast<OQueryController&>(getController()).getVisibleRows());
	m_pSelectionBox->Show();
	// Splitter einrichten
	m_aSplitter.SetSplitHdl(LINK(this, OQueryDesignView,SplitHdl));
	m_aSplitter.Show();

}
// -----------------------------------------------------------------------------
OQueryDesignView::~OQueryDesignView()
{
	if ( m_pTableView )
		::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::RemoveWindow));
	::std::auto_ptr<Window> aTemp(m_pSelectionBox);
	m_pSelectionBox = NULL;

    DBG_DTOR(OQueryDesignView,NULL);
}
//------------------------------------------------------------------------------
IMPL_LINK( OQueryDesignView, SplitHdl, void*, /*p*/ )
{
	if (!getController().isReadOnly())
	{
		m_bInSplitHandler = sal_True;
		m_aSplitter.SetPosPixel( Point( m_aSplitter.GetPosPixel().X(),m_aSplitter.GetSplitPosPixel() ) );
		static_cast<OQueryController&>(getController()).setSplitPos(m_aSplitter.GetSplitPosPixel());
		static_cast<OQueryController&>(getController()).setModified( sal_True );
		Resize();
		m_bInSplitHandler = sal_True;
	}
	return 0L;
}
// -------------------------------------------------------------------------
void OQueryDesignView::Construct()
{
	m_pTableView = new OQueryTableView(m_pScrollWindow,this);
	::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::AddWindow));
	OQueryView::Construct();
}
// -----------------------------------------------------------------------------
void OQueryDesignView::initialize()
{
	if(static_cast<OQueryController&>(getController()).getSplitPos() != -1)
	{
		m_aSplitter.SetPosPixel( Point( m_aSplitter.GetPosPixel().X(),static_cast<OQueryController&>(getController()).getSplitPos() ) );
		m_aSplitter.SetSplitPosPixel(static_cast<OQueryController&>(getController()).getSplitPos());
	}
	m_pSelectionBox->initialize();
	reset();
}
// -------------------------------------------------------------------------
void OQueryDesignView::resizeDocumentView(Rectangle& _rPlayground)
{
	Point aPlaygroundPos( _rPlayground.TopLeft() );
	Size aPlaygroundSize( _rPlayground.GetSize() );

	// calc the split pos, and forward it to the controller
	sal_Int32 nSplitPos = static_cast<OQueryController&>(getController()).getSplitPos();
	if ( 0 != aPlaygroundSize.Height() )
	{
		if	(	( -1 == nSplitPos )
			||	( nSplitPos >= aPlaygroundSize.Height() )
			)
		{
			// let the selection browse box determine an optimal size
			Size aSelectionBoxSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize );
			nSplitPos = aPlaygroundSize.Height() - aSelectionBoxSize.Height() - m_aSplitter.GetSizePixel().Height();
			// still an invalid size?
			if ( nSplitPos == -1 || nSplitPos >= aPlaygroundSize.Height() )
				nSplitPos = sal_Int32(aPlaygroundSize.Height()*0.6);

			static_cast<OQueryController&>(getController()).setSplitPos(nSplitPos);
		}

		if ( !m_bInSplitHandler )
		{	// the resize is triggered by something else than the split handler
			// our main focus is to try to preserve the size of the selectionbrowse box
			Size aSelBoxSize = m_pSelectionBox->GetSizePixel();
			if ( aSelBoxSize.Height() )
			{
				// keep the size of the sel box constant
				nSplitPos = aPlaygroundSize.Height() - m_aSplitter.GetSizePixel().Height() - aSelBoxSize.Height();

				// and if the box is smaller than the optimal size, try to do something about it
				Size aSelBoxOptSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize );
				if ( aSelBoxOptSize.Height() > aSelBoxSize.Height() )
				{
					nSplitPos = aPlaygroundSize.Height() - m_aSplitter.GetSizePixel().Height() - aSelBoxOptSize.Height();
				}

				static_cast< OQueryController& >(getController()).setSplitPos( nSplitPos );
			}
		}
	}

	// normalize the split pos
	Point	aSplitPos		= Point( _rPlayground.Left(), nSplitPos );
	Size	aSplitSize		= Size( _rPlayground.GetSize().Width(), m_aSplitter.GetSizePixel().Height() );

	if( ( aSplitPos.Y() + aSplitSize.Height() ) > ( aPlaygroundSize.Height() ))
		aSplitPos.Y() = aPlaygroundSize.Height() - aSplitSize.Height();

	if( aSplitPos.Y() <= aPlaygroundPos.Y() )
		aSplitPos.Y() = aPlaygroundPos.Y() + sal_Int32(aPlaygroundSize.Height() * 0.2);

	// position the table
	Size aTableViewSize(aPlaygroundSize.Width(), aSplitPos.Y() - aPlaygroundPos.Y());
	m_pScrollWindow->SetPosSizePixel(aPlaygroundPos, aTableViewSize);

	// position the selection browse box
	Point aPos( aPlaygroundPos.X(), aSplitPos.Y() + aSplitSize.Height() );
	m_pSelectionBox->SetPosSizePixel( aPos, Size( aPlaygroundSize.Width(), aPlaygroundSize.Height() - aSplitSize.Height() - aTableViewSize.Height() ));

	// set the size of the splitter
	m_aSplitter.SetPosSizePixel( aSplitPos, aSplitSize );
	m_aSplitter.SetDragRectPixel( _rPlayground );

	// just for completeness: there is no space left, we occupied it all ...
	_rPlayground.SetPos( _rPlayground.BottomRight() );
	_rPlayground.SetSize( Size( 0, 0 ) );
}
// -----------------------------------------------------------------------------
void OQueryDesignView::setReadOnly(sal_Bool _bReadOnly)
{
	m_pSelectionBox->SetReadOnly(_bReadOnly);
}
// -----------------------------------------------------------------------------
void OQueryDesignView::clear()
{
	m_pSelectionBox->ClearAll(); // clear the whole selection
	m_pTableView->ClearAll();
}
// -----------------------------------------------------------------------------
void OQueryDesignView::setStatement(const ::rtl::OUString& /*_rsStatement*/)
{
}
// -----------------------------------------------------------------------------
void OQueryDesignView::copy()
{
	if( m_eChildFocus == SELECTION)
		m_pSelectionBox->copy();
}
// -----------------------------------------------------------------------------
sal_Bool OQueryDesignView::isCutAllowed()
{
	sal_Bool bAllowed = sal_False;
	if ( SELECTION == m_eChildFocus )
		bAllowed = m_pSelectionBox->isCutAllowed();
	return bAllowed;
}
// -----------------------------------------------------------------------------
sal_Bool OQueryDesignView::isPasteAllowed()
{
	sal_Bool bAllowed = sal_False;
	if ( SELECTION == m_eChildFocus )
		bAllowed = m_pSelectionBox->isPasteAllowed();
	return bAllowed;
}
// -----------------------------------------------------------------------------
sal_Bool OQueryDesignView::isCopyAllowed()
{
	sal_Bool bAllowed = sal_False;
	if ( SELECTION == m_eChildFocus )
		bAllowed = m_pSelectionBox->isCopyAllowed();
	return bAllowed;
}
// -----------------------------------------------------------------------------
void OQueryDesignView::stopTimer()
{
	m_pSelectionBox->stopTimer();
}
// -----------------------------------------------------------------------------
void OQueryDesignView::startTimer()
{
	m_pSelectionBox->startTimer();
}
// -----------------------------------------------------------------------------
void OQueryDesignView::cut()
{
	if( m_eChildFocus == SELECTION)
	{
		m_pSelectionBox->cut();
		static_cast<OQueryController&>(getController()).setModified(sal_True);
	}
}
// -----------------------------------------------------------------------------
void OQueryDesignView::paste()
{
	if( m_eChildFocus == SELECTION)
	{
		m_pSelectionBox->paste();
		static_cast<OQueryController&>(getController()).setModified(sal_True);
	}
}
// -----------------------------------------------------------------------------
void OQueryDesignView::TableDeleted(const ::rtl::OUString& rAliasName)
{
	// Nachricht, dass Tabelle aus dem Fenster gel"oscht wurde
	DeleteFields(rAliasName);
	static_cast<OQueryController&>(getController()).InvalidateFeature(ID_BROWSER_ADDTABLE);	// view nochmal bescheid sagen
}
//------------------------------------------------------------------------------
void OQueryDesignView::DeleteFields( const ::rtl::OUString& rAliasName )
{
	m_pSelectionBox->DeleteFields( rAliasName );
}
// -----------------------------------------------------------------------------
bool OQueryDesignView::HasFieldByAliasName(const ::rtl::OUString& rFieldName, OTableFieldDescRef& rInfo)  const
{
    return m_pSelectionBox->HasFieldByAliasName( rFieldName, rInfo);
}
// -----------------------------------------------------------------------------
SqlParseError OQueryDesignView::InsertField( const OTableFieldDescRef& rInfo, sal_Bool bVis, sal_Bool bActivate)
{
	return m_pSelectionBox->InsertField( rInfo, BROWSER_INVALIDID,bVis, bActivate ).isValid() ? eOk : eTooManyColumns;
}
// -----------------------------------------------------------------------------
sal_Int32 OQueryDesignView::getColWidth(sal_uInt16 _nColPos) const
{
    static sal_Int32 s_nDefaultWidth = GetTextWidth(String(RTL_CONSTASCII_USTRINGPARAM("0"))) * 15;
    sal_Int32 nWidth = static_cast<OQueryController&>(getController()).getColWidth(_nColPos);
    if ( !nWidth )
        nWidth = s_nDefaultWidth;
	return nWidth;
}
//------------------------------------------------------------------------------
void OQueryDesignView::fillValidFields(const ::rtl::OUString& sAliasName, ComboBox* pFieldList)
{
	DBG_ASSERT(pFieldList != NULL, "OQueryDesignView::FillValidFields : What the hell do you think I can do with a NULL-ptr ? This will crash !");
	pFieldList->Clear();

	sal_Bool bAllTables = sAliasName.getLength() == 0;

	OJoinTableView::OTableWindowMap* pTabWins = m_pTableView->GetTabWinMap();
	::rtl::OUString strCurrentPrefix;
	::std::vector< ::rtl::OUString> aFields;
	OJoinTableView::OTableWindowMap::iterator aIter = pTabWins->begin();
    OJoinTableView::OTableWindowMap::iterator aEnd  = pTabWins->end();
    for(;aIter != aEnd;++aIter)
	{
		OQueryTableWindow* pCurrentWin = static_cast<OQueryTableWindow*>(aIter->second);
		if (bAllTables || (pCurrentWin->GetAliasName() == sAliasName))
		{
			strCurrentPrefix = pCurrentWin->GetAliasName();
			strCurrentPrefix += ::rtl::OUString('.');

			pCurrentWin->EnumValidFields(aFields);

			::std::vector< ::rtl::OUString>::iterator aStrIter = aFields.begin();
            ::std::vector< ::rtl::OUString>::iterator aStrEnd = aFields.end();
			for(;aStrIter != aStrEnd;++aStrIter)
			{
				if (bAllTables || aStrIter->toChar() == '*')
					pFieldList->InsertEntry(::rtl::OUString(strCurrentPrefix) += *aStrIter);
				else
					pFieldList->InsertEntry(*aStrIter);
			}

			if (!bAllTables)
				// das heisst, dass ich in diesen Block kam, weil der Tabellenname genau der gesuchte war, also bin ich fertig
				// (dadurch verhindere ich auch das doppelte Einfuegen von Feldern, wenn eine Tabelle mehrmals als TabWin vorkommt)
				break;
		}
	}
}
// -----------------------------------------------------------------------------
long OQueryDesignView::PreNotify(NotifyEvent& rNEvt)
{
	switch (rNEvt.GetType())
	{
		case EVENT_GETFOCUS:
#if OSL_DEBUG_LEVEL > 0
			{
				Window* pFocus = Application::GetFocusWindow();
                (void)pFocus;
			}
#endif

			if ( m_pSelectionBox && m_pSelectionBox->HasChildPathFocus() )
				m_eChildFocus = SELECTION;
			else
				m_eChildFocus = TABLEVIEW;
			break;
	}

	return OQueryView::PreNotify(rNEvt);
}
//------------------------------------------------------------------------------


// -----------------------------------------------------------------------------
// check if the statement is correct when not returning false
sal_Bool OQueryDesignView::checkStatement()
{
	sal_Bool bRet = sal_True;
	if ( m_pSelectionBox )
		bRet = m_pSelectionBox->Save(); // a error occurred so we return no
	return bRet;
}
//-------------------------------------------------------------------------------
::rtl::OUString OQueryDesignView::getStatement()
{
	OQueryController& rController = static_cast<OQueryController&>(getController());
	m_rController.clearError();
	// used for fields which aren't any longer in the statement
	OTableFields& rUnUsedFields = rController.getUnUsedFields();
	OTableFields().swap( rUnUsedFields );

	// create the select columns
	sal_uInt32 nFieldcount = 0;
	OTableFields& rFieldList = rController.getTableFieldDesc();
	OTableFields::iterator aIter = rFieldList.begin();
    OTableFields::iterator aEnd = rFieldList.end();
	for(;aIter != aEnd;++aIter)
	{
		OTableFieldDescRef pEntryField = *aIter;
		if ( pEntryField->GetField().getLength() && pEntryField->IsVisible() )
			++nFieldcount;
		else if (pEntryField->GetField().getLength()			&&
				!pEntryField->HasCriteria()					&&
				pEntryField->isNoneFunction()				&&
				pEntryField->GetOrderDir() == ORDER_NONE	&&
                !pEntryField->IsGroupBy()                   &&
				!pEntryField->GetFunction().getLength() )
			rUnUsedFields.push_back(pEntryField);
	}
	if ( !nFieldcount )	// keine Felder sichtbar also zur"uck
	{
		rUnUsedFields = rFieldList;
		return ::rtl::OUString();
	}

	OQueryTableView::OTableWindowMap* pTabList   = m_pTableView->GetTabWinMap();
	sal_uInt32 nTabcount		= pTabList->size();

	::rtl::OUString	aFieldListStr(GenerateSelectList(this,rFieldList,nTabcount>1));
	if( !aFieldListStr.getLength() )
		return ::rtl::OUString();
	// Ausnahmebehandlung, wenn keine Felder angegeben worden sind
	// Dann darf die Tabpage nicht gewechselt werden
	// Im TabBarSelectHdl wird der SQL-::rtl::OUString auf STATEMENT_NOFIELDS abgefragt
	// und eine Errormeldung erzeugt
	// ----------------- Tabellenliste aufbauen ----------------------

	const ::std::vector<OTableConnection*>*	pConnList = m_pTableView->getTableConnections();
	Reference< XConnection> xConnection = rController.getConnection();
	::rtl::OUString aTableListStr(GenerateFromClause(xConnection,pTabList,pConnList));
	DBG_ASSERT(aTableListStr.getLength(), "OQueryDesignView::getStatement() : unerwartet : habe Felder, aber keine Tabellen !");
	// wenn es Felder gibt, koennen die nur durch Einfuegen aus einer schon existenten Tabelle entstanden sein; wenn andererseits
	// eine Tabelle geloescht wird, verschwinden auch die zugehoerigen Felder -> ergo KANN es das nicht geben, dass Felder
	// existieren, aber keine Tabellen (und aFieldListStr hat schon eine Laenge, das stelle ich oben sicher)
	::rtl::OUStringBuffer aHavingStr,aCriteriaListStr;
	// ----------------- Kriterien aufbauen ----------------------
	if (!GenerateCriterias(this,aCriteriaListStr,aHavingStr,rFieldList, nTabcount > 1))
		return ::rtl::OUString();

	::rtl::OUString aJoinCrit;
	GenerateInnerJoinCriterias(xConnection,aJoinCrit,pConnList);
	if(aJoinCrit.getLength())
	{
		::rtl::OUString aTmp = ::rtl::OUString::createFromAscii("( ");
		aTmp += aJoinCrit;
		aTmp += ::rtl::OUString::createFromAscii(" )");
		if(aCriteriaListStr.getLength())
		{
			aTmp += C_AND;
			aTmp += aCriteriaListStr.makeStringAndClear();
		}
		aCriteriaListStr = aTmp;
	}
	// ----------------- Statement aufbauen ----------------------
	::rtl::OUStringBuffer aSqlCmd(::rtl::OUString::createFromAscii("SELECT "));
	if(static_cast<OQueryController&>(getController()).isDistinct())
		aSqlCmd.append(::rtl::OUString::createFromAscii(" DISTINCT "));
	aSqlCmd.append(aFieldListStr);
	aSqlCmd.append(::rtl::OUString::createFromAscii(" FROM "));
	aSqlCmd.append(aTableListStr);

	if (aCriteriaListStr.getLength())
	{
		aSqlCmd.append(::rtl::OUString::createFromAscii(" WHERE "));
		aSqlCmd.append(aCriteriaListStr.makeStringAndClear());
	}
	// ----------------- GroupBy aufbauen und Anh"angen ------------
	Reference<XDatabaseMetaData> xMeta;
	if ( xConnection.is() )
		xMeta = xConnection->getMetaData();
	sal_Bool bUseAlias = nTabcount > 1;
	if ( xMeta.is() )
		bUseAlias = bUseAlias || !xMeta->supportsGroupByUnrelated();

	aSqlCmd.append(GenerateGroupBy(this,rFieldList,bUseAlias));
	// ----------------- having Anh"angen ------------
	if(aHavingStr.getLength())
	{
		aSqlCmd.append(::rtl::OUString::createFromAscii(" HAVING "));
		aSqlCmd.append(aHavingStr.makeStringAndClear());
	}
	// ----------------- Sortierung aufbauen und Anh"angen ------------
	::rtl::OUString sOrder;
	SqlParseError eErrorCode = eOk;
	if ( (eErrorCode = GenerateOrder(this,rFieldList,nTabcount > 1,sOrder)) == eOk)
		aSqlCmd.append(sOrder);
	else
	{
		if ( !m_rController.hasError() )
            m_rController.appendError( getParseErrorMessage( eErrorCode ) );

        m_rController.displayError();
	}

    ::rtl::OUString sSQL = aSqlCmd.makeStringAndClear();
    if ( xConnection.is() )
    {
        ::connectivity::OSQLParser& rParser( rController.getParser() );
        ::rtl::OUString sErrorMessage;
        ::std::auto_ptr<OSQLParseNode> pParseNode( rParser.parseTree( sErrorMessage, sSQL, sal_True ) );
        if ( pParseNode.get() )
        {
            OSQLParseNode* pNode = pParseNode->getChild(3)->getChild(1);
            if ( pNode->count() > 1 )
            {
		        ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1);
		        if ( pCondition ) // no where clause
                {
                    OSQLParseNode::compress(pCondition);
                    ::rtl::OUString sTemp;
                    pParseNode->parseNodeToStr(sTemp,xConnection);
                    sSQL = sTemp;
                }
            }
        }
    }
	return sSQL;
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
void OQueryDesignView::setSlotEnabled(sal_Int32 _nSlotId,sal_Bool _bEnable)
{
	sal_uInt16 nRow;
	switch (_nSlotId)
	{
		case SID_QUERY_VIEW_FUNCTIONS:
			nRow = BROW_FUNCTION_ROW;
			break;
		case SID_QUERY_VIEW_TABLES:
			nRow = BROW_TABLE_ROW;
			break;
		case SID_QUERY_VIEW_ALIASES:
			nRow = BROW_COLUMNALIAS_ROW;
			break;
		default:
			// ????????????
			nRow = 0;
			break;
	}
	m_pSelectionBox->SetRowVisible(nRow,_bEnable);
	m_pSelectionBox->Invalidate();
}
// -----------------------------------------------------------------------------
sal_Bool OQueryDesignView::isSlotEnabled(sal_Int32 _nSlotId)
{
	sal_uInt16 nRow;
	switch (_nSlotId)
	{
		case SID_QUERY_VIEW_FUNCTIONS:
			nRow = BROW_FUNCTION_ROW;
			break;
		case SID_QUERY_VIEW_TABLES:
			nRow = BROW_TABLE_ROW;
			break;
		case SID_QUERY_VIEW_ALIASES:
			nRow = BROW_COLUMNALIAS_ROW;
			break;
		default:
			// ?????????
			nRow = 0;
			break;
	}
	return m_pSelectionBox->IsRowVisible(nRow);
}
// -----------------------------------------------------------------------------
void OQueryDesignView::SaveUIConfig()
{
	OQueryController& rCtrl = static_cast<OQueryController&>(getController());
	rCtrl.SaveTabWinsPosSize( m_pTableView->GetTabWinMap(), m_pScrollWindow->GetHScrollBar()->GetThumbPos(), m_pScrollWindow->GetVScrollBar()->GetThumbPos() );
	//	rCtrl.SaveTabFieldsWidth( m_pSelectionBox );
	rCtrl.setVisibleRows( m_pSelectionBox->GetNoneVisibleRows() );
    if ( m_aSplitter.GetSplitPosPixel() != 0 )
	    rCtrl.setSplitPos( m_aSplitter.GetSplitPosPixel() );
}
// -----------------------------------------------------------------------------
OSQLParseNode* OQueryDesignView::getPredicateTreeFromEntry(OTableFieldDescRef pEntry,
														   const String& _sCriteria,
														   ::rtl::OUString& _rsErrorMessage,
														   Reference<XPropertySet>& _rxColumn) const
{
	OSL_ENSURE(pEntry.isValid(),"Entry is null!");
	if(!pEntry.isValid())
		return NULL;
	Reference< XConnection> xConnection = static_cast<OQueryController&>(getController()).getConnection();
	if(!xConnection.is())
		return NULL;

	::connectivity::OSQLParser& rParser( static_cast<OQueryController&>(getController()).getParser() );
	OQueryTableWindow* pWin = static_cast<OQueryTableWindow*>(pEntry->GetTabWindow());

	String sTest(_sCriteria);
	// special handling for functions
	if ( pEntry->GetFunctionType() & (FKT_OTHER | FKT_AGGREGATE | FKT_NUMERIC) )
	{
		// we have a function here so we have to distinguish the type of return value
		String sFunction;
		if ( pEntry->isNumericOrAggreateFunction() )
			sFunction = pEntry->GetFunction();

        if ( !sFunction.Len() )
			sFunction = pEntry->GetField();

		if(sFunction.GetTokenCount('(') > 1)
			sFunction = sFunction.GetToken(0,'('); // this should be the name of the function

		sal_Int32 nType = ::connectivity::OSQLParser::getFunctionReturnType(sFunction,&rParser.getContext());
		if ( nType == DataType::OTHER || (!sFunction.Len() && pEntry->isNumericOrAggreateFunction()) )
		{
			// first try the international version
			::rtl::OUString sSql;
			sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SELECT * "));
			sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" FROM x WHERE "));
			sSql += pEntry->GetField();
			sSql += _sCriteria;
            ::std::auto_ptr<OSQLParseNode> pParseNode( rParser.parseTree( _rsErrorMessage, sSql, sal_True ) );
			nType = DataType::DOUBLE;
			if ( pParseNode.get() )
			{
				OSQLParseNode* pColumnRef = pParseNode->getByRule(OSQLParseNode::column_ref);
				if ( pColumnRef )
				{
					OTableFieldDescRef aField = new OTableFieldDesc();
					if ( eOk == FillDragInfo(this,pColumnRef,aField) )
					{
						nType = aField->GetDataType();
					}
				}
			}
		}

		Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
		parse::OParseColumn* pColumn = new parse::OParseColumn(	pEntry->GetField(),
																::rtl::OUString(),
																::rtl::OUString(),
                                                                ::rtl::OUString(),
																ColumnValue::NULLABLE_UNKNOWN,
																0,
																0,
																nType,
																sal_False,
																sal_False,
																xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
		_rxColumn = pColumn;
		pColumn->setFunction(sal_True);
		pColumn->setRealName(pEntry->GetField());
	}
	else
	{
		if (pWin)
		{
			Reference<XNameAccess> xColumns = pWin->GetOriginalColumns();
			if (xColumns.is() && xColumns->hasByName(pEntry->GetField()))
				xColumns->getByName(pEntry->GetField()) >>= _rxColumn;
		}
	}

	OSQLParseNode* pParseNode = rParser.predicateTree(	_rsErrorMessage,
														sTest,
														static_cast<OQueryController&>(getController()).getNumberFormatter(),
														_rxColumn);
	return pParseNode;
}
// -----------------------------------------------------------------------------
void OQueryDesignView::GetFocus()
{
	OQueryView::GetFocus();
	if ( m_pSelectionBox && !m_pSelectionBox->HasChildPathFocus() )
	{
		// first we have to deactivate the current cell to refill when necessary
		m_pSelectionBox->DeactivateCell();
		m_pSelectionBox->ActivateCell(m_pSelectionBox->GetCurRow(), m_pSelectionBox->GetCurColumnId());
		m_pSelectionBox->GrabFocus();
	}
}
// -----------------------------------------------------------------------------
void OQueryDesignView::reset()
{
	m_pTableView->ClearAll();
	m_pTableView->ReSync();
}
// -----------------------------------------------------------------------------
void OQueryDesignView::setNoneVisbleRow(sal_Int32 _nRows)
{
	m_pSelectionBox->SetNoneVisbleRow(_nRows);
}

// -----------------------------------------------------------------------------
void OQueryDesignView::initByFieldDescriptions( const Sequence< PropertyValue >& i_rFieldDescriptions )
{
	OQueryController& rController = static_cast< OQueryController& >( getController() );

	m_pSelectionBox->PreFill();
	m_pSelectionBox->SetReadOnly( rController.isReadOnly() );
	m_pSelectionBox->Fill();

    for (   const PropertyValue* field = i_rFieldDescriptions.getConstArray();
            field != i_rFieldDescriptions.getConstArray() + i_rFieldDescriptions.getLength();
            ++field
        )
    {
        ::vos::ORef< OTableFieldDesc > pField( new OTableFieldDesc() );
        pField->Load( *field, true );
        InsertField( pField, sal_True, sal_False );
    }

    rController.ClearUndoManager();
	m_pSelectionBox->Invalidate();
}

// -----------------------------------------------------------------------------
bool OQueryDesignView::initByParseIterator( ::dbtools::SQLExceptionInfo* _pErrorInfo )
{
	SqlParseError eErrorCode = eNativeMode;
	m_rController.clearError();

    try
    {
        eErrorCode = InitFromParseNodeImpl( this, m_pSelectionBox );

        if ( eErrorCode != eOk )
	    {
	        if ( !m_rController.hasError() )
                m_rController.appendError( getParseErrorMessage( eErrorCode ) );

            if ( _pErrorInfo )
            {
                *_pErrorInfo = m_rController.getError();
            }
            else
            {
                m_rController.displayError();
            }
	    }
    }
    catch ( const Exception& )
    {
        DBG_UNHANDLED_EXCEPTION();
    }
	return eErrorCode == eOk;
}
//------------------------------------------------------------------------------
void OQueryDesignView::fillFunctionInfo(  const ::connectivity::OSQLParseNode* pNode
                                        ,const ::rtl::OUString& sFunctionTerm
                                        ,OTableFieldDescRef& aInfo)
{
    // get the type out of the function name
    OQueryController& rController = static_cast<OQueryController&>(getController());
	sal_Int32 nDataType = DataType::DOUBLE;
	::rtl::OUString sFieldName = sFunctionTerm;
	OSQLParseNode* pFunctionName = pNode->getChild(0);
	if ( !SQL_ISPUNCTUATION(pFunctionName,"{") )
	{
		if ( SQL_ISRULEOR2(pNode,length_exp,char_value_fct) )
			pFunctionName = pFunctionName->getChild(0);

		::rtl::OUString sFunctionName = pFunctionName->getTokenValue();
		if ( !sFunctionName.getLength() )
			sFunctionName = ::rtl::OStringToOUString(OSQLParser::TokenIDToStr(pFunctionName->getTokenID()),RTL_TEXTENCODING_UTF8);

		nDataType = OSQLParser::getFunctionReturnType(
							sFunctionName
							,&rController.getParser().getContext());
	}
	aInfo->SetDataType(nDataType);
	aInfo->SetFieldType(TAB_NORMAL_FIELD);
	aInfo->SetField(sFieldName);
	aInfo->SetTabWindow(NULL);
}
// -----------------------------------------------------------------------------