I had to drop XEventBroadcaster from the merged interface because it introduced method name conflicts (addEventListener). Shouldn't be an issue since it was scheduled to be dropped anyhow, and the service implementation still implements it, so existing clients will be fine. I dropped the interface XPropertySet from the combined IDL because nobody seems to be using it, and it's primary purpose appears to be to set weird flags. I dropped the optional interfaces XStatusIndicatorFactory XDispatchInformationProvider from the combined IDL because the service does not implement them, and nobody seems to be using them. I suspect they were mistakenly copied from XFrame. I also did not convert the Title, UserDefinedAttributes and LayoutManager properties to attributes, again because no-one is using them. Change-Id: I678a00006ed2cca2d6c37c4e39465811442c33af
3593 lines
165 KiB
C++
3593 lines
165 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||
/*
|
||
* This file is part of the LibreOffice project.
|
||
*
|
||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||
*
|
||
* This file incorporates work covered by the following license notice:
|
||
*
|
||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||
* contributor license agreements. See the NOTICE file distributed
|
||
* with this work for additional information regarding copyright
|
||
* ownership. The ASF licenses this file to you under the Apache
|
||
* License, Version 2.0 (the "License"); you may not use this file
|
||
* except in compliance with the License. You may obtain a copy of
|
||
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
||
*/
|
||
|
||
#include "QueryDesignView.hxx"
|
||
#include "QueryTableView.hxx"
|
||
#include "QTableWindow.hxx"
|
||
#include <vcl/toolbox.hxx>
|
||
#include "querycontroller.hxx"
|
||
#include <vcl/split.hxx>
|
||
#include <svl/undo.hxx>
|
||
#include <tools/diagnose_ex.h>
|
||
#include <osl/diagnose.h>
|
||
#include "adtabdlg.hxx"
|
||
#include <vcl/svapp.hxx>
|
||
#include <vcl/combobox.hxx>
|
||
#include <vcl/msgbox.hxx>
|
||
#include "browserids.hxx"
|
||
#include "SelectionBrowseBox.hxx"
|
||
#include "dbu_qry.hrc"
|
||
#include <unotools/configmgr.hxx>
|
||
#include <comphelper/extract.hxx>
|
||
#include <comphelper/string.hxx>
|
||
#include <comphelper/types.hxx>
|
||
#include <connectivity/dbtools.hxx>
|
||
#include <connectivity/dbexception.hxx>
|
||
#include <com/sun/star/i18n/XLocaleData.hpp>
|
||
#include <com/sun/star/sdbc/DataType.hpp>
|
||
#include <com/sun/star/container/XNameAccess.hpp>
|
||
#include <com/sun/star/sdbc/ColumnValue.hpp>
|
||
#include <connectivity/PColumn.hxx>
|
||
#include "QTableConnection.hxx"
|
||
#include "ConnectionLine.hxx"
|
||
#include "ConnectionLineData.hxx"
|
||
#include "QTableConnectionData.hxx"
|
||
#include "dbustrings.hrc"
|
||
#include "UITools.hxx"
|
||
#include "querycontainerwindow.hxx"
|
||
#include "sqlmessage.hxx"
|
||
#include <unotools/syslocale.hxx>
|
||
|
||
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;
|
||
|
||
// 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_CONSTASCII_USTRINGPARAM(" AND "));
|
||
static const ::rtl::OUString C_OR(RTL_CONSTASCII_USTRINGPARAM(" 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.isEmpty() )
|
||
{
|
||
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.isEmpty() )
|
||
_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.isEmpty() )
|
||
{
|
||
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,
|
||
const OConnectionLineDataVec* pLineDataList,
|
||
const OQueryTableConnectionData* pData)
|
||
{
|
||
::rtl::OUStringBuffer aCondition;
|
||
if ( _xConnection.is() )
|
||
{
|
||
OConnectionLineDataVec::const_iterator aIter = pLineDataList->begin();
|
||
OConnectionLineDataVec::const_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_FAIL("Failure while building Join criteria!");
|
||
}
|
||
}
|
||
|
||
return aCondition.makeStringAndClear();
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
/** JoinCycle looks for a join cycle and append it to the string
|
||
@param _xConnection the connection
|
||
@param _pEntryConn the table connection which holds the data
|
||
@param _pEntryTabTo the corresponding table window
|
||
@param _rJoin the String which will contain the resulting string
|
||
*/
|
||
void JoinCycle( const Reference< XConnection>& _xConnection,
|
||
OQueryTableConnection* _pEntryConn,
|
||
const OQueryTableWindow* _pEntryTabTo,
|
||
::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.isEmpty() && _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());
|
||
|
||
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(RTL_CONSTASCII_USTRINGPARAM(" "));
|
||
if ( generateAsBeforeTableAlias( _xConnection ) )
|
||
aTableListStr += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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,
|
||
const 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,
|
||
const OQueryTableWindow* pLh,
|
||
const OQueryTableWindow* pRh,
|
||
const OQueryTableConnectionData* pData
|
||
)
|
||
{
|
||
bool bForce = pData->GetJoinType() == CROSS_JOIN || pData->isNatural();
|
||
return BuildJoin(_xConnection,BuildTable(_xConnection,pLh,bForce),BuildTable(_xConnection,pRh,bForce),pData);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
::rtl::OUString BuildJoin( const Reference< XConnection>& _xConnection,
|
||
const ::rtl::OUString &rLh,
|
||
const OQueryTableWindow* pRh,
|
||
const OQueryTableConnectionData* pData
|
||
)
|
||
{
|
||
return BuildJoin(_xConnection,rLh,BuildTable(_xConnection,pRh),pData);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
::rtl::OUString BuildJoin( const Reference< XConnection>& _xConnection,
|
||
const OQueryTableWindow* pLh,
|
||
const ::rtl::OUString &rRh,
|
||
const OQueryTableConnectionData* pData
|
||
)
|
||
{
|
||
// strict ANSI SQL:
|
||
// - does not support any bracketing of JOINS
|
||
// - supports nested joins only in the LEFT HAND SIDE
|
||
// In this case, we are trying to build a join with a nested join
|
||
// in the right hand side.
|
||
// So switch the direction of the join and both hand sides.
|
||
OQueryTableConnectionData data(*pData);
|
||
switch (data.GetJoinType())
|
||
{
|
||
case LEFT_JOIN:
|
||
data.SetJoinType(RIGHT_JOIN);
|
||
break;
|
||
case RIGHT_JOIN:
|
||
data.SetJoinType(LEFT_JOIN);
|
||
break;
|
||
default:
|
||
// the other join types are symmetric, so nothing to change
|
||
break;
|
||
}
|
||
return BuildJoin(_xConnection, rRh, BuildTable(_xConnection,pLh), &data);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void 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;
|
||
|
||
if(aJoin.isEmpty())
|
||
{
|
||
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<6B>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
|
||
OSL_ENSURE(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) ));
|
||
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.isEmpty() && 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().isEmpty(),"No table field name!");
|
||
aTmpStr.append(::dbtools::quoteName(aQuote, rFieldName));
|
||
}
|
||
else
|
||
aTmpStr.append(rFieldName);
|
||
}
|
||
else
|
||
aTmpStr.append(rFieldName);
|
||
|
||
if ( pEntryField->isAggreateFunction() )
|
||
{
|
||
OSL_ENSURE(!pEntryField->GetFunction().isEmpty(),"Functionname darf hier nicht leer sein! ;-(");
|
||
::rtl::OUStringBuffer aTmpStr2( pEntryField->GetFunction());
|
||
aTmpStr2.appendAscii("(");
|
||
aTmpStr2.append(aTmpStr.makeStringAndClear());
|
||
aTmpStr2.appendAscii(")");
|
||
aTmpStr = aTmpStr2;
|
||
}
|
||
|
||
if (!rFieldAlias.isEmpty() &&
|
||
(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_FAIL("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.isEmpty())
|
||
continue;
|
||
aCriteria = pEntryField->GetCriteria( i );
|
||
if ( !aCriteria.isEmpty() )
|
||
{
|
||
// * 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.isEmpty()) // noch keine Kriterien
|
||
aHavingStr += ::rtl::OUString('('); // Klammern
|
||
else
|
||
aHavingStr += C_AND;
|
||
|
||
if ( pEntryField->isAggreateFunction() )
|
||
{
|
||
OSL_ENSURE(!pEntryField->GetFunction().isEmpty(),"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;
|
||
SAL_WNODEPRECATED_DECLARATIONS_PUSH
|
||
::std::auto_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(pEntryField,aTmp,aErrorMsg,xColumn));
|
||
SAL_WNODEPRECATED_DECLARATIONS_POP
|
||
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.isEmpty() ) // 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;
|
||
SAL_WNODEPRECATED_DECLARATIONS_PUSH
|
||
::std::auto_ptr< ::connectivity::OSQLParseNode> pParseNode( _pView->getPredicateTreeFromEntry(pEntryField,aTmp,aErrorMsg,xColumn));
|
||
SAL_WNODEPRECATED_DECLARATIONS_POP
|
||
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.isEmpty()) // noch keine Kriterien
|
||
aWhereStr += ::rtl::OUString('('); // Klammern
|
||
else
|
||
aWhereStr += C_AND;
|
||
aWhereStr += pEntryField->GetField();
|
||
}
|
||
}
|
||
if (!aWhereStr.isEmpty())
|
||
{
|
||
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.isEmpty())
|
||
{
|
||
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_FAIL("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().isEmpty() )
|
||
{
|
||
aWorkStr += ::dbtools::quoteName(aQuote, pEntryField->GetFieldAlias());
|
||
}
|
||
else if ( pEntryField->isNumericOrAggreateFunction() )
|
||
{
|
||
OSL_ENSURE(!pEntryField->GetFunction().isEmpty(),"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 += rtl::OUString( ";ASC;DESC" ).getToken( (sal_uInt16)eOrder, ';' );
|
||
aWorkStr += rtl::OUString(',');
|
||
}
|
||
}
|
||
|
||
{
|
||
String sTemp(comphelper::string::stripEnd(aWorkStr, ','));
|
||
aWorkStr = sTemp;
|
||
}
|
||
|
||
if ( !aWorkStr.isEmpty() )
|
||
{
|
||
const sal_Int32 nMaxOrder = xMetaData->getMaxColumnsInOrderBy();
|
||
String sToken(aWorkStr);
|
||
if ( nMaxOrder && nMaxOrder < comphelper::string::getTokenCount(sToken, ',') )
|
||
eErrorCode = eStatementTooLong;
|
||
else
|
||
{
|
||
_rsRet = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ORDER BY "));
|
||
_rsRet += aWorkStr;
|
||
}
|
||
}
|
||
}
|
||
catch(SQLException&)
|
||
{
|
||
OSL_FAIL("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.isEmpty())
|
||
_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);
|
||
++aConnectionCount[(*aIter)->GetSourceWin()];
|
||
++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.ascii );
|
||
::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.isEmpty())
|
||
{
|
||
// 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
|
||
// these are implemented as
|
||
// "FROM tbl1, tbl2 WHERE tbl1.col1=tlb2.col2"
|
||
// rather than
|
||
// "FROM tbl1 INNER JOIN tbl2 ON tbl1.col1=tlb2.col2"
|
||
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.isEmpty())
|
||
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() )
|
||
{
|
||
OSL_ENSURE(!pEntryField->GetField().isEmpty(),"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;
|
||
SAL_WNODEPRECATED_DECLARATIONS_PUSH
|
||
::std::auto_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(pEntryField,aTmp,aErrorMsg,xColumn));
|
||
SAL_WNODEPRECATED_DECLARATIONS_POP
|
||
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.isEmpty() )
|
||
{
|
||
aGroupByStr = aGroupByStr.replaceAt(aGroupByStr.getLength()-1,1, ::rtl::OUString(' ') );
|
||
::rtl::OUString aGroupByStr2(RTL_CONSTASCII_USTRINGPARAM(" GROUP BY "));
|
||
aGroupByStr2 += aGroupByStr;
|
||
aGroupByStr = aGroupByStr2;
|
||
}
|
||
}
|
||
catch(SQLException&)
|
||
{
|
||
OSL_FAIL("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_ISRULEOR3(pValueExp, general_set_fct, set_fct_spec, position_exp) ||
|
||
SQL_ISRULEOR3(pValueExp, extract_exp, fold, char_substring_fct) ||
|
||
SQL_ISRULEOR2(pValueExp, length_exp, char_value_fct))
|
||
{
|
||
AddFunctionCondition( _pView,
|
||
_pSelectionBrw,
|
||
pCondition,
|
||
nLevel,
|
||
bHaving,
|
||
bAddOrOnOneLine);
|
||
}
|
||
else
|
||
{
|
||
eErrorCode = eNoColumnInLike;
|
||
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).is() ? 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_ISRULEOR3(pFunction, general_set_fct, set_fct_spec, position_exp) ||
|
||
SQL_ISRULEOR3(pFunction, extract_exp, 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
|
||
// 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(RTL_CONSTASCII_USTRINGPARAM("*")), 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());
|
||
|
||
OSL_ENSURE(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(RTL_CONSTASCII_USTRINGPARAM(">"));
|
||
break;
|
||
case SQL_NODE_LESSEQ:
|
||
// take the opposite as we change the order
|
||
i--;
|
||
aCondition = aCondition + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(">="));
|
||
break;
|
||
case SQL_NODE_GREAT:
|
||
// take the opposite as we change the order
|
||
i--;
|
||
aCondition = aCondition + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("<"));
|
||
break;
|
||
case SQL_NODE_GREATEQ:
|
||
// take the opposite as we change the order
|
||
i--;
|
||
aCondition = aCondition + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("<="));
|
||
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);
|
||
OSL_ENSURE(!aColumnName.isEmpty(),"Columnname darf nicht leer sein");
|
||
if (aTableRange.isEmpty())
|
||
{
|
||
// 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)
|
||
{
|
||
OSL_ENSURE( 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<73>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).is())
|
||
(*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() )
|
||
{
|
||
OSL_FAIL( "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 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_FAIL("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<6D> 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_ISRULEOR3(pColumnRef, general_set_fct, set_fct_spec, position_exp) ||
|
||
SQL_ISRULEOR3(pColumnRef, extract_exp, 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());
|
||
|
||
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();
|
||
const OJoinTableView::OTableWindowMap::const_iterator aEnd = pTabList->end();
|
||
for(;aIter != aEnd;++aIter)
|
||
{
|
||
OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(aIter->second);
|
||
if (pTabWin->ExistsField( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")), 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(comphelper::string::stripEnd(aCol.GetToken(0,'('), ' '));
|
||
}
|
||
else
|
||
aInfo->SetFunctionType(nFunctionType|FKT_OTHER);
|
||
|
||
eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField);
|
||
bFirstField = sal_False;
|
||
}
|
||
else
|
||
{
|
||
::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;
|
||
}
|
||
|
||
OSL_FAIL( "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;
|
||
for( sal_uInt32 i=0 ; i<pNode->count() ; i++ )
|
||
{
|
||
OTableFieldDescRef aDragLeft = new OTableFieldDesc();
|
||
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.is() && 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< XComponentContext >& _rxContext)
|
||
:OQueryView( _pParent, _rController, _rxContext )
|
||
,m_aSplitter( this )
|
||
,m_eChildFocus(NONE)
|
||
,m_bInSplitHandler( sal_False )
|
||
{
|
||
DBG_CTOR(OQueryDesignView,NULL);
|
||
|
||
try
|
||
{
|
||
SvtSysLocale aSysLocale;
|
||
m_aLocale = aSysLocale.GetLanguageTag().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));
|
||
SAL_WNODEPRECATED_DECLARATIONS_PUSH
|
||
::std::auto_ptr<Window> aTemp(m_pSelectionBox);
|
||
SAL_WNODEPRECATED_DECLARATIONS_POP
|
||
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 ).is() ? 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)
|
||
{
|
||
OSL_ENSURE(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.isEmpty();
|
||
|
||
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(); // an 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().isEmpty() && pEntryField->IsVisible() )
|
||
++nFieldcount;
|
||
else if (!pEntryField->GetField().isEmpty() &&
|
||
!pEntryField->HasCriteria() &&
|
||
pEntryField->isNoneFunction() &&
|
||
pEntryField->GetOrderDir() == ORDER_NONE &&
|
||
!pEntryField->IsGroupBy() &&
|
||
pEntryField->GetFunction().isEmpty() )
|
||
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.isEmpty() )
|
||
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));
|
||
OSL_ENSURE(!aTableListStr.isEmpty(), "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.isEmpty())
|
||
{
|
||
::rtl::OUString aTmp(RTL_CONSTASCII_USTRINGPARAM("( "));
|
||
aTmp += aJoinCrit;
|
||
aTmp += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" )"));
|
||
if(aCriteriaListStr.getLength())
|
||
{
|
||
aTmp += C_AND;
|
||
aTmp += aCriteriaListStr.makeStringAndClear();
|
||
}
|
||
aCriteriaListStr = aTmp;
|
||
}
|
||
// ----------------- Statement aufbauen ----------------------
|
||
::rtl::OUStringBuffer aSqlCmd(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SELECT ")));
|
||
if(static_cast<OQueryController&>(getController()).isDistinct())
|
||
aSqlCmd.append(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" DISTINCT ")));
|
||
aSqlCmd.append(aFieldListStr);
|
||
aSqlCmd.append(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" FROM ")));
|
||
aSqlCmd.append(aTableListStr);
|
||
|
||
if (aCriteriaListStr.getLength())
|
||
{
|
||
aSqlCmd.append(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" 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(RTL_CONSTASCII_USTRINGPARAM(" 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;
|
||
SAL_WNODEPRECATED_DECLARATIONS_PUSH
|
||
::std::auto_ptr<OSQLParseNode> pParseNode( rParser.parseTree( sErrorMessage, sSQL, sal_True ) );
|
||
SAL_WNODEPRECATED_DECLARATIONS_POP
|
||
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.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.is(),"Entry is null!");
|
||
if(!pEntry.is())
|
||
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 (comphelper::string::getTokenCount(sFunction, '(') > 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;
|
||
SAL_WNODEPRECATED_DECLARATIONS_PUSH
|
||
::std::auto_ptr<OSQLParseNode> pParseNode( rParser.parseTree( _rsErrorMessage, sSql, sal_True ) );
|
||
SAL_WNODEPRECATED_DECLARATIONS_POP
|
||
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(),
|
||
::rtl::OUString(),
|
||
::rtl::OUString(),
|
||
::rtl::OUString());
|
||
_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
|
||
)
|
||
{
|
||
::rtl::Reference< 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;
|
||
}
|
||
|
||
// Utility function for fillFunctionInfo
|
||
namespace {
|
||
sal_Int32 char_datatype(const::connectivity::OSQLParseNode* pDataType, const unsigned int offset) {
|
||
int cnt = pDataType->count() - offset;
|
||
if ( cnt < 0 )
|
||
{
|
||
OSL_FAIL("internal error in decoding character datatype specification");
|
||
return DataType::VARCHAR;
|
||
}
|
||
else if ( cnt == 0 )
|
||
{
|
||
if ( offset == 0 )
|
||
{
|
||
// The datatype is the node itself
|
||
if ( SQL_ISTOKENOR2 (pDataType, CHARACTER, CHAR) )
|
||
return DataType::CHAR;
|
||
else if ( SQL_ISTOKEN (pDataType, VARCHAR) )
|
||
return DataType::VARCHAR;
|
||
else if ( SQL_ISTOKEN (pDataType, CLOB) )
|
||
return DataType::CLOB;
|
||
else
|
||
{
|
||
OSL_FAIL("unknown/unexpected token in decoding character datatype specification");
|
||
return DataType::VARCHAR;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// No child left to read!
|
||
OSL_FAIL("incomplete datatype in decoding character datatype specification");
|
||
return DataType::VARCHAR;
|
||
}
|
||
}
|
||
|
||
if ( SQL_ISTOKEN(pDataType->getChild(offset), NATIONAL) )
|
||
return char_datatype(pDataType, offset+1);
|
||
else if ( SQL_ISTOKENOR3(pDataType->getChild(offset), CHARACTER, CHAR, NCHAR) )
|
||
{
|
||
if ( cnt > 2 && SQL_ISTOKEN(pDataType->getChild(offset+1), LARGE) && SQL_ISTOKEN(pDataType->getChild(offset+2), OBJECT) )
|
||
return DataType::CLOB;
|
||
else if ( cnt > 1 && SQL_ISTOKEN(pDataType->getChild(offset+1), VARYING) )
|
||
return DataType::VARCHAR;
|
||
else
|
||
return DataType::CHAR;
|
||
}
|
||
else if ( SQL_ISTOKEN (pDataType->getChild(offset), VARCHAR) )
|
||
return DataType::VARCHAR;
|
||
else if ( SQL_ISTOKENOR2 (pDataType->getChild(offset), CLOB, NCLOB) )
|
||
return DataType::CLOB;
|
||
|
||
OSL_FAIL("unrecognised character datatype");
|
||
return DataType::VARCHAR;
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Try to guess the type of an expression in simple cases.
|
||
// Originally meant to be called only on a function call (hence the misnomer),
|
||
// but now tries to do the best it can also in other cases.
|
||
// Don't completely rely on fillFunctionInfo,
|
||
// it won't look at the function's arguments to find the return type
|
||
// (in particular, in the case of general_set_fct,
|
||
// the return type is the type of the argument;
|
||
// if that is (as is typical) a column reference,
|
||
// it is the type of the column).
|
||
// TODO: There is similar "guess the expression's type" code in several places:
|
||
// SelectionBrowseBox.cxx: OSelectionBrowseBox::saveField
|
||
// QueryDesignView.cxx: InstallFields, GetOrderCriteria, GetGroupCriteria
|
||
// If possible, they should be factorised into this function
|
||
// (which should then be renamed...)
|
||
|
||
void OQueryDesignView::fillFunctionInfo( const ::connectivity::OSQLParseNode* pNode
|
||
,const ::rtl::OUString& sFunctionTerm
|
||
,OTableFieldDescRef& aInfo)
|
||
{
|
||
// get the type of the expression, as far as easily possible
|
||
OQueryController& rController = static_cast<OQueryController&>(getController());
|
||
sal_Int32 nDataType = DataType::DOUBLE;
|
||
switch(pNode->getNodeType())
|
||
{
|
||
case SQL_NODE_CONCAT:
|
||
case SQL_NODE_STRING:
|
||
nDataType = DataType::VARCHAR;
|
||
break;
|
||
case SQL_NODE_INTNUM:
|
||
nDataType = DataType::INTEGER;
|
||
break;
|
||
case SQL_NODE_APPROXNUM:
|
||
nDataType = DataType::DOUBLE;
|
||
break;
|
||
case SQL_NODE_DATE:
|
||
case SQL_NODE_ACCESS_DATE:
|
||
nDataType = DataType::TIMESTAMP;
|
||
break;
|
||
case SQL_NODE_COMPARISON:
|
||
case SQL_NODE_EQUAL:
|
||
case SQL_NODE_LESS:
|
||
case SQL_NODE_GREAT:
|
||
case SQL_NODE_LESSEQ:
|
||
case SQL_NODE_GREATEQ:
|
||
case SQL_NODE_NOTEQUAL:
|
||
nDataType = DataType::BOOLEAN;
|
||
break;
|
||
case SQL_NODE_NAME:
|
||
case SQL_NODE_LISTRULE:
|
||
case SQL_NODE_COMMALISTRULE:
|
||
case SQL_NODE_KEYWORD:
|
||
case SQL_NODE_AMMSC: //??
|
||
case SQL_NODE_PUNCTUATION:
|
||
OSL_FAIL("Unexpected SQL Node Type");
|
||
break;
|
||
case SQL_NODE_RULE:
|
||
switch(pNode->getKnownRuleID())
|
||
{
|
||
case OSQLParseNode::select_statement:
|
||
case OSQLParseNode::table_exp:
|
||
case OSQLParseNode::table_ref_commalist:
|
||
case OSQLParseNode::table_ref:
|
||
case OSQLParseNode::catalog_name:
|
||
case OSQLParseNode::schema_name:
|
||
case OSQLParseNode::table_name:
|
||
case OSQLParseNode::opt_column_commalist:
|
||
case OSQLParseNode::column_commalist:
|
||
case OSQLParseNode::column_ref_commalist:
|
||
case OSQLParseNode::column_ref:
|
||
case OSQLParseNode::opt_order_by_clause:
|
||
case OSQLParseNode::ordering_spec_commalist:
|
||
case OSQLParseNode::ordering_spec:
|
||
case OSQLParseNode::opt_asc_desc:
|
||
case OSQLParseNode::where_clause:
|
||
case OSQLParseNode::opt_where_clause:
|
||
case OSQLParseNode::opt_escape:
|
||
case OSQLParseNode::scalar_exp_commalist:
|
||
case OSQLParseNode::scalar_exp: // Seems to never be generated?
|
||
case OSQLParseNode::parameter_ref:
|
||
case OSQLParseNode::parameter:
|
||
case OSQLParseNode::range_variable:
|
||
case OSQLParseNode::delete_statement_positioned:
|
||
case OSQLParseNode::delete_statement_searched:
|
||
case OSQLParseNode::update_statement_positioned:
|
||
case OSQLParseNode::update_statement_searched:
|
||
case OSQLParseNode::assignment_commalist:
|
||
case OSQLParseNode::assignment:
|
||
case OSQLParseNode::insert_statement:
|
||
case OSQLParseNode::insert_atom_commalist:
|
||
case OSQLParseNode::insert_atom:
|
||
case OSQLParseNode::from_clause:
|
||
case OSQLParseNode::qualified_join:
|
||
case OSQLParseNode::cross_union:
|
||
case OSQLParseNode::select_sublist:
|
||
case OSQLParseNode::join_type:
|
||
case OSQLParseNode::named_columns_join:
|
||
case OSQLParseNode::joined_table:
|
||
case OSQLParseNode::sql_not:
|
||
case OSQLParseNode::manipulative_statement:
|
||
case OSQLParseNode::value_exp_commalist:
|
||
case OSQLParseNode::union_statement:
|
||
case OSQLParseNode::outer_join_type:
|
||
case OSQLParseNode::selection:
|
||
case OSQLParseNode::base_table_def:
|
||
case OSQLParseNode::base_table_element_commalist:
|
||
case OSQLParseNode::data_type:
|
||
case OSQLParseNode::column_def:
|
||
case OSQLParseNode::table_node:
|
||
case OSQLParseNode::as: // Seems to never be generated?
|
||
case OSQLParseNode::op_column_commalist:
|
||
case OSQLParseNode::table_primary_as_range_column:
|
||
case OSQLParseNode::character_string_type:
|
||
OSL_FAIL("Unexpected SQL RuleID");
|
||
break;
|
||
case OSQLParseNode::column:
|
||
case OSQLParseNode::column_val:
|
||
OSL_FAIL("Cannot guess column type");
|
||
break;
|
||
case OSQLParseNode::values_or_query_spec:
|
||
OSL_FAIL("Cannot guess VALUES type");
|
||
break;
|
||
case OSQLParseNode::derived_column:
|
||
OSL_FAIL("Cannot guess computed column type");
|
||
break;
|
||
case OSQLParseNode::subquery:
|
||
OSL_FAIL("Cannot guess subquery return type");
|
||
break;
|
||
case OSQLParseNode::search_condition:
|
||
case OSQLParseNode::comparison_predicate:
|
||
case OSQLParseNode::between_predicate:
|
||
case OSQLParseNode::like_predicate:
|
||
case OSQLParseNode::test_for_null:
|
||
case OSQLParseNode::predicate_check: // Seems to never be generated?
|
||
case OSQLParseNode::boolean_term:
|
||
case OSQLParseNode::boolean_primary:
|
||
case OSQLParseNode::in_predicate:
|
||
case OSQLParseNode::existence_test:
|
||
case OSQLParseNode::unique_test:
|
||
case OSQLParseNode::all_or_any_predicate:
|
||
case OSQLParseNode::join_condition:
|
||
case OSQLParseNode::boolean_factor:
|
||
case OSQLParseNode::boolean_test:
|
||
case OSQLParseNode::comparison_predicate_part_2:
|
||
case OSQLParseNode::parenthesized_boolean_value_expression:
|
||
case OSQLParseNode::other_like_predicate_part_2:
|
||
case OSQLParseNode::between_predicate_part_2:
|
||
nDataType = DataType::BOOLEAN;
|
||
break;
|
||
case OSQLParseNode::num_value_exp:
|
||
case OSQLParseNode::extract_exp:
|
||
case OSQLParseNode::term:
|
||
case OSQLParseNode::factor:
|
||
// Might by an integer or a float; take the most generic
|
||
nDataType = DataType::DOUBLE;
|
||
break;
|
||
case OSQLParseNode::value_exp_primary:
|
||
case OSQLParseNode::value_exp:
|
||
case OSQLParseNode::odbc_call_spec:
|
||
// Really, we don't know. Let the default.
|
||
break;
|
||
case OSQLParseNode::position_exp:
|
||
case OSQLParseNode::length_exp:
|
||
nDataType = DataType::INTEGER;
|
||
break;
|
||
case OSQLParseNode::char_value_exp:
|
||
case OSQLParseNode::char_value_fct:
|
||
case OSQLParseNode::fold:
|
||
case OSQLParseNode::char_substring_fct:
|
||
case OSQLParseNode::char_factor:
|
||
case OSQLParseNode::concatenation:
|
||
nDataType = DataType::VARCHAR;
|
||
break;
|
||
case OSQLParseNode::datetime_primary:
|
||
nDataType = DataType::TIMESTAMP;
|
||
break;
|
||
case OSQLParseNode::bit_value_fct:
|
||
nDataType = DataType::BINARY;
|
||
break;
|
||
case OSQLParseNode::general_set_fct: // May depend on argument; ignore that for now
|
||
case OSQLParseNode::set_fct_spec:
|
||
{
|
||
if (pNode->count() == 0)
|
||
{
|
||
// This is not a function call, no sense to continue with a function return type lookup
|
||
OSL_FAIL("Got leaf SQL node where non-leaf expected");
|
||
break;
|
||
}
|
||
const OSQLParseNode* pFunctionName = pNode->getChild(0);
|
||
if ( SQL_ISPUNCTUATION(pFunctionName,"{") )
|
||
{
|
||
if ( pNode->count() == 3 )
|
||
return fillFunctionInfo( pNode->getChild(1), sFunctionTerm, aInfo );
|
||
else
|
||
OSL_FAIL("ODBC escape not in recognised form");
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
if ( SQL_ISRULEOR2(pNode,length_exp,char_value_fct) )
|
||
pFunctionName = pFunctionName->getChild(0);
|
||
|
||
::rtl::OUString sFunctionName = pFunctionName->getTokenValue();
|
||
if ( sFunctionName.isEmpty() )
|
||
sFunctionName = ::rtl::OStringToOUString(OSQLParser::TokenIDToStr(pFunctionName->getTokenID()),RTL_TEXTENCODING_UTF8);
|
||
|
||
nDataType = OSQLParser::getFunctionReturnType(
|
||
sFunctionName
|
||
,&rController.getParser().getContext());
|
||
}
|
||
break;
|
||
}
|
||
case OSQLParseNode::odbc_fct_spec:
|
||
{
|
||
if (pNode->count() != 2)
|
||
{
|
||
OSL_FAIL("interior of ODBC escape not in recognised shape");
|
||
break;
|
||
}
|
||
|
||
const OSQLParseNode* const pEscapeType = pNode->getChild(0);
|
||
if (SQL_ISTOKEN(pEscapeType, TS))
|
||
nDataType = DataType::TIMESTAMP;
|
||
else if (SQL_ISTOKEN(pEscapeType, D))
|
||
nDataType = DataType::DATE;
|
||
else if (SQL_ISTOKEN(pEscapeType, T))
|
||
nDataType = DataType::TIME;
|
||
else if (SQL_ISTOKEN(pEscapeType, FN))
|
||
return fillFunctionInfo( pNode->getChild(1), sFunctionTerm, aInfo );
|
||
else
|
||
OSL_FAIL("Unknown ODBC escape");
|
||
break;
|
||
}
|
||
case OSQLParseNode::cast_spec:
|
||
{
|
||
if ( pNode->count() != 6 || !SQL_ISTOKEN(pNode->getChild(3), AS) )
|
||
{
|
||
OSL_FAIL("CAST not in recognised shape");
|
||
break;
|
||
}
|
||
const OSQLParseNode *pCastTarget = pNode->getChild(4);
|
||
if ( SQL_ISTOKENOR2(pCastTarget, INTEGER, INT) )
|
||
nDataType = DataType::INTEGER;
|
||
else if ( SQL_ISTOKEN(pCastTarget, SMALLINT) )
|
||
nDataType = DataType::SMALLINT;
|
||
else if ( SQL_ISTOKEN(pCastTarget, BIGINT) )
|
||
nDataType = DataType::BIGINT;
|
||
else if ( SQL_ISTOKEN(pCastTarget, FLOAT) )
|
||
nDataType = DataType::FLOAT;
|
||
else if ( SQL_ISTOKEN(pCastTarget, REAL) )
|
||
nDataType = DataType::REAL;
|
||
else if ( SQL_ISTOKEN(pCastTarget, DOUBLE) )
|
||
nDataType = DataType::DOUBLE;
|
||
else if ( SQL_ISTOKEN(pCastTarget, BOOLEAN) )
|
||
nDataType = DataType::BOOLEAN;
|
||
else if ( SQL_ISTOKEN(pCastTarget, DATE) )
|
||
nDataType = DataType::DATE;
|
||
else if ( pCastTarget->count() > 0 )
|
||
{
|
||
const OSQLParseNode *pDataType = pCastTarget->getChild(0);
|
||
while (pDataType->count() > 0)
|
||
{
|
||
pCastTarget = pDataType;
|
||
pDataType = pDataType->getChild(0);
|
||
}
|
||
if ( SQL_ISTOKEN (pDataType, TIME) )
|
||
nDataType = DataType::TIME;
|
||
else if ( SQL_ISTOKEN (pDataType, TIMESTAMP) )
|
||
nDataType = DataType::TIMESTAMP;
|
||
else if ( SQL_ISTOKENOR3 (pDataType, CHARACTER, CHAR, NCHAR) )
|
||
nDataType = char_datatype(pCastTarget, 0);
|
||
else if ( SQL_ISTOKEN (pDataType, VARCHAR) )
|
||
nDataType = DataType::VARCHAR;
|
||
else if ( SQL_ISTOKEN (pDataType, CLOB) )
|
||
nDataType = DataType::CLOB;
|
||
else if ( SQL_ISTOKEN (pDataType, NATIONAL) )
|
||
nDataType = char_datatype(pCastTarget, 1);
|
||
else if ( SQL_ISTOKEN (pDataType, BINARY) )
|
||
{
|
||
if ( pCastTarget->count() > 2 && SQL_ISTOKEN(pCastTarget->getChild(1), LARGE) && SQL_ISTOKEN(pCastTarget->getChild(2), OBJECT) )
|
||
nDataType = DataType::BLOB;
|
||
else if ( pCastTarget->count() > 1 && SQL_ISTOKEN(pCastTarget->getChild(1), VARYING) )
|
||
nDataType = DataType::VARBINARY;
|
||
else
|
||
nDataType = DataType::BINARY;
|
||
}
|
||
else if ( SQL_ISTOKEN (pDataType, VARBINARY) )
|
||
nDataType = DataType::VARBINARY;
|
||
else if ( SQL_ISTOKEN (pDataType, BLOB) )
|
||
nDataType = DataType::BLOB;
|
||
else if ( SQL_ISTOKEN (pDataType, NUMERIC) )
|
||
nDataType = DataType::NUMERIC;
|
||
else if ( SQL_ISTOKENOR2 (pDataType, DECIMAL, DEC) )
|
||
nDataType = DataType::DECIMAL;
|
||
else if ( SQL_ISTOKEN (pDataType, FLOAT) )
|
||
nDataType = DataType::FLOAT;
|
||
else if ( SQL_ISTOKEN (pDataType, DOUBLE) )
|
||
nDataType = DataType::DOUBLE;
|
||
else if ( SQL_ISTOKEN (pDataType, TIME) )
|
||
nDataType = DataType::TIME;
|
||
else if ( SQL_ISTOKEN (pDataType, TIMESTAMP) )
|
||
nDataType = DataType::TIMESTAMP;
|
||
else if ( SQL_ISTOKEN (pDataType, INTERVAL) )
|
||
// Not in DataType published constant (because not in JDBC...)
|
||
nDataType = DataType::VARCHAR;
|
||
else
|
||
OSL_FAIL("Failed to decode CAST target");
|
||
}
|
||
else
|
||
OSL_FAIL("Could not decipher CAST target");
|
||
break;
|
||
}
|
||
default:
|
||
OSL_FAIL("Unknown SQL RuleID");
|
||
break;
|
||
}
|
||
break;
|
||
default:
|
||
OSL_FAIL("Unknown SQL Node Type");
|
||
break;
|
||
}
|
||
|
||
aInfo->SetDataType(nDataType);
|
||
aInfo->SetFieldType(TAB_NORMAL_FIELD);
|
||
aInfo->SetField(sFunctionTerm);
|
||
aInfo->SetTabWindow(NULL);
|
||
}
|
||
// -----------------------------------------------------------------------------
|
||
|
||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|