1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "QueryDesignView.hxx"
21 #include "QueryTableView.hxx"
22 #include "QTableWindow.hxx"
23 #include <vcl/toolbox.hxx>
24 #include "querycontroller.hxx"
25 #include "sqlbison.hxx"
26 #include <vcl/split.hxx>
27 #include <svl/undo.hxx>
28 #include <tools/diagnose_ex.h>
29 #include <osl/diagnose.h>
30 #include "adtabdlg.hxx"
31 #include <vcl/svapp.hxx>
32 #include <vcl/combobox.hxx>
33 #include <vcl/msgbox.hxx>
34 #include <vcl/layout.hxx>
35 #include "browserids.hxx"
36 #include "SelectionBrowseBox.hxx"
37 #include "dbu_qry.hrc"
38 #include <unotools/configmgr.hxx>
39 #include <comphelper/extract.hxx>
40 #include <comphelper/string.hxx>
41 #include <comphelper/types.hxx>
42 #include <connectivity/dbtools.hxx>
43 #include <connectivity/dbexception.hxx>
44 #include <com/sun/star/i18n/XLocaleData.hpp>
45 #include <com/sun/star/sdbc/DataType.hpp>
46 #include <com/sun/star/container/XNameAccess.hpp>
47 #include <com/sun/star/sdbc/ColumnValue.hpp>
48 #include <connectivity/PColumn.hxx>
49 #include "QTableConnection.hxx"
50 #include "ConnectionLine.hxx"
51 #include "ConnectionLineData.hxx"
52 #include "QTableConnectionData.hxx"
53 #include "dbustrings.hrc"
54 #include "UITools.hxx"
55 #include "querycontainerwindow.hxx"
56 #include "sqlmessage.hxx"
57 #include <unotools/syslocale.hxx>
58 #include <boost/scoped_ptr.hpp>
60 using namespace ::dbaui
;
61 using namespace ::utl
;
62 using namespace ::connectivity
;
63 using namespace ::dbtools
;
64 using namespace ::com::sun::star::uno
;
65 using namespace ::com::sun::star::lang
;
66 using namespace ::com::sun::star::i18n
;
67 using namespace ::com::sun::star::sdbc
;
68 using namespace ::com::sun::star::beans
;
69 using namespace ::com::sun::star::container
;
71 // here we define our functions used in the anonymous namespace to get our header file smaller
72 // please look at the book LargeScale C++ to know why
75 static const char C_AND
[] = " AND ";
76 static const char C_OR
[] = " OR ";
78 bool InsertJoin( const OQueryDesignView
* _pView
,
79 const ::connectivity::OSQLParseNode
*pNode
);
81 SqlParseError
InstallFields(OQueryDesignView
* _pView
,
82 const ::connectivity::OSQLParseNode
* pNode
,
83 OJoinTableView::OTableWindowMap
* pTabList
);
85 SqlParseError
GetGroupCriteria( OQueryDesignView
* _pView
,
86 OSelectionBrowseBox
* _pSelectionBrw
,
87 const ::connectivity::OSQLParseNode
* pSelectRoot
);
89 SqlParseError
GetHavingCriteria(OQueryDesignView
* _pView
,
90 OSelectionBrowseBox
* _pSelectionBrw
,
91 const ::connectivity::OSQLParseNode
* pSelectRoot
,
94 SqlParseError
GetOrderCriteria( OQueryDesignView
* _pView
,
95 OSelectionBrowseBox
* _pSelectionBrw
,
96 const ::connectivity::OSQLParseNode
* pParseRoot
);
98 SqlParseError
AddFunctionCondition(OQueryDesignView
* _pView
,
99 OSelectionBrowseBox
* _pSelectionBrw
,
100 const ::connectivity::OSQLParseNode
* pCondition
,
101 const sal_uInt16 nLevel
,
103 bool _bAddOrOnOneLine
);
105 OUString
quoteTableAlias(bool _bQuote
, const OUString
& _sAliasName
, const OUString
& _sQuote
)
108 if ( _bQuote
&& !_sAliasName
.isEmpty() )
110 sRet
= ::dbtools::quoteName(_sQuote
,_sAliasName
);
115 OUString
getTableRange(const OQueryDesignView
* _pView
,const ::connectivity::OSQLParseNode
* _pTableRef
)
117 Reference
< XConnection
> xConnection
= static_cast<OQueryController
&>(_pView
->getController()).getConnection();
118 OUString sTableRange
;
121 sTableRange
= ::connectivity::OSQLParseNode::getTableRange(_pTableRef
);
122 if ( sTableRange
.isEmpty() )
123 _pTableRef
->parseNodeToStr(sTableRange
,xConnection
,NULL
,false,false);
127 void insertConnection(const OQueryDesignView
* _pView
,const EJoinType
& _eJoinType
,OTableFieldDescRef _aDragLeft
,OTableFieldDescRef _aDragRight
,bool _bNatural
= false)
129 OQueryTableView
* pTableView
= static_cast<OQueryTableView
*>(_pView
->getTableView());
130 OQueryTableConnection
* pConn
= static_cast<OQueryTableConnection
*>( pTableView
->GetTabConn(static_cast<OTableWindow
*>(_aDragLeft
->GetTabWindow()),static_cast<OTableWindow
*>(_aDragRight
->GetTabWindow()),true));
134 OQueryTableConnectionData
* pInfoData
= new OQueryTableConnectionData();
135 TTableConnectionData::value_type
aInfoData(pInfoData
);
136 pInfoData
->InitFromDrag(_aDragLeft
, _aDragRight
);
137 pInfoData
->SetJoinType(_eJoinType
);
141 aInfoData
->ResetConnLines();
142 pInfoData
->setNatural(_bNatural
);
145 Reference
<XNameAccess
> xReferencedTableColumns(aInfoData
->getReferencedTable()->getColumns());
146 Sequence
< OUString
> aSeq
= aInfoData
->getReferencingTable()->getColumns()->getElementNames();
147 const OUString
* pIter
= aSeq
.getConstArray();
148 const OUString
* pEnd
= pIter
+ aSeq
.getLength();
149 for(;pIter
!= pEnd
;++pIter
)
151 if ( xReferencedTableColumns
->hasByName(*pIter
) )
152 aInfoData
->AppendConnLine(*pIter
,*pIter
);
155 catch( const Exception
& )
157 DBG_UNHANDLED_EXCEPTION();
161 ScopedVclPtrInstance
< OQueryTableConnection
> aInfo(pTableView
, aInfoData
);
162 // Because OQueryTableConnection never takes ownership of the data passed to it, but only remembers the pointer,
163 // this pointer to a local variable is not critical, as aInfoData and aInfo have the same lifetime
164 pTableView
->NotifyTabConnection( *aInfo
.get() );
168 OUString
aSourceFieldName(_aDragLeft
->GetField());
169 OUString
aDestFieldName(_aDragRight
->GetField());
170 // the connection could point on the other side
171 if(pConn
->GetSourceWin() == _aDragRight
->GetTabWindow())
173 OUString
aTmp(aSourceFieldName
);
174 aSourceFieldName
= aDestFieldName
;
175 aDestFieldName
= aTmp
;
177 pConn
->GetData()->AppendConnLine( aSourceFieldName
,aDestFieldName
);
178 pConn
->UpdateLineList();
182 pConn
->RecalcLines();
183 // for the following Invalidate, the new Connection must first be able
184 // to determine its BoundingRect
185 pConn
->InvalidateConnection();
188 OUString
ParseCondition( OQueryController
& rController
189 ,const ::connectivity::OSQLParseNode
* pCondition
190 ,const OUString
& _sDecimal
191 ,const ::com::sun::star::lang::Locale
& _rLocale
192 ,sal_uInt32 _nStartIndex
)
195 Reference
< XConnection
> xConnection
= rController
.getConnection();
196 if ( xConnection
.is() )
198 sal_uInt32 nCount
= pCondition
->count();
199 for(sal_uInt32 i
= _nStartIndex
; i
< nCount
; ++i
)
200 pCondition
->getChild(i
)->parseNodeToPredicateStr(aCondition
,
202 rController
.getNumberFormatter(),
204 static_cast<sal_Char
>(_sDecimal
.toChar()),
205 &rController
.getParser().getContext());
209 SqlParseError
FillOuterJoins(OQueryDesignView
* _pView
,
210 const ::connectivity::OSQLParseNode
* pTableRefList
)
212 SqlParseError eErrorCode
= eOk
;
213 sal_uInt32 nCount
= pTableRefList
->count();
215 for (sal_uInt32 i
=0; !bError
&& i
< nCount
; ++i
)
217 const ::connectivity::OSQLParseNode
* pParseNode
= pTableRefList
->getChild(i
);
218 const ::connectivity::OSQLParseNode
* pJoinNode
= NULL
;
220 if ( SQL_ISRULE( pParseNode
, qualified_join
) || SQL_ISRULE( pParseNode
, joined_table
) || SQL_ISRULE( pParseNode
, cross_union
) )
221 pJoinNode
= pParseNode
;
222 else if( SQL_ISRULE(pParseNode
,table_ref
)
223 && pParseNode
->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
224 pJoinNode
= pParseNode
->getChild(2);
228 if ( !InsertJoin(_pView
,pJoinNode
) )
232 // check if error occurred
234 eErrorCode
= eIllegalJoin
;
239 /** FillDragInfo fills the field description out of the table
241 SqlParseError
FillDragInfo( const OQueryDesignView
* _pView
,
242 const ::connectivity::OSQLParseNode
* pColumnRef
,
243 OTableFieldDescRef
& _rDragInfo
)
245 SqlParseError eErrorCode
= eOk
;
249 OUString aTableRange
,aColumnName
;
250 sal_uInt16 nCntAccount
;
251 ::connectivity::OSQLParseTreeIterator
& rParseIter
= static_cast<OQueryController
&>(_pView
->getController()).getParseIterator();
252 rParseIter
.getColumnRange( pColumnRef
, aColumnName
, aTableRange
);
254 if ( !aTableRange
.isEmpty() )
256 OQueryTableWindow
* pSTW
= static_cast<OQueryTableView
*>(_pView
->getTableView())->FindTable( aTableRange
);
257 bErg
= (pSTW
&& pSTW
->ExistsField( aColumnName
, _rDragInfo
) );
261 bErg
= static_cast<OQueryTableView
*>(_pView
->getTableView())->FindTableFromField(aColumnName
, _rDragInfo
, nCntAccount
);
263 bErg
= _pView
->HasFieldByAliasName(aColumnName
, _rDragInfo
);
267 eErrorCode
= eColumnNotFound
;
268 OUString
sError(ModuleRes(STR_QRY_COLUMN_NOT_FOUND
));
269 sError
= sError
.replaceFirst("$name$",aColumnName
);
270 _pView
->getController().appendError( sError
);
274 Reference
<XDatabaseMetaData
> xMeta
= _pView
->getController().getConnection()->getMetaData();
275 if ( xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers() )
276 _pView
->getController().appendError( OUString( ModuleRes( STR_QRY_CHECK_CASESENSITIVE
) ) );
285 OUString
BuildJoinCriteria( const Reference
< XConnection
>& _xConnection
,
286 const OConnectionLineDataVec
* pLineDataList
,
287 const OQueryTableConnectionData
* pData
)
289 OUStringBuffer aCondition
;
290 if ( _xConnection
.is() )
292 OConnectionLineDataVec::const_iterator aIter
= pLineDataList
->begin();
293 OConnectionLineDataVec::const_iterator aEnd
= pLineDataList
->end();
296 const Reference
< XDatabaseMetaData
> xMetaData
= _xConnection
->getMetaData();
297 const OUString aQuote
= xMetaData
->getIdentifierQuoteString();
298 const OUString
sEqual(" = ");
300 for(;aIter
!= aEnd
;++aIter
)
302 OConnectionLineDataRef pLineData
= *aIter
;
303 if(!aCondition
.isEmpty())
304 aCondition
.append(C_AND
);
305 aCondition
.append(quoteTableAlias(true,pData
->GetAliasName(JTCS_FROM
),aQuote
));
306 aCondition
.append(::dbtools::quoteName(aQuote
, pLineData
->GetFieldName(JTCS_FROM
) ));
307 aCondition
.append(sEqual
);
308 aCondition
.append(quoteTableAlias(true,pData
->GetAliasName(JTCS_TO
),aQuote
));
309 aCondition
.append(::dbtools::quoteName(aQuote
, pLineData
->GetFieldName(JTCS_TO
) ));
314 OSL_FAIL("Failure while building Join criteria!");
318 return aCondition
.makeStringAndClear();
320 /** JoinCycle looks for a join cycle and append it to the string
321 @param _xConnection the connection
322 @param _pEntryConn the table connection which holds the data
323 @param _pEntryTabTo the corresponding table window
324 @param _rJoin the String which will contain the resulting string
326 void JoinCycle( const Reference
< XConnection
>& _xConnection
,
327 OQueryTableConnection
* _pEntryConn
,
328 const OQueryTableWindow
* _pEntryTabTo
,
331 OSL_ENSURE(_pEntryConn
,"TableConnection can not be null!");
333 OQueryTableConnectionData
* pData
= static_cast< OQueryTableConnectionData
*>(_pEntryConn
->GetData().get());
334 if ( pData
->GetJoinType() != INNER_JOIN
&& _pEntryTabTo
->ExistsAVisitedConn() )
337 if(_rJoin
.endsWith(")"))
340 _rJoin
= _rJoin
.replaceAt(_rJoin
.getLength()-1,1,OUString(' '));
342 (_rJoin
+= C_AND
) += BuildJoinCriteria(_xConnection
,&pData
->GetConnLineDataList(),pData
);
345 _pEntryConn
->SetVisited(true);
348 OUString
BuildTable( const Reference
< XConnection
>& _xConnection
,
349 const OQueryTableWindow
* pEntryTab
,
353 OUString
aDBName(pEntryTab
->GetComposedName());
355 if( _xConnection
.is() )
359 Reference
< XDatabaseMetaData
> xMetaData
= _xConnection
->getMetaData();
361 OUString sCatalog
, sSchema
, sTable
;
362 ::dbtools::qualifiedNameComponents( xMetaData
, aDBName
, sCatalog
, sSchema
, sTable
, ::dbtools::eInDataManipulation
);
363 OUString aTableListStr
= ::dbtools::composeTableNameForSelect( _xConnection
, sCatalog
, sSchema
, sTable
);
365 OUString aQuote
= xMetaData
->getIdentifierQuoteString();
366 if ( _bForce
|| isAppendTableAliasEnabled( _xConnection
) || pEntryTab
->GetAliasName() != aDBName
)
368 aTableListStr
+= " ";
369 if ( generateAsBeforeTableAlias( _xConnection
) )
370 aTableListStr
+= "AS ";
371 aTableListStr
+= ::dbtools::quoteName( aQuote
, pEntryTab
->GetAliasName() );
373 aDBName
= aTableListStr
;
375 catch(const SQLException
&)
377 DBG_UNHANDLED_EXCEPTION();
382 OUString
BuildJoin( const Reference
< XConnection
>& _xConnection
,
385 const OQueryTableConnectionData
* pData
)
389 if ( pData
->isNatural() && pData
->GetJoinType() != CROSS_JOIN
)
391 switch(pData
->GetJoinType())
394 aErg
+= " LEFT OUTER ";
397 aErg
+= " RIGHT OUTER ";
400 OSL_ENSURE(!pData
->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!");
404 OSL_ENSURE(pData
->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!");
408 aErg
+= " FULL OUTER ";
413 if ( CROSS_JOIN
!= pData
->GetJoinType() && !pData
->isNatural() )
416 aErg
+= BuildJoinCriteria(_xConnection
,&pData
->GetConnLineDataList(),pData
);
421 OUString
BuildJoin( const Reference
< XConnection
>& _xConnection
,
422 const OQueryTableWindow
* pLh
,
423 const OQueryTableWindow
* pRh
,
424 const OQueryTableConnectionData
* pData
427 bool bForce
= pData
->GetJoinType() == CROSS_JOIN
|| pData
->isNatural();
428 return BuildJoin(_xConnection
,BuildTable(_xConnection
,pLh
,bForce
),BuildTable(_xConnection
,pRh
,bForce
),pData
);
430 OUString
BuildJoin( const Reference
< XConnection
>& _xConnection
,
432 const OQueryTableWindow
* pRh
,
433 const OQueryTableConnectionData
* pData
436 return BuildJoin(_xConnection
,rLh
,BuildTable(_xConnection
,pRh
),pData
);
438 OUString
BuildJoin( const Reference
< XConnection
>& _xConnection
,
439 const OQueryTableWindow
* pLh
,
441 const OQueryTableConnectionData
* pData
445 // - does not support any bracketing of JOINS
446 // - supports nested joins only in the LEFT HAND SIDE
447 // In this case, we are trying to build a join with a nested join
448 // in the right hand side.
449 // So switch the direction of the join and both hand sides.
450 OQueryTableConnectionData
data(*pData
);
451 switch (data
.GetJoinType())
454 data
.SetJoinType(RIGHT_JOIN
);
457 data
.SetJoinType(LEFT_JOIN
);
460 // the other join types are symmetric, so nothing to change
463 return BuildJoin(_xConnection
, rRh
, BuildTable(_xConnection
,pLh
), &data
);
465 typedef ::std::map
< OUString
,sal_Bool
,::comphelper::UStringMixLess
> tableNames_t
;
466 void addConnectionTableNames( const Reference
< XConnection
>& _xConnection
,
467 const OQueryTableConnection
* const pEntryConn
,
468 tableNames_t
&_rTableNames
)
470 // insert tables into table list to avoid double entries
471 const OQueryTableWindow
* const pEntryTabFrom
= static_cast<OQueryTableWindow
*>(pEntryConn
->GetSourceWin());
472 const OQueryTableWindow
* const pEntryTabTo
= static_cast<OQueryTableWindow
*>(pEntryConn
->GetDestWin());
474 OUString
sTabName(BuildTable(_xConnection
,pEntryTabFrom
));
475 if(_rTableNames
.find(sTabName
) == _rTableNames
.end())
476 _rTableNames
[sTabName
] = sal_True
;
477 sTabName
= BuildTable(_xConnection
,pEntryTabTo
);
478 if(_rTableNames
.find(sTabName
) == _rTableNames
.end())
479 _rTableNames
[sTabName
] = sal_True
;
481 void GetNextJoin( const Reference
< XConnection
>& _xConnection
,
482 OQueryTableConnection
* pEntryConn
,
483 OQueryTableWindow
* pEntryTabTo
,
485 tableNames_t
&_rTableNames
)
487 OQueryTableConnectionData
* pEntryConnData
= static_cast<OQueryTableConnectionData
*>(pEntryConn
->GetData().get());
488 if ( pEntryConnData
->GetJoinType() == INNER_JOIN
&& !pEntryConnData
->isNatural() )
493 addConnectionTableNames(_xConnection
, pEntryConn
, _rTableNames
);
494 OQueryTableWindow
* pEntryTabFrom
= static_cast<OQueryTableWindow
*>(pEntryConn
->GetSourceWin());
495 aJoin
= BuildJoin(_xConnection
,pEntryTabFrom
,pEntryTabTo
,pEntryConnData
);
497 else if(pEntryTabTo
== pEntryConn
->GetDestWin())
499 addConnectionTableNames(_xConnection
, pEntryConn
, _rTableNames
);
500 aJoin
= BuildJoin(_xConnection
,aJoin
,pEntryTabTo
,pEntryConnData
);
502 else if(pEntryTabTo
== pEntryConn
->GetSourceWin())
504 addConnectionTableNames(_xConnection
, pEntryConn
, _rTableNames
);
505 aJoin
= BuildJoin(_xConnection
,pEntryTabTo
,aJoin
,pEntryConnData
);
508 pEntryConn
->SetVisited(true);
510 // first search for the "to" window
511 const auto& rConnections
= pEntryConn
->GetParent()->getTableConnections();
512 auto aIter
= rConnections
.begin();
513 auto aEnd
= rConnections
.end();
514 for(;aIter
!= aEnd
;++aIter
)
516 OQueryTableConnection
* pNext
= static_cast<OQueryTableConnection
*>((*aIter
).get());
517 if(!pNext
->IsVisited() && (pNext
->GetSourceWin() == pEntryTabTo
|| pNext
->GetDestWin() == pEntryTabTo
))
519 OQueryTableWindow
* pEntryTab
= pNext
->GetSourceWin() == pEntryTabTo
? static_cast<OQueryTableWindow
*>(pNext
->GetDestWin()) : static_cast<OQueryTableWindow
*>(pNext
->GetSourceWin());
520 // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
521 JoinCycle(_xConnection
,pNext
,pEntryTab
,aJoin
);
522 if(!pNext
->IsVisited())
523 GetNextJoin(_xConnection
, pNext
, pEntryTab
, aJoin
, _rTableNames
);
527 // when nothing found found look for the "from" window
530 OQueryTableWindow
* pEntryTabFrom
= static_cast<OQueryTableWindow
*>(pEntryConn
->GetSourceWin());
531 aIter
= rConnections
.begin();
532 for(;aIter
!= aEnd
;++aIter
)
534 OQueryTableConnection
* pNext
= static_cast<OQueryTableConnection
*>((*aIter
).get());
535 if(!pNext
->IsVisited() && (pNext
->GetSourceWin() == pEntryTabFrom
|| pNext
->GetDestWin() == pEntryTabFrom
))
537 OQueryTableWindow
* pEntryTab
= pNext
->GetSourceWin() == pEntryTabFrom
? static_cast<OQueryTableWindow
*>(pNext
->GetDestWin()) : static_cast<OQueryTableWindow
*>(pNext
->GetSourceWin());
538 // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
539 JoinCycle(_xConnection
,pNext
,pEntryTab
,aJoin
);
540 if(!pNext
->IsVisited())
541 GetNextJoin(_xConnection
, pNext
, pEntryTab
, aJoin
, _rTableNames
);
546 SqlParseError
InsertJoinConnection( const OQueryDesignView
* _pView
,
547 const ::connectivity::OSQLParseNode
*pNode
,
548 const EJoinType
& _eJoinType
,
549 const ::connectivity::OSQLParseNode
*pLeftTable
,
550 const ::connectivity::OSQLParseNode
*pRightTable
)
552 SqlParseError eErrorCode
= eOk
;
553 if (pNode
->count() == 3 && // statement between brackets
554 SQL_ISPUNCTUATION(pNode
->getChild(0),"(") &&
555 SQL_ISPUNCTUATION(pNode
->getChild(2),")"))
557 eErrorCode
= InsertJoinConnection(_pView
,pNode
->getChild(1), _eJoinType
,pLeftTable
,pRightTable
);
559 else if (SQL_ISRULEOR2(pNode
,search_condition
,boolean_term
) && // AND/OR-joints:
562 // only allow AND joints
563 if (!SQL_ISTOKEN(pNode
->getChild(1),AND
))
564 eErrorCode
= eIllegalJoinCondition
;
565 else if ( eOk
== (eErrorCode
= InsertJoinConnection(_pView
,pNode
->getChild(0), _eJoinType
,pLeftTable
,pRightTable
)) )
566 eErrorCode
= InsertJoinConnection(_pView
,pNode
->getChild(2), _eJoinType
,pLeftTable
,pRightTable
);
568 else if (SQL_ISRULE(pNode
,comparison_predicate
))
570 // only the comparison of columns is allowed
571 OSL_ENSURE(pNode
->count() == 3,"OQueryDesignView::InsertJoinConnection: Error in Parse Tree");
572 if (!(SQL_ISRULE(pNode
->getChild(0),column_ref
) &&
573 SQL_ISRULE(pNode
->getChild(2),column_ref
) &&
574 pNode
->getChild(1)->getNodeType() == SQL_NODE_EQUAL
))
576 OUString
sError(ModuleRes(STR_QRY_JOIN_COLUMN_COMPARE
));
577 _pView
->getController().appendError( sError
);
581 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
582 OTableFieldDescRef aDragRight
= new OTableFieldDesc();
583 if ( eOk
!= ( eErrorCode
= FillDragInfo(_pView
,pNode
->getChild(0),aDragLeft
)) ||
584 eOk
!= ( eErrorCode
= FillDragInfo(_pView
,pNode
->getChild(2),aDragRight
)))
589 OQueryTableWindow
* pLeftWindow
= static_cast<OQueryTableView
*>(_pView
->getTableView())->FindTable( getTableRange(_pView
,pLeftTable
->getByRule(OSQLParseNode::table_ref
) ));
590 if ( pLeftWindow
== aDragLeft
->GetTabWindow() )
591 insertConnection(_pView
,_eJoinType
,aDragLeft
,aDragRight
);
593 insertConnection(_pView
,_eJoinType
,aDragRight
,aDragLeft
);
596 insertConnection(_pView
,_eJoinType
,aDragLeft
,aDragRight
);
599 eErrorCode
= eIllegalJoin
;
602 bool GetInnerJoinCriteria( const OQueryDesignView
* _pView
,
603 const ::connectivity::OSQLParseNode
*pCondition
)
605 return InsertJoinConnection(_pView
,pCondition
, INNER_JOIN
,NULL
,NULL
) != eOk
;
607 OUString
GenerateSelectList( const OQueryDesignView
* _pView
,
608 OTableFields
& _rFieldList
,
611 Reference
< XConnection
> xConnection
= static_cast<OQueryController
&>(_pView
->getController()).getConnection();
612 if ( !xConnection
.is() )
615 OUStringBuffer aTmpStr
,aFieldListStr
;
617 bool bAsterisk
= false;
619 OTableFields::iterator aIter
= _rFieldList
.begin();
620 OTableFields::iterator aEnd
= _rFieldList
.end();
621 for(;aIter
!= aEnd
;++aIter
)
623 OTableFieldDescRef pEntryField
= *aIter
;
624 if ( pEntryField
->IsVisible() )
626 if ( pEntryField
->GetField().toChar() == '*' )
636 const Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
637 const OUString aQuote
= xMetaData
->getIdentifierQuoteString();
639 OJoinTableView::OTableWindowMap
& rTabList
= _pView
->getTableView()->GetTabWinMap();
641 static const char sFieldSeparator
[] = ", ";
642 static const char s_sAs
[] = " AS ";
644 aIter
= _rFieldList
.begin();
645 for(;aIter
!= aEnd
;++aIter
)
647 OTableFieldDescRef pEntryField
= *aIter
;
648 OUString rFieldName
= pEntryField
->GetField();
649 if ( !rFieldName
.isEmpty() && pEntryField
->IsVisible() )
652 const OUString rAlias
= pEntryField
->GetAlias();
653 const OUString rFieldAlias
= pEntryField
->GetFieldAlias();
655 aTmpStr
.append(quoteTableAlias((bAlias
|| bAsterisk
),rAlias
,aQuote
));
657 // if we have a none numeric field, the table alias could be in the name
658 // otherwise we are not allowed to do this (e.g. 0.1 * PRICE )
659 if ( !pEntryField
->isOtherFunction() )
661 // we have to look if we have alias.* here but before we have to check if the column doesn't already exist
662 OTableFieldDescRef aInfo
= new OTableFieldDesc();
663 OJoinTableView::OTableWindowMap::iterator tableIter
= rTabList
.begin();
664 OJoinTableView::OTableWindowMap::iterator tableEnd
= rTabList
.end();
666 for(;!bFound
&& tableIter
!= tableEnd
;++tableIter
)
668 OQueryTableWindow
* pTabWin
= static_cast<OQueryTableWindow
*>(tableIter
->second
.get());
670 bFound
= pTabWin
->ExistsField( rFieldName
, aInfo
);
672 rFieldName
= aInfo
->GetField();
674 if ( ( rFieldName
.toChar() != '*' ) && ( rFieldName
.indexOf( aQuote
) == -1 ) )
676 OSL_ENSURE(!pEntryField
->GetTable().isEmpty(),"No table field name!");
677 aTmpStr
.append(::dbtools::quoteName(aQuote
, rFieldName
));
680 aTmpStr
.append(rFieldName
);
683 aTmpStr
.append(rFieldName
);
685 if ( pEntryField
->isAggreateFunction() )
687 OSL_ENSURE(!pEntryField
->GetFunction().isEmpty(),"Function name must not be empty! ;-(");
688 OUStringBuffer
aTmpStr2( pEntryField
->GetFunction());
689 aTmpStr2
.appendAscii("(");
690 aTmpStr2
.append(aTmpStr
.makeStringAndClear());
691 aTmpStr2
.appendAscii(")");
695 if (!rFieldAlias
.isEmpty() &&
696 (rFieldName
.toChar() != '*' ||
697 pEntryField
->isNumericOrAggreateFunction() ||
698 pEntryField
->isOtherFunction()))
700 aTmpStr
.append(s_sAs
);
701 aTmpStr
.append(::dbtools::quoteName(aQuote
, rFieldAlias
));
703 aFieldListStr
.append(aTmpStr
.makeStringAndClear());
704 aFieldListStr
.append(sFieldSeparator
);
707 if(!aFieldListStr
.isEmpty())
708 aFieldListStr
.setLength(aFieldListStr
.getLength()-2);
712 OSL_FAIL("Failure while building select list!");
714 return aFieldListStr
.makeStringAndClear();
716 bool GenerateCriterias( OQueryDesignView
* _pView
,
717 OUStringBuffer
& rRetStr
,
718 OUStringBuffer
& rHavingStr
,
719 OTableFields
& _rFieldList
,
722 OUString aFieldName
,aCriteria
,aWhereStr
,aHavingStr
,aWork
/*,aOrderStr*/;
723 // print line by line joined with AND
724 sal_uInt16 nMaxCriteria
= 0;
725 OTableFields::iterator aIter
= _rFieldList
.begin();
726 OTableFields::iterator aEnd
= _rFieldList
.end();
727 for(;aIter
!= aEnd
;++aIter
)
729 nMaxCriteria
= ::std::max
<sal_uInt16
>(nMaxCriteria
,(sal_uInt16
)(*aIter
)->GetCriteria().size());
731 Reference
< XConnection
> xConnection
= static_cast<OQueryController
&>(_pView
->getController()).getConnection();
732 if(!xConnection
.is())
736 const Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
737 const OUString aQuote
= xMetaData
->getIdentifierQuoteString();
738 const IParseContext
& rContext
= static_cast<OQueryController
&>(_pView
->getController()).getParser().getContext();
739 // * must not contain a filter : have I already shown the correct warning ?
740 bool bCritsOnAsterikWarning
= false; // ** TMFS **
742 for (sal_uInt16 i
=0 ; i
< nMaxCriteria
; i
++)
747 for(aIter
= _rFieldList
.begin();aIter
!= aEnd
;++aIter
)
749 OTableFieldDescRef pEntryField
= *aIter
;
750 aFieldName
= pEntryField
->GetField();
752 if (aFieldName
.isEmpty())
754 aCriteria
= pEntryField
->GetCriteria( i
);
755 if ( !aCriteria
.isEmpty() )
757 // * is not allowed to contain any filter, only when used in combination an aggregate function
758 if ( aFieldName
.toChar() == '*' && pEntryField
->isNoneFunction() )
760 // only show the messagebox the first time
761 if (!bCritsOnAsterikWarning
)
762 ScopedVclPtrInstance
<MessageDialog
>::Create(_pView
, ModuleRes( STR_QRY_CRITERIA_ON_ASTERISK
))->Execute();
763 bCritsOnAsterikWarning
= true;
766 aWork
= quoteTableAlias(bMulti
,pEntryField
->GetAlias(),aQuote
);
768 if ( (pEntryField
->GetFunctionType() & (FKT_OTHER
|FKT_NUMERIC
)) || (aFieldName
.toChar() == '*') )
771 aWork
+= ::dbtools::quoteName(aQuote
, aFieldName
);
773 if ( pEntryField
->isAggreateFunction() || pEntryField
->IsGroupBy() )
775 if (aHavingStr
.isEmpty()) // no more criteria
776 aHavingStr
+= "("; // bracket
780 if ( pEntryField
->isAggreateFunction() )
782 OSL_ENSURE(!pEntryField
->GetFunction().isEmpty(),"No function name for aggregate given!");
783 aHavingStr
+= pEntryField
->GetFunction();
784 aHavingStr
+= "("; // bracket
786 aHavingStr
+= ")"; // bracket
791 OUString aTmp
= aCriteria
;
793 Reference
<XPropertySet
> xColumn
;
794 boost::scoped_ptr
< ::connectivity::OSQLParseNode
> pParseNode(_pView
->getPredicateTreeFromEntry(pEntryField
,aTmp
,aErrorMsg
,xColumn
));
795 if (pParseNode
.get())
797 if (bMulti
&& !(pEntryField
->isOtherFunction() || (aFieldName
.toChar() == '*')))
798 pParseNode
->replaceNodeValue(pEntryField
->GetAlias(),aFieldName
);
799 OUString sHavingStr
= aHavingStr
;
801 sal_uInt32 nCount
= pParseNode
->count();
802 for( sal_uInt32 node
= 1 ; node
< nCount
; ++node
)
803 pParseNode
->getChild(node
)->parseNodeToStr( sHavingStr
,
807 !pEntryField
->isOtherFunction());
808 aHavingStr
= sHavingStr
;
811 aHavingStr
+= aCriteria
;
815 if ( aWhereStr
.isEmpty() ) // no more criteria
816 aWhereStr
+= "("; // bracket
821 // aCriteria could have some german numbers so I have to be sure here
822 OUString aTmp
= aCriteria
;
824 Reference
<XPropertySet
> xColumn
;
825 boost::scoped_ptr
< ::connectivity::OSQLParseNode
> pParseNode( _pView
->getPredicateTreeFromEntry(pEntryField
,aTmp
,aErrorMsg
,xColumn
));
826 if (pParseNode
.get())
828 if (bMulti
&& !(pEntryField
->isOtherFunction() || (aFieldName
.toChar() == '*')))
829 pParseNode
->replaceNodeValue(pEntryField
->GetAlias(),aFieldName
);
830 OUString aWhere
= aWhereStr
;
831 pParseNode
->parseNodeToStr( aWhere
,
835 !pEntryField
->isOtherFunction() );
840 aWhereStr
+= aWork
+ "=" + aCriteria
;
844 // only once for each field
845 else if ( !i
&& pEntryField
->isCondition() )
847 if (aWhereStr
.isEmpty()) // no more criteria
848 aWhereStr
+= "("; // bracket
851 aWhereStr
+= pEntryField
->GetField();
854 if (!aWhereStr
.isEmpty())
856 aWhereStr
+= ")"; // close bracket for the AND branch
857 if (!rRetStr
.isEmpty()) // are there conditions on the field?
858 rRetStr
.append(C_OR
);
859 else // open bracket for the OR branch
861 rRetStr
.append(aWhereStr
);
863 if (!aHavingStr
.isEmpty())
865 aHavingStr
+= ")"; // close bracket for the AND branch
866 if (!rHavingStr
.isEmpty()) // are there conditions on the field?
867 rHavingStr
.append(C_OR
);
868 else // Open bracket for the OR branch
869 rHavingStr
.append('(');
870 rHavingStr
.append(aHavingStr
);
874 if (!rRetStr
.isEmpty())
875 rRetStr
.append(')'); // close bracket for the OR branch
876 if (!rHavingStr
.isEmpty())
877 rHavingStr
.append(')'); // close bracket for the OR branch
881 OSL_FAIL("Failure while building where clause!");
885 SqlParseError
GenerateOrder( OQueryDesignView
* _pView
,
886 OTableFields
& _rFieldList
,
890 const OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
891 Reference
< XConnection
> xConnection
= rController
.getConnection();
892 if ( !xConnection
.is() )
893 return eNoConnection
;
895 SqlParseError eErrorCode
= eOk
;
897 OUString aColumnName
;
901 const bool bColumnAliasInOrderBy
= rController
.getSdbMetaData().supportsColumnAliasInOrderBy();
902 Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
903 OUString aQuote
= xMetaData
->getIdentifierQuoteString();
904 // * must not containa filter - have I already shown the warning?
905 bool bCritsOnAsterikWarning
= false; // ** TMFS **
906 OTableFields::iterator aIter
= _rFieldList
.begin();
907 OTableFields::iterator aEnd
= _rFieldList
.end();
908 for(;aIter
!= aEnd
;++aIter
)
910 OTableFieldDescRef pEntryField
= *aIter
;
911 EOrderDir eOrder
= pEntryField
->GetOrderDir();
912 // only create a sort expression when the table name and the sort criteria are defined
913 // otherwise they will be built in GenerateCriteria
914 if ( eOrder
!= ORDER_NONE
)
916 aColumnName
= pEntryField
->GetField();
917 if(aColumnName
.toChar() == '*')
919 // only show the MessageBox the first time
920 if (!bCritsOnAsterikWarning
)
921 ScopedVclPtrInstance
<MessageDialog
>::Create(_pView
, ModuleRes( STR_QRY_ORDERBY_ON_ASTERISK
))->Execute();
922 bCritsOnAsterikWarning
= true;
926 if ( bColumnAliasInOrderBy
&& !pEntryField
->GetFieldAlias().isEmpty() )
928 aWorkStr
+= ::dbtools::quoteName(aQuote
, pEntryField
->GetFieldAlias());
930 else if ( pEntryField
->isNumericOrAggreateFunction() )
932 OSL_ENSURE(!pEntryField
->GetFunction().isEmpty(),"Function name cannot be empty! ;-(");
933 aWorkStr
+= pEntryField
->GetFunction();
934 aWorkStr
+= OUString('(');
935 aWorkStr
+= quoteTableAlias(bMulti
,pEntryField
->GetAlias(),aQuote
);
936 // only quote column name when we don't have a numeric
937 if ( pEntryField
->isNumeric() )
938 aWorkStr
+= aColumnName
;
940 aWorkStr
+= ::dbtools::quoteName(aQuote
, aColumnName
);
942 aWorkStr
+= OUString(')');
944 else if ( pEntryField
->isOtherFunction() )
946 aWorkStr
+= aColumnName
;
950 aWorkStr
+= quoteTableAlias(bMulti
,pEntryField
->GetAlias(),aQuote
);
951 aWorkStr
+= ::dbtools::quoteName(aQuote
, aColumnName
);
954 aWorkStr
+= OUString( ";ASC;DESC" ).getToken( (sal_uInt16
)eOrder
, ';' );
960 OUString
sTemp(comphelper::string::stripEnd(aWorkStr
, ','));
964 if ( !aWorkStr
.isEmpty() )
966 const sal_Int32 nMaxOrder
= xMetaData
->getMaxColumnsInOrderBy();
967 OUString
sToken(aWorkStr
);
968 if ( nMaxOrder
&& nMaxOrder
< comphelper::string::getTokenCount(sToken
, ',') )
969 eErrorCode
= eStatementTooLong
;
972 _rsRet
= " ORDER BY " + aWorkStr
;
978 OSL_FAIL("Failure while building group by!");
984 void GenerateInnerJoinCriterias(const Reference
< XConnection
>& _xConnection
,
985 OUString
& _rJoinCrit
,
986 const ::std::vector
<VclPtr
<OTableConnection
> >& _rConnList
)
988 auto aIter
= _rConnList
.begin();
989 auto aEnd
= _rConnList
.end();
990 for(;aIter
!= aEnd
;++aIter
)
992 const OQueryTableConnection
* pEntryConn
= static_cast<const OQueryTableConnection
*>((*aIter
).get());
993 OQueryTableConnectionData
* pEntryConnData
= static_cast<OQueryTableConnectionData
*>(pEntryConn
->GetData().get());
994 if ( pEntryConnData
->GetJoinType() == INNER_JOIN
&& !pEntryConnData
->isNatural() )
996 if(!_rJoinCrit
.isEmpty())
998 _rJoinCrit
+= BuildJoinCriteria(_xConnection
,&pEntryConnData
->GetConnLineDataList(),pEntryConnData
);
1002 void searchAndAppendName(const Reference
< XConnection
>& _xConnection
,
1003 const OQueryTableWindow
* _pTableWindow
,
1004 tableNames_t
& _rTableNames
,
1005 OUString
& _rsTableListStr
1008 OUString
sTabName(BuildTable(_xConnection
,_pTableWindow
));
1010 if(_rTableNames
.find(sTabName
) == _rTableNames
.end())
1012 _rTableNames
[sTabName
] = sal_True
;
1013 _rsTableListStr
+= sTabName
;
1014 _rsTableListStr
+= ",";
1017 OUString
GenerateFromClause( const Reference
< XConnection
>& _xConnection
,
1018 const OQueryTableView::OTableWindowMap
* pTabList
,
1019 const ::std::vector
<VclPtr
<OTableConnection
> >& rConnList
1023 OUString aTableListStr
;
1024 // used to avoid putting a table twice in FROM clause
1025 tableNames_t aTableNames
;
1027 // generate outer join clause in from
1028 if(!rConnList
.empty())
1030 auto aIter
= rConnList
.begin();
1031 auto aEnd
= rConnList
.end();
1032 ::std::map
<OTableWindow
*,sal_Int32
> aConnectionCount
;
1033 for(;aIter
!= aEnd
;++aIter
)
1035 static_cast<OQueryTableConnection
*>((*aIter
).get())->SetVisited(false);
1036 ++aConnectionCount
[(*aIter
)->GetSourceWin()];
1037 ++aConnectionCount
[(*aIter
)->GetDestWin()];
1039 ::std::multimap
<sal_Int32
, OTableWindow
*> aMulti
;
1040 ::std::map
<OTableWindow
*,sal_Int32
>::iterator aCountIter
= aConnectionCount
.begin();
1041 ::std::map
<OTableWindow
*,sal_Int32
>::iterator aCountEnd
= aConnectionCount
.end();
1042 for(;aCountIter
!= aCountEnd
;++aCountIter
)
1044 aMulti
.insert(::std::multimap
<sal_Int32
, OTableWindow
*>::value_type(aCountIter
->second
,aCountIter
->first
));
1047 const bool bUseEscape
= ::dbtools::getBooleanDataSourceSetting( _xConnection
, PROPERTY_OUTERJOINESCAPE
);
1048 ::std::multimap
<sal_Int32
, OTableWindow
*>::reverse_iterator aRIter
= aMulti
.rbegin();
1049 ::std::multimap
<sal_Int32
, OTableWindow
*>::reverse_iterator aREnd
= aMulti
.rend();
1050 for(;aRIter
!= aREnd
;++aRIter
)
1052 auto aConIter
= aRIter
->second
->getTableView()->getTableConnections(aRIter
->second
);
1053 for(;aConIter
!= aEnd
;++aConIter
)
1055 OQueryTableConnection
* pEntryConn
= static_cast<OQueryTableConnection
*>((*aConIter
).get());
1056 if(!pEntryConn
->IsVisited() && pEntryConn
->GetSourceWin() == aRIter
->second
)
1059 GetNextJoin(_xConnection
,
1061 static_cast<OQueryTableWindow
*>(pEntryConn
->GetDestWin()),
1065 if(!aJoin
.isEmpty())
1068 switch(static_cast<OQueryTableConnectionData
*>(pEntryConn
->GetData().get())->GetJoinType())
1074 // create outer join
1087 aTableListStr
+= aStr
;
1093 // and now all inner joins
1094 // these are implemented as
1095 // "FROM tbl1, tbl2 WHERE tbl1.col1=tlb2.col2"
1097 // "FROM tbl1 INNER JOIN tbl2 ON tbl1.col1=tlb2.col2"
1098 aIter
= rConnList
.begin();
1099 for(;aIter
!= aEnd
;++aIter
)
1101 OQueryTableConnection
* pEntryConn
= static_cast<OQueryTableConnection
*>((*aIter
).get());
1102 if(!pEntryConn
->IsVisited())
1104 searchAndAppendName(_xConnection
,
1105 static_cast<OQueryTableWindow
*>(pEntryConn
->GetSourceWin()),
1109 searchAndAppendName(_xConnection
,
1110 static_cast<OQueryTableWindow
*>(pEntryConn
->GetDestWin()),
1116 // all tables that haven't a connection to anyone
1117 OQueryTableView::OTableWindowMap::const_iterator aTabIter
= pTabList
->begin();
1118 OQueryTableView::OTableWindowMap::const_iterator aTabEnd
= pTabList
->end();
1119 for(;aTabIter
!= aTabEnd
;++aTabIter
)
1121 const OQueryTableWindow
* pEntryTab
= static_cast<const OQueryTableWindow
*>(aTabIter
->second
.get());
1122 if(!pEntryTab
->ExistsAConn())
1124 aTableListStr
+= BuildTable(_xConnection
,pEntryTab
);
1125 aTableListStr
+= ",";
1129 if(!aTableListStr
.isEmpty())
1130 aTableListStr
= aTableListStr
.replaceAt(aTableListStr
.getLength()-1,1, OUString() );
1131 return aTableListStr
;
1133 OUString
GenerateGroupBy(const OQueryDesignView
* _pView
,OTableFields
& _rFieldList
, bool bMulti
)
1135 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
1136 const Reference
< XConnection
> xConnection
= rController
.getConnection();
1137 if(!xConnection
.is())
1140 ::std::map
< OUString
,bool> aGroupByNames
;
1142 OUString aGroupByStr
;
1145 const Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
1146 const OUString aQuote
= xMetaData
->getIdentifierQuoteString();
1148 OTableFields::iterator aIter
= _rFieldList
.begin();
1149 OTableFields::iterator aEnd
= _rFieldList
.end();
1150 for(;aIter
!= aEnd
;++aIter
)
1152 OTableFieldDescRef pEntryField
= *aIter
;
1153 if ( pEntryField
->IsGroupBy() )
1155 OSL_ENSURE(!pEntryField
->GetField().isEmpty(),"No Field Name available!;-(");
1156 OUString sGroupByPart
= quoteTableAlias(bMulti
,pEntryField
->GetAlias(),aQuote
);
1158 // only quote the field name when it isn't calculated
1159 if ( pEntryField
->isNoneFunction() )
1161 sGroupByPart
+= ::dbtools::quoteName(aQuote
, pEntryField
->GetField());
1165 OUString aTmp
= pEntryField
->GetField();
1167 Reference
<XPropertySet
> xColumn
;
1168 boost::scoped_ptr
< ::connectivity::OSQLParseNode
> pParseNode(_pView
->getPredicateTreeFromEntry(pEntryField
,aTmp
,aErrorMsg
,xColumn
));
1169 if (pParseNode
.get())
1172 pParseNode
->getChild(0)->parseNodeToStr( sGroupBy
,
1174 &rController
.getParser().getContext(),
1176 !pEntryField
->isOtherFunction());
1177 sGroupByPart
+= sGroupBy
;
1180 sGroupByPart
+= pEntryField
->GetField();
1182 if ( aGroupByNames
.find(sGroupByPart
) == aGroupByNames
.end() )
1184 aGroupByNames
.insert(::std::map
< OUString
,bool>::value_type(sGroupByPart
,true));
1185 aGroupByStr
+= sGroupByPart
;
1190 if ( !aGroupByStr
.isEmpty() )
1192 aGroupByStr
= aGroupByStr
.replaceAt(aGroupByStr
.getLength()-1,1, OUString(' ') );
1193 OUString
aGroupByStr2(" GROUP BY ");
1194 aGroupByStr2
+= aGroupByStr
;
1195 aGroupByStr
= aGroupByStr2
;
1198 catch(SQLException
&)
1200 OSL_FAIL("Failure while building group by!");
1204 SqlParseError
GetORCriteria(OQueryDesignView
* _pView
,
1205 OSelectionBrowseBox
* _pSelectionBrw
,
1206 const ::connectivity::OSQLParseNode
* pCondition
,
1207 sal_uInt16
& nLevel
,
1208 bool bHaving
= false,
1209 bool bAddOrOnOneLine
= false);
1210 SqlParseError
GetSelectionCriteria( OQueryDesignView
* _pView
,
1211 OSelectionBrowseBox
* _pSelectionBrw
,
1212 const ::connectivity::OSQLParseNode
* pNode
,
1213 sal_uInt16
& rLevel
)
1215 if (!pNode
|| !SQL_ISRULE(pNode
, select_statement
))
1216 return eNoSelectStatement
;
1218 // nyi: more checking for the correct structure!
1219 pNode
= pNode
->getChild(3)->getChild(1);
1220 // no where clause found
1221 if (!pNode
|| pNode
->isLeaf())
1224 // Next free sentence...
1225 SqlParseError eErrorCode
= eOk
;
1226 ::connectivity::OSQLParseNode
* pCondition
= pNode
->getChild(1);
1227 if ( pCondition
) // no where clause
1229 // now we have to check the other conditions
1230 // first make the logical easier
1231 ::connectivity::OSQLParseNode::negateSearchCondition(pCondition
);
1232 ::connectivity::OSQLParseNode
*pNodeTmp
= pNode
->getChild(1);
1234 ::connectivity::OSQLParseNode::disjunctiveNormalForm(pNodeTmp
);
1235 pNodeTmp
= pNode
->getChild(1);
1236 ::connectivity::OSQLParseNode::absorptions(pNodeTmp
);
1237 pNodeTmp
= pNode
->getChild(1);
1238 // compress sort the criteria @see http://www.openoffice.org/issues/show_bug.cgi?id=24079
1239 OSQLParseNode::compress(pNodeTmp
);
1240 pNodeTmp
= pNode
->getChild(1);
1242 // first extract the inner joins conditions
1243 GetInnerJoinCriteria(_pView
,pNodeTmp
);
1244 // now simplify again, join are checked in ComparisonPredicate
1245 ::connectivity::OSQLParseNode::absorptions(pNodeTmp
);
1246 pNodeTmp
= pNode
->getChild(1);
1248 // it could happen that pCondition is not more valid
1249 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pNodeTmp
, rLevel
);
1253 SqlParseError
GetANDCriteria( OQueryDesignView
* _pView
,
1254 OSelectionBrowseBox
* _pSelectionBrw
,
1255 const ::connectivity::OSQLParseNode
* pCondition
,
1258 bool bAddOrOnOneLine
);
1259 SqlParseError
ComparisonPredicate(OQueryDesignView
* _pView
,
1260 OSelectionBrowseBox
* _pSelectionBrw
,
1261 const ::connectivity::OSQLParseNode
* pCondition
,
1262 const sal_uInt16 nLevel
,
1264 bool bAddOrOnOneLine
);
1265 SqlParseError
GetORCriteria(OQueryDesignView
* _pView
,
1266 OSelectionBrowseBox
* _pSelectionBrw
,
1267 const ::connectivity::OSQLParseNode
* pCondition
,
1268 sal_uInt16
& nLevel
,
1270 bool bAddOrOnOneLine
)
1272 SqlParseError eErrorCode
= eOk
;
1274 // round brackets around the printout
1275 if (pCondition
->count() == 3 &&
1276 SQL_ISPUNCTUATION(pCondition
->getChild(0),"(") &&
1277 SQL_ISPUNCTUATION(pCondition
->getChild(2),")"))
1279 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pCondition
->getChild(1),nLevel
,bHaving
,bAddOrOnOneLine
);
1282 // a searchcondition can only look like this: search_condition SQL_TOKEN_OR boolean_term
1283 else if (SQL_ISRULE(pCondition
,search_condition
))
1285 for (int i
= 0; i
< 3 && eErrorCode
== eOk
; i
+=2)
1287 const ::connectivity::OSQLParseNode
* pChild
= pCondition
->getChild(i
);
1288 if ( SQL_ISRULE(pChild
,search_condition
) )
1289 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pChild
,nLevel
,bHaving
,bAddOrOnOneLine
);
1292 eErrorCode
= GetANDCriteria(_pView
,_pSelectionBrw
,pChild
, nLevel
,bHaving
, i
!= 0 && bAddOrOnOneLine
);
1293 if ( !bAddOrOnOneLine
)
1299 eErrorCode
= GetANDCriteria( _pView
,_pSelectionBrw
,pCondition
, nLevel
, bHaving
,bAddOrOnOneLine
);
1303 bool CheckOrCriteria(const ::connectivity::OSQLParseNode
* _pCondition
,::connectivity::OSQLParseNode
* _pFirstColumnRef
)
1306 ::connectivity::OSQLParseNode
* pFirstColumnRef
= _pFirstColumnRef
;
1307 for (size_t i
= 0; bRet
&& i
< _pCondition
->count() && bRet
; ++i
)
1309 const ::connectivity::OSQLParseNode
* pChild
= _pCondition
->getChild(i
);
1310 if ( pChild
->isToken() )
1312 else if ( SQL_ISRULE(pChild
,search_condition
) )
1313 bRet
= CheckOrCriteria(pChild
,pFirstColumnRef
);
1316 // this is a simple way to test columns are the same, may be we have to adjust this algo a little bit in future. :-)
1317 ::connectivity::OSQLParseNode
* pSecondColumnRef
= pChild
->getByRule(::connectivity::OSQLParseNode::column_ref
);
1318 if ( pFirstColumnRef
&& pSecondColumnRef
)
1319 bRet
= *pFirstColumnRef
== *pSecondColumnRef
;
1320 else if ( !pFirstColumnRef
)
1321 pFirstColumnRef
= pSecondColumnRef
;
1326 SqlParseError
GetANDCriteria( OQueryDesignView
* _pView
,
1327 OSelectionBrowseBox
* _pSelectionBrw
,
1328 const ::connectivity::OSQLParseNode
* pCondition
,
1331 bool bAddOrOnOneLine
)
1333 const ::com::sun::star::lang::Locale aLocale
= _pView
->getLocale();
1334 const OUString sDecimal
= _pView
->getDecimalSeparator();
1336 // I will need a cast pointer to my com::sun::star::sdbcx::Container
1337 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
1338 SqlParseError eErrorCode
= eOk
;
1341 if (SQL_ISRULE(pCondition
,boolean_primary
))
1343 // check if we have to put the or criteria on one line.
1344 const ::connectivity::OSQLParseNode
* pSearchCondition
= pCondition
->getChild(1);
1345 bool bMustAddOrOnOneLine
= CheckOrCriteria(pSearchCondition
,NULL
);
1346 if ( SQL_ISRULE( pSearchCondition
, search_condition
) ) // we have a or
1348 _pSelectionBrw
->DuplicateConditionLevel( nLevel
);
1349 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pSearchCondition
->getChild(0), nLevel
,bHaving
,bMustAddOrOnOneLine
);
1351 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pSearchCondition
->getChild(2), nLevel
,bHaving
,bMustAddOrOnOneLine
);
1354 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pSearchCondition
, nLevel
,bHaving
,bMustAddOrOnOneLine
);
1356 // The first element is (again) an AND condition
1357 else if ( SQL_ISRULE(pCondition
,boolean_term
) )
1359 OSL_ENSURE(pCondition
->count() == 3,"Illegal definifiton of boolean_term");
1360 eErrorCode
= GetANDCriteria(_pView
,_pSelectionBrw
,pCondition
->getChild(0), nLevel
,bHaving
,bAddOrOnOneLine
);
1361 if ( eErrorCode
== eOk
)
1362 eErrorCode
= GetANDCriteria(_pView
,_pSelectionBrw
,pCondition
->getChild(2), nLevel
,bHaving
,bAddOrOnOneLine
);
1364 else if (SQL_ISRULE( pCondition
, comparison_predicate
))
1366 eErrorCode
= ComparisonPredicate(_pView
,_pSelectionBrw
,pCondition
,nLevel
,bHaving
,bAddOrOnOneLine
);
1368 else if( SQL_ISRULE(pCondition
,like_predicate
) )
1370 const ::connectivity::OSQLParseNode
* pValueExp
= pCondition
->getChild(0);
1371 if (SQL_ISRULE(pValueExp
, column_ref
) )
1373 OUString aColumnName
;
1374 OUString aCondition
;
1375 Reference
< XConnection
> xConnection
= rController
.getConnection();
1376 if ( xConnection
.is() )
1378 Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
1379 // the international doesn't matter I have a string
1380 pCondition
->parseNodeToPredicateStr(aCondition
,
1382 rController
.getNumberFormatter(),
1384 static_cast<sal_Char
>(sDecimal
.toChar()),
1385 &rController
.getParser().getContext());
1387 pValueExp
->parseNodeToPredicateStr( aColumnName
,
1389 rController
.getNumberFormatter(),
1391 static_cast<sal_Char
>(sDecimal
.toChar()),
1392 &rController
.getParser().getContext());
1394 // don't display the column name
1395 aCondition
= aCondition
.copy(aColumnName
.getLength());
1396 aCondition
= aCondition
.trim();
1399 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1400 if ( eOk
== ( eErrorCode
= FillDragInfo(_pView
,pValueExp
,aDragLeft
) ))
1403 aDragLeft
->SetGroupBy(true);
1404 _pSelectionBrw
->AddCondition(aDragLeft
, aCondition
, nLevel
,bAddOrOnOneLine
);
1407 else if(SQL_ISRULEOR3(pValueExp
, general_set_fct
, set_fct_spec
, position_exp
) ||
1408 SQL_ISRULEOR3(pValueExp
, extract_exp
, fold
, char_substring_fct
) ||
1409 SQL_ISRULEOR2(pValueExp
, length_exp
, char_value_fct
))
1411 AddFunctionCondition( _pView
,
1420 eErrorCode
= eNoColumnInLike
;
1421 OUString
sError(ModuleRes(STR_QRY_LIKE_LEFT_NO_COLUMN
));
1422 _pView
->getController().appendError( sError
);
1425 else if( SQL_ISRULEOR2(pCondition
,test_for_null
,in_predicate
)
1426 || SQL_ISRULEOR2(pCondition
,all_or_any_predicate
,between_predicate
))
1428 if ( SQL_ISRULEOR2(pCondition
->getChild(0), set_fct_spec
, general_set_fct
) )
1430 AddFunctionCondition( _pView
,
1437 else if ( SQL_ISRULE(pCondition
->getChild(0), column_ref
) )
1440 OUString sCondition
= ParseCondition(rController
,pCondition
,sDecimal
,aLocale
,1);
1441 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1442 if ( eOk
== ( eErrorCode
= FillDragInfo(_pView
,pCondition
->getChild(0),aDragLeft
)) )
1445 aDragLeft
->SetGroupBy(true);
1446 _pSelectionBrw
->AddCondition(aDragLeft
, sCondition
, nLevel
,bAddOrOnOneLine
);
1451 // Parse the function condition
1452 OUString sCondition
= ParseCondition(rController
,pCondition
,sDecimal
,aLocale
,1);
1453 Reference
< XConnection
> xConnection
= rController
.getConnection();
1454 Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
1455 // the international doesn't matter I have a string
1457 pCondition
->getChild(0)->parseNodeToPredicateStr(sName
,
1459 rController
.getNumberFormatter(),
1461 static_cast<sal_Char
>(sDecimal
.toChar()),
1462 &rController
.getParser().getContext());
1464 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1465 aDragLeft
->SetField(sName
);
1466 aDragLeft
->SetFunctionType(FKT_OTHER
);
1469 aDragLeft
->SetGroupBy(true);
1470 _pSelectionBrw
->AddCondition(aDragLeft
, sCondition
, nLevel
,bAddOrOnOneLine
);
1473 else if( SQL_ISRULEOR2(pCondition
,existence_test
,unique_test
) )
1475 // Parse the function condition
1476 OUString aCondition
= ParseCondition(rController
,pCondition
,sDecimal
,aLocale
,0);
1478 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1479 aDragLeft
->SetField(aCondition
);
1480 aDragLeft
->SetFunctionType(FKT_CONDITION
);
1482 eErrorCode
= _pSelectionBrw
->InsertField(aDragLeft
,BROWSER_INVALIDID
,false,true).is() ? eOk
: eTooManyColumns
;
1484 else //! TODO not supported yet
1485 eErrorCode
= eStatementTooComplex
;
1486 // Pass on the error code
1489 SqlParseError
AddFunctionCondition(OQueryDesignView
* _pView
,
1490 OSelectionBrowseBox
* _pSelectionBrw
,
1491 const ::connectivity::OSQLParseNode
* pCondition
,
1492 const sal_uInt16 nLevel
,
1494 bool bAddOrOnOneLine
)
1496 SqlParseError eErrorCode
= eOk
;
1497 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
1499 OSQLParseNode
* pFunction
= pCondition
->getChild(0);
1501 OSL_ENSURE(SQL_ISRULEOR3(pFunction
, general_set_fct
, set_fct_spec
, position_exp
) ||
1502 SQL_ISRULEOR3(pFunction
, extract_exp
, fold
, char_substring_fct
) ||
1503 SQL_ISRULEOR2(pFunction
,length_exp
,char_value_fct
),
1505 OUString aCondition
;
1506 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1508 OUString aColumnName
;
1509 Reference
< XConnection
> xConnection
= rController
.getConnection();
1510 if(xConnection
.is())
1512 Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
1513 pCondition
->parseNodeToPredicateStr(aCondition
,
1515 rController
.getNumberFormatter(),
1516 _pView
->getLocale(),
1517 static_cast<sal_Char
>(_pView
->getDecimalSeparator().toChar()),
1518 &rController
.getParser().getContext());
1520 pFunction
->parseNodeToStr( aColumnName
,
1522 &rController
.getParser().getContext(),
1524 true); // quote is to true because we need quoted elements inside the function
1525 // don't display the column name
1526 aCondition
= aCondition
.copy(aColumnName
.getLength());
1527 aCondition
= aCondition
.trim();
1528 if ( aCondition
.startsWith("=") ) // ignore the equal sign
1529 aCondition
= aCondition
.copy(1);
1531 if ( SQL_ISRULE(pFunction
, general_set_fct
) )
1533 sal_Int32 nFunctionType
= FKT_AGGREGATE
;
1534 OSQLParseNode
* pParamNode
= pFunction
->getChild(pFunction
->count()-2);
1535 if ( pParamNode
&& pParamNode
->getTokenValue().toChar() == '*' )
1537 OJoinTableView::OTableWindowMap
& rTabList
= _pView
->getTableView()->GetTabWinMap();
1538 OJoinTableView::OTableWindowMap::iterator aIter
= rTabList
.begin();
1539 OJoinTableView::OTableWindowMap::iterator aTabEnd
= rTabList
.end();
1540 for(;aIter
!= aTabEnd
;++aIter
)
1542 OQueryTableWindow
* pTabWin
= static_cast<OQueryTableWindow
*>(aIter
->second
.get());
1543 if (pTabWin
->ExistsField( OUString("*"), aDragLeft
))
1545 aDragLeft
->SetAlias(OUString());
1546 aDragLeft
->SetTable(OUString());
1551 else if (pParamNode
&& eOk
!= (eErrorCode
= FillDragInfo(_pView
,pParamNode
,aDragLeft
))
1552 && SQL_ISRULE(pParamNode
,num_value_exp
))
1554 OUString sParameterValue
;
1555 pParamNode
->parseNodeToStr( sParameterValue
,
1557 &rController
.getParser().getContext());
1558 nFunctionType
|= FKT_NUMERIC
;
1559 aDragLeft
->SetField(sParameterValue
);
1562 aDragLeft
->SetFunctionType(nFunctionType
);
1564 aDragLeft
->SetGroupBy(true);
1565 sal_Int32 nIndex
= 0;
1566 aDragLeft
->SetFunction(aColumnName
.getToken(0,'(',nIndex
));
1570 // for an unknown function we write the whole text in the field
1571 aDragLeft
->SetField(aColumnName
);
1573 aDragLeft
->SetGroupBy(true);
1574 aDragLeft
->SetFunctionType(FKT_OTHER
|FKT_NUMERIC
);
1576 _pSelectionBrw
->AddCondition(aDragLeft
, aCondition
, nLevel
,bAddOrOnOneLine
);
1581 SqlParseError
ComparisonPredicate(OQueryDesignView
* _pView
,
1582 OSelectionBrowseBox
* _pSelectionBrw
,
1583 const ::connectivity::OSQLParseNode
* pCondition
,
1584 const sal_uInt16 nLevel
,
1586 ,bool bAddOrOnOneLine
)
1588 SqlParseError eErrorCode
= eOk
;
1589 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
1591 OSL_ENSURE(SQL_ISRULE( pCondition
, comparison_predicate
),"ComparisonPredicate: pCondition is not a Comparison Predicate");
1592 if ( SQL_ISRULE(pCondition
->getChild(0), column_ref
)
1593 || SQL_ISRULE(pCondition
->getChild(pCondition
->count()-1), column_ref
) )
1595 OUString aCondition
;
1596 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1598 if ( SQL_ISRULE(pCondition
->getChild(0), column_ref
) && SQL_ISRULE(pCondition
->getChild(pCondition
->count()-1), column_ref
) )
1600 OTableFieldDescRef aDragRight
= new OTableFieldDesc();
1601 if (eOk
!= ( eErrorCode
= FillDragInfo(_pView
,pCondition
->getChild(0),aDragLeft
)) ||
1602 eOk
!= ( eErrorCode
= FillDragInfo(_pView
,pCondition
->getChild(2),aDragRight
)))
1605 OQueryTableConnection
* pConn
= static_cast<OQueryTableConnection
*>(
1606 _pView
->getTableView()->GetTabConn(static_cast<OQueryTableWindow
*>(aDragLeft
->GetTabWindow()),
1607 static_cast<OQueryTableWindow
*>(aDragRight
->GetTabWindow()),
1611 OConnectionLineDataVec
& rLineDataList
= pConn
->GetData()->GetConnLineDataList();
1612 OConnectionLineDataVec::iterator aIter
= rLineDataList
.begin();
1613 OConnectionLineDataVec::iterator aEnd
= rLineDataList
.end();
1614 for(;aIter
!= aEnd
;++aIter
)
1616 if((*aIter
)->GetSourceFieldName() == aDragLeft
->GetField() ||
1617 (*aIter
)->GetDestFieldName() == aDragLeft
->GetField() )
1625 sal_uInt32 nPos
= 0;
1626 if(SQL_ISRULE(pCondition
->getChild(0), column_ref
))
1631 // don't display the equal
1632 if (pCondition
->getChild(i
)->getNodeType() == SQL_NODE_EQUAL
)
1636 aCondition
= ParseCondition(rController
1638 ,_pView
->getDecimalSeparator()
1639 ,_pView
->getLocale()
1642 else if( SQL_ISRULE(pCondition
->getChild(pCondition
->count()-1), column_ref
) )
1644 nPos
= pCondition
->count()-1;
1646 sal_Int32 i
= static_cast<sal_Int32
>(pCondition
->count() - 2);
1647 switch (pCondition
->getChild(i
)->getNodeType())
1649 case SQL_NODE_EQUAL
:
1650 // don't display the equal
1654 // take the opposite as we change the order
1658 case SQL_NODE_LESSEQ
:
1659 // take the opposite as we change the order
1663 case SQL_NODE_GREAT
:
1664 // take the opposite as we change the order
1668 case SQL_NODE_GREATEQ
:
1669 // take the opposite as we change the order
1678 Reference
< XConnection
> xConnection
= rController
.getConnection();
1679 if(xConnection
.is())
1681 Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
1683 pCondition
->getChild(i
)->parseNodeToPredicateStr(aCondition
,
1685 rController
.getNumberFormatter(),
1686 _pView
->getLocale(),
1687 static_cast<sal_Char
>(_pView
->getDecimalSeparator().toChar()),
1688 &rController
.getParser().getContext());
1693 if( eOk
== ( eErrorCode
= FillDragInfo(_pView
,pCondition
->getChild(nPos
),aDragLeft
)))
1696 aDragLeft
->SetGroupBy(true);
1697 _pSelectionBrw
->AddCondition(aDragLeft
, aCondition
, nLevel
,bAddOrOnOneLine
);
1700 else if( SQL_ISRULEOR2(pCondition
->getChild(0), set_fct_spec
, general_set_fct
) )
1702 AddFunctionCondition( _pView
,
1709 else // it can only be an Expr
1711 OUString aName
,aCondition
;
1713 ::connectivity::OSQLParseNode
*pLhs
= pCondition
->getChild(0);
1714 ::connectivity::OSQLParseNode
*pRhs
= pCondition
->getChild(2);
1716 Reference
< XConnection
> xConnection
= rController
.getConnection();
1717 if(xConnection
.is())
1719 pLhs
->parseNodeToStr(aName
,
1721 &rController
.getParser().getContext(),
1724 aCondition
= pCondition
->getChild(1)->getTokenValue();
1725 pRhs
->parseNodeToPredicateStr(aCondition
,
1727 rController
.getNumberFormatter(),
1728 _pView
->getLocale(),
1729 static_cast<sal_Char
>(_pView
->getDecimalSeparator().toChar()),
1730 &rController
.getParser().getContext());
1733 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1734 aDragLeft
->SetField(aName
);
1735 aDragLeft
->SetFunctionType(FKT_OTHER
|FKT_NUMERIC
);
1737 _pSelectionBrw
->AddCondition(aDragLeft
, aCondition
, nLevel
,bAddOrOnOneLine
);
1744 OQueryTableWindow
* lcl_findColumnInTables( const OUString
& _rColumName
, const OJoinTableView::OTableWindowMap
& _rTabList
, OTableFieldDescRef
& _rInfo
)
1746 OJoinTableView::OTableWindowMap::const_iterator aIter
= _rTabList
.begin();
1747 OJoinTableView::OTableWindowMap::const_iterator aEnd
= _rTabList
.end();
1748 for ( ; aIter
!= aEnd
; ++aIter
)
1750 OQueryTableWindow
* pTabWin
= static_cast< OQueryTableWindow
* >( aIter
->second
.get() );
1751 if ( pTabWin
&& pTabWin
->ExistsField( _rColumName
, _rInfo
) )
1758 void InsertColumnRef(const OQueryDesignView
* _pView
,
1759 const ::connectivity::OSQLParseNode
* pColumnRef
,
1760 OUString
& aColumnName
,
1761 const OUString
& aColumnAlias
,
1762 OUString
& aTableRange
,
1763 OTableFieldDescRef
& _raInfo
,
1764 OJoinTableView::OTableWindowMap
* pTabList
)
1767 // Put the table names together
1768 ::connectivity::OSQLParseTreeIterator
& rParseIter
= static_cast<OQueryController
&>(_pView
->getController()).getParseIterator();
1769 rParseIter
.getColumnRange( pColumnRef
, aColumnName
, aTableRange
);
1772 OSL_ENSURE(!aColumnName
.isEmpty(),"Column name must not be empty");
1773 if (aTableRange
.isEmpty())
1775 // SELECT column, ...
1776 bFound
= NULL
!= lcl_findColumnInTables( aColumnName
, *pTabList
, _raInfo
);
1777 if ( bFound
&& ( aColumnName
.toChar() != '*' ) )
1778 _raInfo
->SetFieldAlias(aColumnAlias
);
1782 // SELECT range.column, ...
1783 OQueryTableWindow
* pTabWin
= static_cast<OQueryTableView
*>(_pView
->getTableView())->FindTable(aTableRange
);
1785 if (pTabWin
&& pTabWin
->ExistsField(aColumnName
, _raInfo
))
1787 if(aColumnName
.toChar() != '*')
1788 _raInfo
->SetFieldAlias(aColumnAlias
);
1794 _raInfo
->SetTable(OUString());
1795 _raInfo
->SetAlias(OUString());
1796 _raInfo
->SetField(aColumnName
);
1797 _raInfo
->SetFieldAlias(aColumnAlias
); // nyi : here it continues Expr_1, Expr_2 ...
1798 _raInfo
->SetFunctionType(FKT_OTHER
);
1801 bool checkJoinConditions( const OQueryDesignView
* _pView
,
1802 const ::connectivity::OSQLParseNode
* _pNode
)
1804 const ::connectivity::OSQLParseNode
* pJoinNode
= NULL
;
1806 if (SQL_ISRULE(_pNode
,qualified_join
))
1808 else if (SQL_ISRULE(_pNode
,table_ref
)
1809 && _pNode
->count() == 3
1810 && SQL_ISPUNCTUATION(_pNode
->getChild(0),"(")
1811 && SQL_ISPUNCTUATION(_pNode
->getChild(2),")") ) // '(' joined_table ')'
1812 pJoinNode
= _pNode
->getChild(1);
1813 else if (! ( SQL_ISRULE(_pNode
, table_ref
) && _pNode
->count() == 2) ) // table_node table_primary_as_range_column
1816 if (pJoinNode
&& !InsertJoin(_pView
,pJoinNode
))
1820 bool InsertJoin(const OQueryDesignView
* _pView
,
1821 const ::connectivity::OSQLParseNode
*pNode
)
1823 OSL_ENSURE( SQL_ISRULE( pNode
, qualified_join
) || SQL_ISRULE( pNode
, joined_table
) || SQL_ISRULE( pNode
, cross_union
),
1824 "OQueryDesignView::InsertJoin: Error in the Parse Tree");
1826 if (SQL_ISRULE(pNode
,joined_table
))
1827 return InsertJoin(_pView
,pNode
->getChild(1));
1829 // first check the left and right side
1830 const ::connectivity::OSQLParseNode
* pRightTableRef
= pNode
->getChild(3); // table_ref
1831 if ( SQL_ISRULE(pNode
, qualified_join
) && SQL_ISTOKEN(pNode
->getChild(1),NATURAL
) )
1832 pRightTableRef
= pNode
->getChild(4); // table_ref
1834 if ( !checkJoinConditions(_pView
,pNode
->getChild(0)) || !checkJoinConditions(_pView
,pRightTableRef
))
1837 // named column join may be implemented later
1838 // SQL_ISRULE(pNode->getChild(4),named_columns_join)
1839 EJoinType eJoinType
= INNER_JOIN
;
1840 bool bNatural
= false;
1841 if ( SQL_ISRULE(pNode
, qualified_join
) )
1843 ::connectivity::OSQLParseNode
* pJoinType
= pNode
->getChild(1); // join_type
1844 if ( SQL_ISTOKEN(pJoinType
,NATURAL
) )
1847 pJoinType
= pNode
->getChild(2);
1850 if (SQL_ISRULE(pJoinType
,join_type
) && (!pJoinType
->count() || SQL_ISTOKEN(pJoinType
->getChild(0),INNER
)))
1852 eJoinType
= INNER_JOIN
;
1856 if (SQL_ISRULE(pJoinType
,join_type
)) // one level deeper
1857 pJoinType
= pJoinType
->getChild(0);
1859 if (SQL_ISTOKEN(pJoinType
->getChild(0),LEFT
))
1860 eJoinType
= LEFT_JOIN
;
1861 else if(SQL_ISTOKEN(pJoinType
->getChild(0),RIGHT
))
1862 eJoinType
= RIGHT_JOIN
;
1864 eJoinType
= FULL_JOIN
;
1866 if ( SQL_ISRULE(pNode
->getChild(4),join_condition
) )
1868 if ( InsertJoinConnection(_pView
,pNode
->getChild(4)->getChild(1), eJoinType
,pNode
->getChild(0),pRightTableRef
) != eOk
)
1872 else if ( SQL_ISRULE(pNode
, cross_union
) )
1874 eJoinType
= CROSS_JOIN
;
1875 pRightTableRef
= pNode
->getChild(pNode
->count() - 1);
1880 if ( eJoinType
== CROSS_JOIN
|| bNatural
)
1883 OQueryTableWindow
* pLeftWindow
= static_cast<OQueryTableView
*>(_pView
->getTableView())->FindTable( getTableRange(_pView
,pNode
->getChild(0)) );
1884 OQueryTableWindow
* pRightWindow
= static_cast<OQueryTableView
*>(_pView
->getTableView())->FindTable( getTableRange(_pView
,pRightTableRef
) );
1885 OSL_ENSURE(pLeftWindow
&& pRightWindow
,"Table Windows could not be found!");
1886 if ( !pLeftWindow
|| !pRightWindow
)
1889 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1890 aDragLeft
->SetTabWindow(pLeftWindow
);
1891 aDragLeft
->SetTable(pLeftWindow
->GetTableName());
1892 aDragLeft
->SetAlias(pLeftWindow
->GetAliasName());
1894 OTableFieldDescRef aDragRight
= new OTableFieldDesc();
1895 aDragRight
->SetTabWindow(pRightWindow
);
1896 aDragRight
->SetTable(pRightWindow
->GetTableName());
1897 aDragRight
->SetAlias(pRightWindow
->GetAliasName());
1899 insertConnection(_pView
,eJoinType
,aDragLeft
,aDragRight
,bNatural
);
1904 void insertUnUsedFields(OQueryDesignView
* _pView
,OSelectionBrowseBox
* _pSelectionBrw
)
1906 // now we have to insert the fields which aren't in the statement
1907 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
1908 OTableFields
& rUnUsedFields
= rController
.getUnUsedFields();
1909 OTableFields::iterator aEnd
= rUnUsedFields
.end();
1910 for(OTableFields::iterator aIter
= rUnUsedFields
.begin();aIter
!= aEnd
;++aIter
)
1911 if(_pSelectionBrw
->InsertField(*aIter
,BROWSER_INVALIDID
,false,false).is())
1913 OTableFields().swap( rUnUsedFields
);
1916 SqlParseError
InitFromParseNodeImpl(OQueryDesignView
* _pView
,OSelectionBrowseBox
* _pSelectionBrw
)
1918 SqlParseError eErrorCode
= eOk
;
1920 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
1922 _pSelectionBrw
->PreFill();
1923 _pSelectionBrw
->SetReadOnly(rController
.isReadOnly());
1924 _pSelectionBrw
->Fill();
1926 ::connectivity::OSQLParseTreeIterator
& aIterator
= rController
.getParseIterator();
1927 const ::connectivity::OSQLParseNode
* pParseTree
= aIterator
.getParseTree();
1933 // now we have to insert the fields which aren't in the statement
1934 insertUnUsedFields(_pView
,_pSelectionBrw
);
1938 if ( !rController
.isEscapeProcessing() ) // not allowed in this mode
1940 eErrorCode
= eNativeMode
;
1944 if ( !( SQL_ISRULE( pParseTree
, select_statement
) ) )
1946 eErrorCode
= eNoSelectStatement
;
1950 const OSQLParseNode
* pTableExp
= pParseTree
->getChild(3);
1951 if ( pTableExp
->getChild(7)->count() > 0 || pTableExp
->getChild(8)->count() > 0)
1953 eErrorCode
= eStatementTooComplex
;
1957 Reference
< XConnection
> xConnection
= rController
.getConnection();
1958 if ( !xConnection
.is() )
1960 OSL_FAIL( "InitFromParseNodeImpl: no connection? no connection!" );
1964 const OSQLTables
& aMap
= aIterator
.getTables();
1965 ::comphelper::UStringMixLess
aTmp(aMap
.key_comp());
1966 ::comphelper::UStringMixEqual
aKeyComp( aTmp
.isCaseSensitive() );
1968 Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
1971 sal_Int32 nMax
= xMetaData
->getMaxTablesInSelect();
1972 if ( nMax
&& nMax
< (sal_Int32
)aMap
.size() )
1974 eErrorCode
= eTooManyTables
;
1978 OUString sComposedName
;
1981 OQueryTableView
* pTableView
= static_cast<OQueryTableView
*>(_pView
->getTableView());
1982 pTableView
->clearLayoutInformation();
1983 OSQLTables::const_iterator aIter
= aMap
.begin();
1984 OSQLTables::const_iterator aEnd
= aMap
.end();
1985 for(;aIter
!= aEnd
;++aIter
)
1987 OSQLTable xTable
= aIter
->second
;
1988 Reference
< XPropertySet
> xTableProps( xTable
, UNO_QUERY_THROW
);
1990 sAlias
= aIter
->first
;
1992 // check whether this is a query
1993 Reference
< XPropertySetInfo
> xPSI
= xTableProps
->getPropertySetInfo();
1994 bool bIsQuery
= xPSI
.is() && xPSI
->hasPropertyByName( PROPERTY_COMMAND
);
1997 OSL_VERIFY( xTableProps
->getPropertyValue( PROPERTY_NAME
) >>= sComposedName
);
2000 sComposedName
= ::dbtools::composeTableName( xMetaData
, xTableProps
, ::dbtools::eInDataManipulation
, false, false, false );
2002 // if the alias is the complete (composed) table, then shorten it
2003 if ( aKeyComp( sComposedName
, aIter
->first
) )
2005 OUString sCatalog
, sSchema
, sTable
;
2006 ::dbtools::qualifiedNameComponents( xMetaData
, sComposedName
, sCatalog
, sSchema
, sTable
, ::dbtools::eInDataManipulation
);
2011 // find the existent window for this alias
2012 OQueryTableWindow
* pExistentWin
= pTableView
->FindTable( sAlias
);
2013 if ( !pExistentWin
)
2015 pTableView
->AddTabWin( sComposedName
, sAlias
, false ); // don't create data here
2019 // there already exists a window for this alias ....
2020 if ( !aKeyComp( pExistentWin
->GetData()->GetComposedName(), sComposedName
) )
2021 // ... but for another complete table name -> new window
2022 pTableView
->AddTabWin(sComposedName
, sAlias
);
2026 // now delete the data for which we haven't any tablewindow
2027 OJoinTableView::OTableWindowMap
aTableMap(pTableView
->GetTabWinMap());
2028 OJoinTableView::OTableWindowMap::iterator aIterTableMap
= aTableMap
.begin();
2029 OJoinTableView::OTableWindowMap::iterator aIterTableEnd
= aTableMap
.end();
2030 for(;aIterTableMap
!= aIterTableEnd
;++aIterTableMap
)
2032 if(aMap
.find(aIterTableMap
->second
->GetComposedName()) == aMap
.end() &&
2033 aMap
.find(aIterTableMap
->first
) == aMap
.end())
2034 pTableView
->RemoveTabWin(aIterTableMap
->second
);
2037 if ( eOk
== (eErrorCode
= FillOuterJoins(_pView
,pTableExp
->getChild(0)->getChild(1))) )
2039 // check if we have a distinct statement
2040 if(SQL_ISTOKEN(pParseTree
->getChild(1),DISTINCT
))
2042 rController
.setDistinct(true);
2043 rController
.InvalidateFeature(SID_QUERY_DISTINCT_VALUES
);
2047 rController
.setDistinct(false);
2050 ///check if query has a limit
2051 if( pTableExp
->getChild(6)->count() >= 2 && pTableExp
->getChild(6)->getChild(1) )
2053 rController
.setLimit(
2054 pTableExp
->getChild(6)->getChild(1)->getTokenValue().toInt64() );
2058 rController
.setLimit(-1);
2061 if ( (eErrorCode
= InstallFields(_pView
, pParseTree
, &pTableView
->GetTabWinMap())) == eOk
)
2063 // GetSelectionCriteria must be called before GetHavingCriteria
2064 sal_uInt16 nLevel
=0;
2066 if ( eOk
== (eErrorCode
= GetSelectionCriteria(_pView
,_pSelectionBrw
,pParseTree
,nLevel
)) )
2068 if ( eOk
== (eErrorCode
= GetGroupCriteria(_pView
,_pSelectionBrw
,pParseTree
)) )
2070 if ( eOk
== (eErrorCode
= GetHavingCriteria(_pView
,_pSelectionBrw
,pParseTree
,nLevel
)) )
2072 if ( eOk
== (eErrorCode
= GetOrderCriteria(_pView
,_pSelectionBrw
,pParseTree
)) )
2073 insertUnUsedFields(_pView
,_pSelectionBrw
);
2080 catch(SQLException
&)
2082 OSL_FAIL("getMaxTablesInSelect!");
2087 // New Undo-Actions were created in the Manager by the regeneration
2088 rController
.ClearUndoManager();
2089 _pSelectionBrw
->Invalidate();
2092 /** fillSelectSubList
2094 <TRUE/> when columns could be inserted otherwise <FALSE/>
2096 SqlParseError
fillSelectSubList( OQueryDesignView
* _pView
,
2097 OJoinTableView::OTableWindowMap
* _pTabList
)
2099 SqlParseError eErrorCode
= eOk
;
2100 bool bFirstField
= true;
2101 OUString
sAsterisk("*");
2102 OJoinTableView::OTableWindowMap::iterator aIter
= _pTabList
->begin();
2103 OJoinTableView::OTableWindowMap::iterator aEnd
= _pTabList
->end();
2104 for(;aIter
!= aEnd
&& eOk
== eErrorCode
;++aIter
)
2106 OQueryTableWindow
* pTabWin
= static_cast<OQueryTableWindow
*>(aIter
->second
.get());
2107 OTableFieldDescRef aInfo
= new OTableFieldDesc();
2108 if (pTabWin
->ExistsField( sAsterisk
, aInfo
))
2110 eErrorCode
= _pView
->InsertField(aInfo
, true, bFirstField
);
2111 bFirstField
= false;
2116 SqlParseError
InstallFields(OQueryDesignView
* _pView
,
2117 const ::connectivity::OSQLParseNode
* pNode
,
2118 OJoinTableView::OTableWindowMap
* pTabList
)
2120 if( pNode
==0 || !SQL_ISRULE(pNode
,select_statement
))
2121 return eNoSelectStatement
;
2123 ::connectivity::OSQLParseNode
* pParseTree
= pNode
->getChild(2); // selection
2124 bool bFirstField
= true; // When initializing, the first field must be reactivated
2126 SqlParseError eErrorCode
= eOk
;
2128 if ( pParseTree
->isRule() && SQL_ISPUNCTUATION(pParseTree
->getChild(0),"*") )
2131 eErrorCode
= fillSelectSubList(_pView
,pTabList
);
2133 else if (SQL_ISRULE(pParseTree
,scalar_exp_commalist
) )
2135 // SELECT column, ...
2136 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
2137 Reference
< XConnection
> xConnection
= rController
.getConnection();
2139 OUString aColumnName
,aTableRange
;
2140 for (sal_uInt32 i
= 0; i
< pParseTree
->count() && eOk
== eErrorCode
; ++i
)
2142 ::connectivity::OSQLParseNode
* pColumnRef
= pParseTree
->getChild(i
);
2146 if ( SQL_ISRULE(pColumnRef
,select_sublist
) )
2148 eErrorCode
= fillSelectSubList(_pView
,pTabList
);
2152 if ( SQL_ISRULE(pColumnRef
,derived_column
) )
2154 OUString
aColumnAlias(connectivity::OSQLParseTreeIterator::getColumnAlias(pColumnRef
)); // might be empty
2155 pColumnRef
= pColumnRef
->getChild(0);
2156 OTableFieldDescRef aInfo
= new OTableFieldDesc();
2158 if ( pColumnRef
->getKnownRuleID() != OSQLParseNode::subquery
&&
2159 pColumnRef
->count() == 3 &&
2160 SQL_ISPUNCTUATION(pColumnRef
->getChild(0),"(") &&
2161 SQL_ISPUNCTUATION(pColumnRef
->getChild(2),")")
2163 pColumnRef
= pColumnRef
->getChild(1);
2165 if (SQL_ISRULE(pColumnRef
,column_ref
))
2167 InsertColumnRef(_pView
,pColumnRef
,aColumnName
,aColumnAlias
,aTableRange
,aInfo
,pTabList
);
2168 eErrorCode
= _pView
->InsertField(aInfo
, true, bFirstField
);
2169 bFirstField
= false;
2171 else if(SQL_ISRULEOR3(pColumnRef
, general_set_fct
, set_fct_spec
, position_exp
) ||
2172 SQL_ISRULEOR3(pColumnRef
, extract_exp
, fold
, char_substring_fct
) ||
2173 SQL_ISRULEOR2(pColumnRef
,length_exp
,char_value_fct
))
2176 pColumnRef
->parseNodeToPredicateStr(aColumns
,
2178 rController
.getNumberFormatter(),
2179 _pView
->getLocale(),
2180 static_cast<sal_Char
>(_pView
->getDecimalSeparator().toChar()),
2181 &rController
.getParser().getContext());
2183 sal_Int32 nFunctionType
= FKT_NONE
;
2184 ::connectivity::OSQLParseNode
* pParamRef
= NULL
;
2185 sal_Int32 nColumnRefPos
= pColumnRef
->count() - 2;
2186 if ( nColumnRefPos
>= 0 && static_cast<sal_uInt32
>(nColumnRefPos
) < pColumnRef
->count() )
2187 pParamRef
= pColumnRef
->getChild(nColumnRefPos
);
2189 if ( SQL_ISRULE(pColumnRef
,general_set_fct
)
2190 && pParamRef
&& SQL_ISRULE(pParamRef
,column_ref
) )
2192 // Check the parameters for Column references
2193 InsertColumnRef(_pView
,pParamRef
,aColumnName
,aColumnAlias
,aTableRange
,aInfo
,pTabList
);
2195 else if ( SQL_ISRULE(pColumnRef
,general_set_fct
) )
2197 if ( pParamRef
&& pParamRef
->getTokenValue().toChar() == '*' )
2199 OJoinTableView::OTableWindowMap::iterator aIter
= pTabList
->begin();
2200 const OJoinTableView::OTableWindowMap::const_iterator aEnd
= pTabList
->end();
2201 for(;aIter
!= aEnd
;++aIter
)
2203 OQueryTableWindow
* pTabWin
= static_cast<OQueryTableWindow
*>(aIter
->second
.get());
2204 if (pTabWin
->ExistsField( OUString("*"), aInfo
))
2206 aInfo
->SetAlias(OUString());
2207 aInfo
->SetTable(OUString());
2214 OUString sFieldName
= aColumns
;
2216 { // we got an aggregate function but without column name inside
2217 // so we set the whole argument of the function as field name
2218 nFunctionType
|= FKT_NUMERIC
;
2220 pParamRef
->parseNodeToStr( sFieldName
,
2222 &rController
.getParser().getContext(),
2224 true); // quote is to true because we need quoted elements inside the function
2226 aInfo
->SetDataType(DataType::DOUBLE
);
2227 aInfo
->SetFieldType(TAB_NORMAL_FIELD
);
2228 aInfo
->SetField(sFieldName
);
2230 aInfo
->SetTabWindow(NULL
);
2231 aInfo
->SetFieldAlias(aColumnAlias
);
2235 _pView
->fillFunctionInfo(pColumnRef
,aColumns
,aInfo
);
2236 aInfo
->SetFieldAlias(aColumnAlias
);
2239 if ( SQL_ISRULE(pColumnRef
,general_set_fct
) )
2241 aInfo
->SetFunctionType(nFunctionType
|FKT_AGGREGATE
);
2242 OUString
aCol(aColumns
);
2243 aInfo
->SetFunction(comphelper::string::stripEnd(aCol
.getToken(0,'('), ' '));
2246 aInfo
->SetFunctionType(nFunctionType
|FKT_OTHER
);
2248 eErrorCode
= _pView
->InsertField(aInfo
, true, bFirstField
);
2249 bFirstField
= false;
2254 pColumnRef
->parseNodeToStr( aColumns
,
2256 &rController
.getParser().getContext(),
2258 true); // quote is to true because we need quoted elements inside the function
2260 aInfo
->SetTabWindow( NULL
);
2262 // since we support queries in queries, the thingie might belong to an existing "table"
2263 OQueryTableWindow
* pExistingTable
= lcl_findColumnInTables( aColumns
, *pTabList
, aInfo
);
2264 if ( pExistingTable
)
2266 aInfo
->SetTabWindow( pExistingTable
);
2267 aInfo
->SetTable( pExistingTable
->GetTableName() );
2268 aInfo
->SetAlias( pExistingTable
->GetAliasName() );
2271 aInfo
->SetDataType(DataType::DOUBLE
);
2272 aInfo
->SetFieldType(TAB_NORMAL_FIELD
);
2273 aInfo
->SetField(aColumns
);
2274 aInfo
->SetFieldAlias(aColumnAlias
);
2275 aInfo
->SetFunctionType(FKT_NUMERIC
| FKT_OTHER
);
2277 eErrorCode
= _pView
->InsertField(aInfo
, true, bFirstField
);
2278 bFirstField
= false;
2284 OSL_FAIL( "InstallFields: don't know how to interpret this parse node!" );
2290 eErrorCode
= eStatementTooComplex
;
2294 SqlParseError
GetOrderCriteria( OQueryDesignView
* _pView
,
2295 OSelectionBrowseBox
* _pSelectionBrw
,
2296 const ::connectivity::OSQLParseNode
* pParseRoot
)
2298 SqlParseError eErrorCode
= eOk
;
2299 if (!pParseRoot
->getChild(3)->getChild(ORDER_BY_CHILD_POS
)->isLeaf())
2301 ::connectivity::OSQLParseNode
* pNode
= pParseRoot
->getChild(3)->getChild(ORDER_BY_CHILD_POS
)->getChild(2);
2302 ::connectivity::OSQLParseNode
* pParamRef
= NULL
;
2304 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
2305 EOrderDir eOrderDir
;
2306 for( sal_uInt32 i
=0 ; i
<pNode
->count() ; i
++ )
2308 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
2309 eOrderDir
= ORDER_ASC
;
2310 ::connectivity::OSQLParseNode
* pChild
= pNode
->getChild( i
);
2312 if (SQL_ISTOKEN( pChild
->getChild(1), DESC
) )
2313 eOrderDir
= ORDER_DESC
;
2315 ::connectivity::OSQLParseNode
* pArgument
= pChild
->getChild(0);
2317 if(SQL_ISRULE(pArgument
,column_ref
))
2319 if( eOk
== FillDragInfo(_pView
,pArgument
,aDragLeft
))
2320 _pSelectionBrw
->AddOrder( aDragLeft
, eOrderDir
, i
);
2321 else // it could be a alias name for a field
2323 OUString aTableRange
,aColumnName
;
2324 ::connectivity::OSQLParseTreeIterator
& rParseIter
= rController
.getParseIterator();
2325 rParseIter
.getColumnRange( pArgument
, aColumnName
, aTableRange
);
2327 OTableFields
& aList
= rController
.getTableFieldDesc();
2328 OTableFields::iterator aIter
= aList
.begin();
2329 OTableFields::iterator aEnd
= aList
.end();
2330 for(;aIter
!= aEnd
;++aIter
)
2332 OTableFieldDescRef pEntry
= *aIter
;
2333 if(pEntry
.is() && pEntry
->GetFieldAlias() == aColumnName
)
2334 pEntry
->SetOrderDir( eOrderDir
);
2338 else if(SQL_ISRULE(pArgument
, general_set_fct
) &&
2339 SQL_ISRULE(pParamRef
= pArgument
->getChild(pArgument
->count()-2),column_ref
) &&
2340 eOk
== FillDragInfo(_pView
,pParamRef
,aDragLeft
))
2341 _pSelectionBrw
->AddOrder( aDragLeft
, eOrderDir
, i
);
2342 else if( SQL_ISRULE(pArgument
, set_fct_spec
) )
2345 Reference
< XConnection
> xConnection
= rController
.getConnection();
2346 if(xConnection
.is())
2348 OUString sCondition
;
2349 pArgument
->parseNodeToPredicateStr(sCondition
,
2351 rController
.getNumberFormatter(),
2352 _pView
->getLocale(),
2353 static_cast<sal_Char
>(_pView
->getDecimalSeparator().toChar()),
2354 &rController
.getParser().getContext());
2355 _pView
->fillFunctionInfo(pArgument
,sCondition
,aDragLeft
);
2356 aDragLeft
->SetFunctionType(FKT_OTHER
);
2357 aDragLeft
->SetOrderDir(eOrderDir
);
2358 aDragLeft
->SetVisible(false);
2359 _pSelectionBrw
->AddOrder( aDragLeft
, eOrderDir
, i
);
2362 eErrorCode
= eColumnNotFound
;
2365 eErrorCode
= eColumnNotFound
;
2370 SqlParseError
GetHavingCriteria( OQueryDesignView
* _pView
,
2371 OSelectionBrowseBox
* _pSelectionBrw
,
2372 const ::connectivity::OSQLParseNode
* pSelectRoot
,
2373 sal_uInt16
& rLevel
)
2375 SqlParseError eErrorCode
= eOk
;
2376 if (!pSelectRoot
->getChild(3)->getChild(3)->isLeaf())
2377 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pSelectRoot
->getChild(3)->getChild(3)->getChild(1),rLevel
, true);
2380 SqlParseError
GetGroupCriteria( OQueryDesignView
* _pView
,
2381 OSelectionBrowseBox
* _pSelectionBrw
,
2382 const ::connectivity::OSQLParseNode
* pSelectRoot
)
2384 SqlParseError eErrorCode
= eOk
;
2385 if (!pSelectRoot
->getChild(3)->getChild(2)->isLeaf()) // opt_group_by_clause
2387 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
2388 ::connectivity::OSQLParseNode
* pGroupBy
= pSelectRoot
->getChild(3)->getChild(2)->getChild(2);
2390 for( sal_uInt32 i
=0 ; i
< pGroupBy
->count() && eOk
== eErrorCode
; ++i
)
2392 OTableFieldDescRef aDragInfo
= new OTableFieldDesc();
2393 ::connectivity::OSQLParseNode
* pParamRef
= NULL
;
2394 ::connectivity::OSQLParseNode
* pArgument
= pGroupBy
->getChild( i
);
2395 if(SQL_ISRULE(pArgument
,column_ref
))
2397 if ( eOk
== (eErrorCode
= FillDragInfo(_pView
,pArgument
,aDragInfo
)) )
2399 aDragInfo
->SetGroupBy(true);
2400 _pSelectionBrw
->AddGroupBy(aDragInfo
,i
);
2403 else if(SQL_ISRULE(pArgument
, general_set_fct
) &&
2404 SQL_ISRULE(pParamRef
= pArgument
->getChild(pArgument
->count()-2),column_ref
) &&
2405 eOk
== FillDragInfo(_pView
,pParamRef
,aDragInfo
))
2407 aDragInfo
->SetGroupBy(true);
2408 _pSelectionBrw
->AddGroupBy( aDragInfo
, i
);
2410 else if( SQL_ISRULE(pArgument
, set_fct_spec
) )
2412 Reference
< XConnection
> xConnection
= rController
.getConnection();
2413 if(xConnection
.is())
2415 OUString sGroupByExpression
;
2416 pArgument
->parseNodeToStr( sGroupByExpression
,
2418 &rController
.getParser().getContext(),
2420 true); // quote is to true because we need quoted elements inside the function
2421 _pView
->fillFunctionInfo(pArgument
,sGroupByExpression
,aDragInfo
);
2422 aDragInfo
->SetFunctionType(FKT_OTHER
);
2423 aDragInfo
->SetGroupBy(true);
2424 aDragInfo
->SetVisible(false);
2425 _pSelectionBrw
->AddGroupBy( aDragInfo
, i
);
2428 eErrorCode
= eColumnNotFound
;
2435 OUString
getParseErrorMessage( SqlParseError _eErrorCode
)
2441 nResId
= STR_QRY_ILLEGAL_JOIN
;
2443 case eStatementTooLong
:
2444 nResId
= STR_QRY_TOO_LONG_STATEMENT
;
2447 nResId
= STR_QRY_SYNTAX
;
2449 case eNoSelectStatement
:
2450 nResId
= STR_QRY_NOSELECT
;
2452 case eColumnInLikeNotFound
:
2453 nResId
= STR_QRY_SYNTAX
;
2455 case eNoColumnInLike
:
2456 nResId
= STR_QRY_SYNTAX
;
2458 case eColumnNotFound
:
2459 nResId
= STR_QRY_SYNTAX
;
2462 nResId
= STR_QRY_NATIVE
;
2464 case eTooManyTables
:
2465 nResId
= STR_QRY_TOO_MANY_TABLES
;
2467 case eTooManyConditions
:
2468 nResId
= STR_QRY_TOOMANYCOND
;
2470 case eTooManyColumns
:
2471 nResId
= STR_QRY_TOO_MANY_COLUMNS
;
2473 case eStatementTooComplex
:
2474 nResId
= STR_QRY_TOOCOMPLEX
;
2477 nResId
= STR_QRY_SYNTAX
;
2481 return OUString( ModuleRes( nResId
) );
2486 // end of anonymouse namespace
2488 OQueryDesignView::OQueryDesignView( OQueryContainerWindow
* _pParent
,
2489 OQueryController
& _rController
,
2490 const Reference
< XComponentContext
>& _rxContext
)
2491 :OQueryView( _pParent
, _rController
, _rxContext
)
2492 ,m_aSplitter( VclPtr
<Splitter
>::Create(this) )
2493 ,m_eChildFocus(NONE
)
2494 ,m_bInSplitHandler( false )
2499 SvtSysLocale aSysLocale
;
2500 m_aLocale
= aSysLocale
.GetLanguageTag().getLocale();
2501 m_sDecimalSep
= aSysLocale
.GetLocaleData().getNumDecimalSep();
2507 m_pSelectionBox
= VclPtr
<OSelectionBrowseBox
>::Create(this);
2509 setNoneVisbleRow(static_cast<OQueryController
&>(getController()).getVisibleRows());
2510 m_pSelectionBox
->Show();
2512 m_aSplitter
->SetSplitHdl(LINK(this, OQueryDesignView
,SplitHdl
));
2513 m_aSplitter
->Show();
2517 OQueryDesignView::~OQueryDesignView()
2522 void OQueryDesignView::dispose()
2525 ::dbaui::notifySystemWindow(this,m_pTableView
,::comphelper::mem_fun(&TaskPaneList::RemoveWindow
));
2526 m_pSelectionBox
.disposeAndClear();
2527 m_aSplitter
.disposeAndClear();
2528 OQueryView::dispose();
2531 IMPL_LINK_NOARG( OQueryDesignView
, SplitHdl
)
2533 if (!getController().isReadOnly())
2535 m_bInSplitHandler
= true;
2536 m_aSplitter
->SetPosPixel( Point( m_aSplitter
->GetPosPixel().X(),m_aSplitter
->GetSplitPosPixel() ) );
2537 static_cast<OQueryController
&>(getController()).setSplitPos(m_aSplitter
->GetSplitPosPixel());
2538 static_cast<OQueryController
&>(getController()).setModified( sal_True
);
2540 m_bInSplitHandler
= true;
2545 void OQueryDesignView::Construct()
2547 m_pTableView
= VclPtr
<OQueryTableView
>::Create(m_pScrollWindow
,this);
2548 ::dbaui::notifySystemWindow(this,m_pTableView
,::comphelper::mem_fun(&TaskPaneList::AddWindow
));
2549 OQueryView::Construct();
2552 void OQueryDesignView::initialize()
2554 if(static_cast<OQueryController
&>(getController()).getSplitPos() != -1)
2556 m_aSplitter
->SetPosPixel( Point( m_aSplitter
->GetPosPixel().X(),static_cast<OQueryController
&>(getController()).getSplitPos() ) );
2557 m_aSplitter
->SetSplitPosPixel(static_cast<OQueryController
&>(getController()).getSplitPos());
2559 m_pSelectionBox
->initialize();
2563 void OQueryDesignView::resizeDocumentView(Rectangle
& _rPlayground
)
2565 Point
aPlaygroundPos( _rPlayground
.TopLeft() );
2566 Size
aPlaygroundSize( _rPlayground
.GetSize() );
2568 // calc the split pos, and forward it to the controller
2569 sal_Int32 nSplitPos
= static_cast<OQueryController
&>(getController()).getSplitPos();
2570 if ( 0 != aPlaygroundSize
.Height() )
2572 if ( ( -1 == nSplitPos
)
2573 || ( nSplitPos
>= aPlaygroundSize
.Height() )
2576 // let the selection browse box determine an optimal size
2577 Size aSelectionBoxSize
= m_pSelectionBox
->CalcOptimalSize( aPlaygroundSize
);
2578 nSplitPos
= aPlaygroundSize
.Height() - aSelectionBoxSize
.Height() - m_aSplitter
->GetSizePixel().Height();
2579 // still an invalid size?
2580 if ( nSplitPos
== -1 || nSplitPos
>= aPlaygroundSize
.Height() )
2581 nSplitPos
= sal_Int32(aPlaygroundSize
.Height()*0.6);
2583 static_cast<OQueryController
&>(getController()).setSplitPos(nSplitPos
);
2586 if ( !m_bInSplitHandler
)
2587 { // the resize is triggered by something else than the split handler
2588 // our main focus is to try to preserve the size of the selectionbrowse box
2589 Size aSelBoxSize
= m_pSelectionBox
->GetSizePixel();
2590 if ( aSelBoxSize
.Height() )
2592 // keep the size of the sel box constant
2593 nSplitPos
= aPlaygroundSize
.Height() - m_aSplitter
->GetSizePixel().Height() - aSelBoxSize
.Height();
2595 // and if the box is smaller than the optimal size, try to do something about it
2596 Size aSelBoxOptSize
= m_pSelectionBox
->CalcOptimalSize( aPlaygroundSize
);
2597 if ( aSelBoxOptSize
.Height() > aSelBoxSize
.Height() )
2599 nSplitPos
= aPlaygroundSize
.Height() - m_aSplitter
->GetSizePixel().Height() - aSelBoxOptSize
.Height();
2602 static_cast< OQueryController
& >(getController()).setSplitPos( nSplitPos
);
2607 // normalize the split pos
2608 Point aSplitPos
= Point( _rPlayground
.Left(), nSplitPos
);
2609 Size aSplitSize
= Size( _rPlayground
.GetSize().Width(), m_aSplitter
->GetSizePixel().Height() );
2611 if( ( aSplitPos
.Y() + aSplitSize
.Height() ) > ( aPlaygroundSize
.Height() ))
2612 aSplitPos
.Y() = aPlaygroundSize
.Height() - aSplitSize
.Height();
2614 if( aSplitPos
.Y() <= aPlaygroundPos
.Y() )
2615 aSplitPos
.Y() = aPlaygroundPos
.Y() + sal_Int32(aPlaygroundSize
.Height() * 0.2);
2617 // position the table
2618 Size
aTableViewSize(aPlaygroundSize
.Width(), aSplitPos
.Y() - aPlaygroundPos
.Y());
2619 m_pScrollWindow
->SetPosSizePixel(aPlaygroundPos
, aTableViewSize
);
2621 // position the selection browse box
2622 Point
aPos( aPlaygroundPos
.X(), aSplitPos
.Y() + aSplitSize
.Height() );
2623 m_pSelectionBox
->SetPosSizePixel( aPos
, Size( aPlaygroundSize
.Width(), aPlaygroundSize
.Height() - aSplitSize
.Height() - aTableViewSize
.Height() ));
2625 // set the size of the splitter
2626 m_aSplitter
->SetPosSizePixel( aSplitPos
, aSplitSize
);
2627 m_aSplitter
->SetDragRectPixel( _rPlayground
);
2629 // just for completeness: there is no space left, we occupied it all ...
2630 _rPlayground
.SetPos( _rPlayground
.BottomRight() );
2631 _rPlayground
.SetSize( Size( 0, 0 ) );
2634 void OQueryDesignView::setReadOnly(bool _bReadOnly
)
2636 m_pSelectionBox
->SetReadOnly(_bReadOnly
);
2639 void OQueryDesignView::clear()
2641 m_pSelectionBox
->ClearAll(); // clear the whole selection
2642 m_pTableView
->ClearAll();
2645 void OQueryDesignView::setStatement(const OUString
& /*_rsStatement*/)
2649 void OQueryDesignView::copy()
2651 if( m_eChildFocus
== SELECTION
)
2652 m_pSelectionBox
->copy();
2655 bool OQueryDesignView::isCutAllowed()
2657 bool bAllowed
= false;
2658 if ( SELECTION
== m_eChildFocus
)
2659 bAllowed
= m_pSelectionBox
->isCutAllowed();
2663 bool OQueryDesignView::isPasteAllowed()
2665 bool bAllowed
= false;
2666 if ( SELECTION
== m_eChildFocus
)
2667 bAllowed
= m_pSelectionBox
->isPasteAllowed();
2671 bool OQueryDesignView::isCopyAllowed()
2673 bool bAllowed
= false;
2674 if ( SELECTION
== m_eChildFocus
)
2675 bAllowed
= m_pSelectionBox
->isCopyAllowed();
2679 void OQueryDesignView::stopTimer()
2681 m_pSelectionBox
->stopTimer();
2684 void OQueryDesignView::startTimer()
2686 m_pSelectionBox
->startTimer();
2689 void OQueryDesignView::cut()
2691 if( m_eChildFocus
== SELECTION
)
2693 m_pSelectionBox
->cut();
2694 static_cast<OQueryController
&>(getController()).setModified(sal_True
);
2698 void OQueryDesignView::paste()
2700 if( m_eChildFocus
== SELECTION
)
2702 m_pSelectionBox
->paste();
2703 static_cast<OQueryController
&>(getController()).setModified(sal_True
);
2707 void OQueryDesignView::TableDeleted(const OUString
& rAliasName
)
2709 // message that the table was removed from the window
2710 DeleteFields(rAliasName
);
2711 static_cast<OQueryController
&>(getController()).InvalidateFeature(ID_BROWSER_ADDTABLE
); // inform the view again
2714 void OQueryDesignView::DeleteFields( const OUString
& rAliasName
)
2716 m_pSelectionBox
->DeleteFields( rAliasName
);
2719 bool OQueryDesignView::HasFieldByAliasName(const OUString
& rFieldName
, OTableFieldDescRef
& rInfo
) const
2721 return m_pSelectionBox
->HasFieldByAliasName( rFieldName
, rInfo
);
2724 SqlParseError
OQueryDesignView::InsertField( const OTableFieldDescRef
& rInfo
, bool bVis
, bool bActivate
)
2726 return m_pSelectionBox
->InsertField( rInfo
, BROWSER_INVALIDID
,bVis
, bActivate
).is() ? eOk
: eTooManyColumns
;
2729 sal_Int32
OQueryDesignView::getColWidth(sal_uInt16 _nColPos
) const
2731 static sal_Int32 s_nDefaultWidth
= GetTextWidth(OUString("0")) * 15;
2732 sal_Int32 nWidth
= static_cast<OQueryController
&>(getController()).getColWidth(_nColPos
);
2734 nWidth
= s_nDefaultWidth
;
2738 void OQueryDesignView::fillValidFields(const OUString
& sAliasName
, ComboBox
* pFieldList
)
2740 OSL_ENSURE(pFieldList
!= NULL
, "OQueryDesignView::FillValidFields : What the hell do you think I can do with a NULL-ptr ? This will crash !");
2741 pFieldList
->Clear();
2743 bool bAllTables
= sAliasName
.isEmpty();
2745 OJoinTableView::OTableWindowMap
& rTabWins
= m_pTableView
->GetTabWinMap();
2746 OUString strCurrentPrefix
;
2747 ::std::vector
< OUString
> aFields
;
2748 OJoinTableView::OTableWindowMap::iterator aIter
= rTabWins
.begin();
2749 OJoinTableView::OTableWindowMap::iterator aEnd
= rTabWins
.end();
2750 for(;aIter
!= aEnd
;++aIter
)
2752 OQueryTableWindow
* pCurrentWin
= static_cast<OQueryTableWindow
*>(aIter
->second
.get());
2753 if (bAllTables
|| (pCurrentWin
->GetAliasName() == sAliasName
))
2755 strCurrentPrefix
= pCurrentWin
->GetAliasName();
2756 strCurrentPrefix
+= ".";
2758 pCurrentWin
->EnumValidFields(aFields
);
2760 ::std::vector
< OUString
>::iterator aStrIter
= aFields
.begin();
2761 ::std::vector
< OUString
>::iterator aStrEnd
= aFields
.end();
2762 for(;aStrIter
!= aStrEnd
;++aStrIter
)
2764 if (bAllTables
|| aStrIter
->toChar() == '*')
2765 pFieldList
->InsertEntry(OUString(strCurrentPrefix
) += *aStrIter
);
2767 pFieldList
->InsertEntry(*aStrIter
);
2771 // this means that I came into this block because the table name was exactly what I was looking for so I can end here
2772 // (and I prevent that fields get added more than once, if a table is repeated in TabWin)
2778 bool OQueryDesignView::PreNotify(NotifyEvent
& rNEvt
)
2780 if (rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
2782 #if OSL_DEBUG_LEVEL > 0
2784 vcl::Window
* pFocus
= Application::GetFocusWindow();
2789 if ( m_pSelectionBox
&& m_pSelectionBox
->HasChildPathFocus() )
2790 m_eChildFocus
= SELECTION
;
2792 m_eChildFocus
= TABLEVIEW
;
2795 return OQueryView::PreNotify(rNEvt
);
2798 // check if the statement is correct when not returning false
2799 bool OQueryDesignView::checkStatement()
2802 if ( m_pSelectionBox
)
2803 bRet
= m_pSelectionBox
->Save(); // an error occurred so we return no
2807 OUString
OQueryDesignView::getStatement()
2809 OQueryController
& rController
= static_cast<OQueryController
&>(getController());
2810 m_rController
.clearError();
2811 // used for fields which aren't any longer in the statement
2812 OTableFields
& rUnUsedFields
= rController
.getUnUsedFields();
2813 OTableFields().swap( rUnUsedFields
);
2815 // create the select columns
2816 sal_uInt32 nFieldcount
= 0;
2817 OTableFields
& rFieldList
= rController
.getTableFieldDesc();
2818 OTableFields::iterator aIter
= rFieldList
.begin();
2819 OTableFields::iterator aEnd
= rFieldList
.end();
2820 for(;aIter
!= aEnd
;++aIter
)
2822 OTableFieldDescRef pEntryField
= *aIter
;
2823 if (!pEntryField
->GetField().isEmpty() && pEntryField
->IsVisible() )
2825 else if (!pEntryField
->GetField().isEmpty() &&
2826 !pEntryField
->HasCriteria() &&
2827 pEntryField
->isNoneFunction() &&
2828 pEntryField
->GetOrderDir() == ORDER_NONE
&&
2829 !pEntryField
->IsGroupBy() &&
2830 pEntryField
->GetFunction().isEmpty() )
2831 rUnUsedFields
.push_back(pEntryField
);
2833 if ( !nFieldcount
) // no visible fields so return
2835 rUnUsedFields
= rFieldList
;
2839 OQueryTableView::OTableWindowMap
& rTabList
= m_pTableView
->GetTabWinMap();
2840 sal_uInt32 nTabcount
= rTabList
.size();
2842 OUString
aFieldListStr(GenerateSelectList(this,rFieldList
,nTabcount
>1));
2843 if( aFieldListStr
.isEmpty() )
2846 // Exceptionhandling, if no fields have been passed we should not
2847 // change the tab page
2848 // TabBarSelectHdl will query the SQL-OUString for STATEMENT_NOFIELDS
2849 // and trigger a error message
2850 // ----------------- Build table list ----------------------
2852 const auto& rConnList
= m_pTableView
->getTableConnections();
2853 Reference
< XConnection
> xConnection
= rController
.getConnection();
2854 OUString
aTableListStr(GenerateFromClause(xConnection
,&rTabList
,rConnList
));
2855 OSL_ENSURE(!aTableListStr
.isEmpty(), "OQueryDesignView::getStatement() : unexpected : have Fields, but no Tables !");
2856 // if fields exist now, these only can be created by inserting from an already existing table; if on the other hand
2857 // a table is deleted, also the belonging fields will be deleted -> therefore it CANNOT occur that fields
2858 // exist but no tables exist (and aFieldListStr has its length, I secure this above)
2859 OUStringBuffer aHavingStr
,aCriteriaListStr
;
2861 // ----------------- Kriterien aufbauen ----------------------
2862 if (!GenerateCriterias(this,aCriteriaListStr
,aHavingStr
,rFieldList
, nTabcount
> 1))
2866 GenerateInnerJoinCriterias(xConnection
,aJoinCrit
,rConnList
);
2867 if(!aJoinCrit
.isEmpty())
2869 OUString aTmp
= "( " + aJoinCrit
+ " )";
2870 if(!aCriteriaListStr
.isEmpty())
2873 aTmp
+= aCriteriaListStr
.makeStringAndClear();
2875 aCriteriaListStr
= aTmp
;
2877 // ----------------- construct statement ----------------------
2878 OUStringBuffer
aSqlCmd("SELECT ");
2879 if(rController
.isDistinct())
2880 aSqlCmd
.append(" DISTINCT ");
2881 aSqlCmd
.append(aFieldListStr
);
2882 aSqlCmd
.append(" FROM ");
2883 aSqlCmd
.append(aTableListStr
);
2885 if (!aCriteriaListStr
.isEmpty())
2887 aSqlCmd
.append(" WHERE ");
2888 aSqlCmd
.append(aCriteriaListStr
.makeStringAndClear());
2890 Reference
<XDatabaseMetaData
> xMeta
;
2891 if ( xConnection
.is() )
2892 xMeta
= xConnection
->getMetaData();
2893 bool bUseAlias
= nTabcount
> 1;
2895 bUseAlias
= bUseAlias
|| !xMeta
->supportsGroupByUnrelated();
2897 aSqlCmd
.append(GenerateGroupBy(this,rFieldList
,bUseAlias
));
2898 // ----------------- construct GroupBy and attachen ------------
2899 if(!aHavingStr
.isEmpty())
2901 aSqlCmd
.append(" HAVING ");
2902 aSqlCmd
.append(aHavingStr
.makeStringAndClear());
2904 // ----------------- construct sorting and attach ------------
2906 SqlParseError eErrorCode
= eOk
;
2907 if ( (eErrorCode
= GenerateOrder(this,rFieldList
,nTabcount
> 1,sOrder
)) == eOk
)
2908 aSqlCmd
.append(sOrder
);
2911 if ( !m_rController
.hasError() )
2912 m_rController
.appendError( getParseErrorMessage( eErrorCode
) );
2914 m_rController
.displayError();
2916 // --------------------- Limit Clause -------------------
2918 const sal_Int64 nLimit
= rController
.getLimit();
2921 aSqlCmd
.append( " LIMIT " + OUString::number(nLimit
) );
2925 OUString sSQL
= aSqlCmd
.makeStringAndClear();
2926 if ( xConnection
.is() )
2928 ::connectivity::OSQLParser
& rParser( rController
.getParser() );
2929 OUString sErrorMessage
;
2930 boost::scoped_ptr
<OSQLParseNode
> pParseNode( rParser
.parseTree( sErrorMessage
, sSQL
, true ) );
2931 if ( pParseNode
.get() )
2933 OSQLParseNode
* pNode
= pParseNode
->getChild(3)->getChild(1);
2934 if ( pNode
->count() > 1 )
2936 ::connectivity::OSQLParseNode
* pCondition
= pNode
->getChild(1);
2937 if ( pCondition
) // no where clause
2939 OSQLParseNode::compress(pCondition
);
2941 pParseNode
->parseNodeToStr(sTemp
,xConnection
);
2950 void OQueryDesignView::setSlotEnabled(sal_Int32 _nSlotId
, bool _bEnable
)
2955 case SID_QUERY_VIEW_FUNCTIONS
:
2956 nRow
= BROW_FUNCTION_ROW
;
2958 case SID_QUERY_VIEW_TABLES
:
2959 nRow
= BROW_TABLE_ROW
;
2961 case SID_QUERY_VIEW_ALIASES
:
2962 nRow
= BROW_COLUMNALIAS_ROW
;
2969 m_pSelectionBox
->SetRowVisible(nRow
,_bEnable
);
2970 m_pSelectionBox
->Invalidate();
2973 bool OQueryDesignView::isSlotEnabled(sal_Int32 _nSlotId
)
2978 case SID_QUERY_VIEW_FUNCTIONS
:
2979 nRow
= BROW_FUNCTION_ROW
;
2981 case SID_QUERY_VIEW_TABLES
:
2982 nRow
= BROW_TABLE_ROW
;
2984 case SID_QUERY_VIEW_ALIASES
:
2985 nRow
= BROW_COLUMNALIAS_ROW
;
2992 return m_pSelectionBox
->IsRowVisible(nRow
);
2995 void OQueryDesignView::SaveUIConfig()
2997 OQueryController
& rCtrl
= static_cast<OQueryController
&>(getController());
2998 rCtrl
.SaveTabWinsPosSize( &m_pTableView
->GetTabWinMap(), m_pScrollWindow
->GetHScrollBar().GetThumbPos(), m_pScrollWindow
->GetVScrollBar().GetThumbPos() );
2999 rCtrl
.setVisibleRows( m_pSelectionBox
->GetNoneVisibleRows() );
3000 if ( m_aSplitter
->GetSplitPosPixel() != 0 )
3001 rCtrl
.setSplitPos( m_aSplitter
->GetSplitPosPixel() );
3004 OSQLParseNode
* OQueryDesignView::getPredicateTreeFromEntry(OTableFieldDescRef pEntry
,
3005 const OUString
& _sCriteria
,
3006 OUString
& _rsErrorMessage
,
3007 Reference
<XPropertySet
>& _rxColumn
) const
3009 OSL_ENSURE(pEntry
.is(),"Entry is null!");
3012 Reference
< XConnection
> xConnection
= static_cast<OQueryController
&>(getController()).getConnection();
3013 if(!xConnection
.is())
3016 ::connectivity::OSQLParser
& rParser( static_cast<OQueryController
&>(getController()).getParser() );
3017 OQueryTableWindow
* pWin
= static_cast<OQueryTableWindow
*>(pEntry
->GetTabWindow());
3019 // special handling for functions
3020 if ( pEntry
->GetFunctionType() & (FKT_OTHER
| FKT_AGGREGATE
| FKT_NUMERIC
) )
3022 // we have a function here so we have to distinguish the type of return vOUalue
3024 if ( pEntry
->isNumericOrAggreateFunction() )
3025 sFunction
= pEntry
->GetFunction();
3027 if ( sFunction
.isEmpty() )
3028 sFunction
= pEntry
->GetField();
3030 if (comphelper::string::getTokenCount(sFunction
, '(') > 1)
3031 sFunction
= sFunction
.getToken(0,'('); // this should be the name of the function
3033 sal_Int32 nType
= ::connectivity::OSQLParser::getFunctionReturnType(sFunction
,&rParser
.getContext());
3034 if ( nType
== DataType::OTHER
|| (sFunction
.isEmpty() && pEntry
->isNumericOrAggreateFunction()) )
3036 // first try the international version
3038 sSql
+= "SELECT * ";
3039 sSql
+= " FROM x WHERE ";
3040 sSql
+= pEntry
->GetField();
3042 boost::scoped_ptr
<OSQLParseNode
> pParseNode( rParser
.parseTree( _rsErrorMessage
, sSql
, true ) );
3043 nType
= DataType::DOUBLE
;
3044 if ( pParseNode
.get() )
3046 OSQLParseNode
* pColumnRef
= pParseNode
->getByRule(OSQLParseNode::column_ref
);
3049 OTableFieldDescRef aField
= new OTableFieldDesc();
3050 if ( eOk
== FillDragInfo(this,pColumnRef
,aField
) )
3052 nType
= aField
->GetDataType();
3058 Reference
<XDatabaseMetaData
> xMeta
= xConnection
->getMetaData();
3059 parse::OParseColumn
* pColumn
= new parse::OParseColumn( pEntry
->GetField(),
3063 ColumnValue::NULLABLE_UNKNOWN
,
3069 xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers(),
3073 _rxColumn
= pColumn
;
3074 pColumn
->setFunction(true);
3075 pColumn
->setRealName(pEntry
->GetField());
3081 Reference
<XNameAccess
> xColumns
= pWin
->GetOriginalColumns();
3082 if (xColumns
.is() && xColumns
->hasByName(pEntry
->GetField()))
3083 xColumns
->getByName(pEntry
->GetField()) >>= _rxColumn
;
3087 OUString
sTest(_sCriteria
);
3088 // _rxColumn, if it is a "lookup" column, not a computed column,
3089 // is guaranteed to be the column taken from the *source* of the column,
3090 // that is either a table or another query.
3091 // _rxColumn is *not* taken from the columns of the query we are constructing
3092 // (and rightfully so, since it may not be part of these columns; SELECT A FROM t WHERE B = foo)
3093 // If it is a computed column, we just constructed it above, with same Name and RealName.
3094 // In all cases, we should use the "external" name of the column, not the "RealName";
3095 // the latter is the name that the column had in the source of the source query.
3096 // An example: we are designing "SELECT A, B FROM q WHERE C='foo'"
3097 // q itself is query "SELECT aye AS A, bee as B, cee as C FROM t"
3098 // We are currently treating the entry "C='foo'"
3099 // Then _rxColumn has Name "C" and RealName "cee". We should *obviously* use "C", not "cee".
3100 OSQLParseNode
* pParseNode
= rParser
.predicateTree( _rsErrorMessage
,
3102 static_cast<OQueryController
&>(getController()).getNumberFormatter(),
3108 void OQueryDesignView::GetFocus()
3110 OQueryView::GetFocus();
3111 if ( m_pSelectionBox
&& !m_pSelectionBox
->HasChildPathFocus() )
3113 // first we have to deactivate the current cell to refill when necessary
3114 m_pSelectionBox
->DeactivateCell();
3115 m_pSelectionBox
->ActivateCell(m_pSelectionBox
->GetCurRow(), m_pSelectionBox
->GetCurColumnId());
3116 m_pSelectionBox
->GrabFocus();
3120 void OQueryDesignView::reset()
3122 m_pTableView
->ClearAll();
3123 m_pTableView
->ReSync();
3126 void OQueryDesignView::setNoneVisbleRow(sal_Int32 _nRows
)
3128 m_pSelectionBox
->SetNoneVisbleRow(_nRows
);
3131 void OQueryDesignView::initByFieldDescriptions( const Sequence
< PropertyValue
>& i_rFieldDescriptions
)
3133 OQueryController
& rController
= static_cast< OQueryController
& >( getController() );
3135 m_pSelectionBox
->PreFill();
3136 m_pSelectionBox
->SetReadOnly( rController
.isReadOnly() );
3137 m_pSelectionBox
->Fill();
3139 for ( const PropertyValue
* field
= i_rFieldDescriptions
.getConstArray();
3140 field
!= i_rFieldDescriptions
.getConstArray() + i_rFieldDescriptions
.getLength();
3144 ::rtl::Reference
< OTableFieldDesc
> pField( new OTableFieldDesc() );
3145 pField
->Load( *field
, true );
3146 InsertField( pField
, true, false );
3149 rController
.ClearUndoManager();
3150 m_pSelectionBox
->Invalidate();
3153 bool OQueryDesignView::initByParseIterator( ::dbtools::SQLExceptionInfo
* _pErrorInfo
)
3155 SqlParseError eErrorCode
= eNativeMode
;
3156 m_rController
.clearError();
3160 eErrorCode
= InitFromParseNodeImpl( this, m_pSelectionBox
);
3162 if ( eErrorCode
!= eOk
)
3164 if ( !m_rController
.hasError() )
3165 m_rController
.appendError( getParseErrorMessage( eErrorCode
) );
3169 *_pErrorInfo
= m_rController
.getError();
3173 m_rController
.displayError();
3177 catch ( const Exception
& )
3179 DBG_UNHANDLED_EXCEPTION();
3181 return eErrorCode
== eOk
;
3184 // Utility function for fillFunctionInfo
3186 sal_Int32
char_datatype(const::connectivity::OSQLParseNode
* pDataType
, const unsigned int offset
) {
3187 int cnt
= pDataType
->count() - offset
;
3190 OSL_FAIL("internal error in decoding character datatype specification");
3191 return DataType::VARCHAR
;
3193 else if ( cnt
== 0 )
3197 // The datatype is the node itself
3198 if ( SQL_ISTOKENOR2 (pDataType
, CHARACTER
, CHAR
) )
3199 return DataType::CHAR
;
3200 else if ( SQL_ISTOKEN (pDataType
, VARCHAR
) )
3201 return DataType::VARCHAR
;
3202 else if ( SQL_ISTOKEN (pDataType
, CLOB
) )
3203 return DataType::CLOB
;
3206 OSL_FAIL("unknown/unexpected token in decoding character datatype specification");
3207 return DataType::VARCHAR
;
3212 // No child left to read!
3213 OSL_FAIL("incomplete datatype in decoding character datatype specification");
3214 return DataType::VARCHAR
;
3218 if ( SQL_ISTOKEN(pDataType
->getChild(offset
), NATIONAL
) )
3219 return char_datatype(pDataType
, offset
+1);
3220 else if ( SQL_ISTOKENOR3(pDataType
->getChild(offset
), CHARACTER
, CHAR
, NCHAR
) )
3222 if ( cnt
> 2 && SQL_ISTOKEN(pDataType
->getChild(offset
+1), LARGE
) && SQL_ISTOKEN(pDataType
->getChild(offset
+2), OBJECT
) )
3223 return DataType::CLOB
;
3224 else if ( cnt
> 1 && SQL_ISTOKEN(pDataType
->getChild(offset
+1), VARYING
) )
3225 return DataType::VARCHAR
;
3227 return DataType::CHAR
;
3229 else if ( SQL_ISTOKEN (pDataType
->getChild(offset
), VARCHAR
) )
3230 return DataType::VARCHAR
;
3231 else if ( SQL_ISTOKENOR2 (pDataType
->getChild(offset
), CLOB
, NCLOB
) )
3232 return DataType::CLOB
;
3234 OSL_FAIL("unrecognised character datatype");
3235 return DataType::VARCHAR
;
3239 // Try to guess the type of an expression in simple cases.
3240 // Originally meant to be called only on a function call (hence the misnomer),
3241 // but now tries to do the best it can also in other cases.
3242 // Don't completely rely on fillFunctionInfo,
3243 // it won't look at the function's arguments to find the return type
3244 // (in particular, in the case of general_set_fct,
3245 // the return type is the type of the argument;
3246 // if that is (as is typical) a column reference,
3247 // it is the type of the column).
3248 // TODO: There is similar "guess the expression's type" code in several places:
3249 // SelectionBrowseBox.cxx: OSelectionBrowseBox::saveField
3250 // QueryDesignView.cxx: InstallFields, GetOrderCriteria, GetGroupCriteria
3251 // If possible, they should be factorised into this function
3252 // (which should then be renamed...)
3254 void OQueryDesignView::fillFunctionInfo( const ::connectivity::OSQLParseNode
* pNode
3255 ,const OUString
& sFunctionTerm
3256 ,OTableFieldDescRef
& aInfo
)
3258 // get the type of the expression, as far as easily possible
3259 OQueryController
& rController
= static_cast<OQueryController
&>(getController());
3260 sal_Int32 nDataType
= DataType::DOUBLE
;
3261 switch(pNode
->getNodeType())
3263 case SQL_NODE_CONCAT
:
3264 case SQL_NODE_STRING
:
3265 nDataType
= DataType::VARCHAR
;
3267 case SQL_NODE_INTNUM
:
3268 nDataType
= DataType::INTEGER
;
3270 case SQL_NODE_APPROXNUM
:
3271 nDataType
= DataType::DOUBLE
;
3274 case SQL_NODE_ACCESS_DATE
:
3275 nDataType
= DataType::TIMESTAMP
;
3277 case SQL_NODE_COMPARISON
:
3278 case SQL_NODE_EQUAL
:
3280 case SQL_NODE_GREAT
:
3281 case SQL_NODE_LESSEQ
:
3282 case SQL_NODE_GREATEQ
:
3283 case SQL_NODE_NOTEQUAL
:
3284 nDataType
= DataType::BOOLEAN
;
3287 case SQL_NODE_LISTRULE
:
3288 case SQL_NODE_COMMALISTRULE
:
3289 case SQL_NODE_KEYWORD
:
3290 case SQL_NODE_AMMSC
: //??
3291 case SQL_NODE_PUNCTUATION
:
3292 OSL_FAIL("Unexpected SQL Node Type");
3295 switch(pNode
->getKnownRuleID())
3297 case OSQLParseNode::select_statement
:
3298 case OSQLParseNode::table_exp
:
3299 case OSQLParseNode::table_ref_commalist
:
3300 case OSQLParseNode::table_ref
:
3301 case OSQLParseNode::catalog_name
:
3302 case OSQLParseNode::schema_name
:
3303 case OSQLParseNode::table_name
:
3304 case OSQLParseNode::opt_column_commalist
:
3305 case OSQLParseNode::column_commalist
:
3306 case OSQLParseNode::column_ref_commalist
:
3307 case OSQLParseNode::column_ref
:
3308 case OSQLParseNode::opt_order_by_clause
:
3309 case OSQLParseNode::ordering_spec_commalist
:
3310 case OSQLParseNode::ordering_spec
:
3311 case OSQLParseNode::opt_asc_desc
:
3312 case OSQLParseNode::where_clause
:
3313 case OSQLParseNode::opt_where_clause
:
3314 case OSQLParseNode::opt_escape
:
3315 case OSQLParseNode::scalar_exp_commalist
:
3316 case OSQLParseNode::scalar_exp
: // Seems to never be generated?
3317 case OSQLParseNode::parameter_ref
:
3318 case OSQLParseNode::parameter
:
3319 case OSQLParseNode::range_variable
:
3320 case OSQLParseNode::delete_statement_positioned
:
3321 case OSQLParseNode::delete_statement_searched
:
3322 case OSQLParseNode::update_statement_positioned
:
3323 case OSQLParseNode::update_statement_searched
:
3324 case OSQLParseNode::assignment_commalist
:
3325 case OSQLParseNode::assignment
:
3326 case OSQLParseNode::insert_statement
:
3327 case OSQLParseNode::insert_atom_commalist
:
3328 case OSQLParseNode::insert_atom
:
3329 case OSQLParseNode::from_clause
:
3330 case OSQLParseNode::qualified_join
:
3331 case OSQLParseNode::cross_union
:
3332 case OSQLParseNode::select_sublist
:
3333 case OSQLParseNode::join_type
:
3334 case OSQLParseNode::named_columns_join
:
3335 case OSQLParseNode::joined_table
:
3336 case OSQLParseNode::sql_not
:
3337 case OSQLParseNode::manipulative_statement
:
3338 case OSQLParseNode::value_exp_commalist
:
3339 case OSQLParseNode::union_statement
:
3340 case OSQLParseNode::outer_join_type
:
3341 case OSQLParseNode::selection
:
3342 case OSQLParseNode::base_table_def
:
3343 case OSQLParseNode::base_table_element_commalist
:
3344 case OSQLParseNode::data_type
:
3345 case OSQLParseNode::column_def
:
3346 case OSQLParseNode::table_node
:
3347 case OSQLParseNode::as_clause
:
3348 case OSQLParseNode::opt_as
:
3349 case OSQLParseNode::op_column_commalist
:
3350 case OSQLParseNode::table_primary_as_range_column
:
3351 case OSQLParseNode::character_string_type
:
3352 case OSQLParseNode::comparison
:
3353 OSL_FAIL("Unexpected SQL RuleID");
3355 case OSQLParseNode::column
:
3356 case OSQLParseNode::column_val
:
3357 OSL_FAIL("Cannot guess column type");
3359 case OSQLParseNode::values_or_query_spec
:
3360 OSL_FAIL("Cannot guess VALUES type");
3362 case OSQLParseNode::derived_column
:
3363 OSL_FAIL("Cannot guess computed column type");
3365 case OSQLParseNode::subquery
:
3366 OSL_FAIL("Cannot guess subquery return type");
3368 case OSQLParseNode::search_condition
:
3369 case OSQLParseNode::comparison_predicate
:
3370 case OSQLParseNode::between_predicate
:
3371 case OSQLParseNode::like_predicate
:
3372 case OSQLParseNode::test_for_null
:
3373 case OSQLParseNode::boolean_term
:
3374 case OSQLParseNode::boolean_primary
:
3375 case OSQLParseNode::in_predicate
:
3376 case OSQLParseNode::existence_test
:
3377 case OSQLParseNode::unique_test
:
3378 case OSQLParseNode::all_or_any_predicate
:
3379 case OSQLParseNode::join_condition
:
3380 case OSQLParseNode::boolean_factor
:
3381 case OSQLParseNode::comparison_predicate_part_2
:
3382 case OSQLParseNode::parenthesized_boolean_value_expression
:
3383 case OSQLParseNode::other_like_predicate_part_2
:
3384 case OSQLParseNode::between_predicate_part_2
:
3385 nDataType
= DataType::BOOLEAN
;
3387 case OSQLParseNode::num_value_exp
:
3388 case OSQLParseNode::extract_exp
:
3389 case OSQLParseNode::term
:
3390 case OSQLParseNode::factor
:
3391 // Might by an integer or a float; take the most generic
3392 nDataType
= DataType::DOUBLE
;
3394 case OSQLParseNode::value_exp_primary
:
3395 case OSQLParseNode::value_exp
:
3396 case OSQLParseNode::odbc_call_spec
:
3397 // Really, we don't know. Let the default.
3399 case OSQLParseNode::position_exp
:
3400 case OSQLParseNode::length_exp
:
3401 nDataType
= DataType::INTEGER
;
3403 case OSQLParseNode::char_value_exp
:
3404 case OSQLParseNode::char_value_fct
:
3405 case OSQLParseNode::fold
:
3406 case OSQLParseNode::char_substring_fct
:
3407 case OSQLParseNode::char_factor
:
3408 case OSQLParseNode::concatenation
:
3409 nDataType
= DataType::VARCHAR
;
3411 case OSQLParseNode::datetime_primary
:
3412 nDataType
= DataType::TIMESTAMP
;
3414 case OSQLParseNode::bit_value_fct
:
3415 nDataType
= DataType::BINARY
;
3417 case OSQLParseNode::general_set_fct
: // May depend on argument; ignore that for now
3418 case OSQLParseNode::set_fct_spec
:
3420 if (pNode
->count() == 0)
3422 // This is not a function call, no sense to continue with a function return type lookup
3423 OSL_FAIL("Got leaf SQL node where non-leaf expected");
3426 const OSQLParseNode
* pFunctionName
= pNode
->getChild(0);
3427 if ( SQL_ISPUNCTUATION(pFunctionName
,"{") )
3429 if ( pNode
->count() == 3 )
3430 return fillFunctionInfo( pNode
->getChild(1), sFunctionTerm
, aInfo
);
3432 OSL_FAIL("ODBC escape not in recognised form");
3437 if ( SQL_ISRULEOR2(pNode
,length_exp
,char_value_fct
) )
3438 pFunctionName
= pFunctionName
->getChild(0);
3440 OUString sFunctionName
= pFunctionName
->getTokenValue();
3441 if ( sFunctionName
.isEmpty() )
3442 sFunctionName
= OStringToOUString(OSQLParser::TokenIDToStr(pFunctionName
->getTokenID()),RTL_TEXTENCODING_UTF8
);
3444 nDataType
= OSQLParser::getFunctionReturnType(
3446 ,&rController
.getParser().getContext());
3450 case OSQLParseNode::odbc_fct_spec
:
3452 if (pNode
->count() != 2)
3454 OSL_FAIL("interior of ODBC escape not in recognised shape");
3458 const OSQLParseNode
* const pEscapeType
= pNode
->getChild(0);
3459 if (SQL_ISTOKEN(pEscapeType
, TS
))
3460 nDataType
= DataType::TIMESTAMP
;
3461 else if (SQL_ISTOKEN(pEscapeType
, D
))
3462 nDataType
= DataType::DATE
;
3463 else if (SQL_ISTOKEN(pEscapeType
, T
))
3464 nDataType
= DataType::TIME
;
3465 else if (SQL_ISTOKEN(pEscapeType
, FN
))
3466 return fillFunctionInfo( pNode
->getChild(1), sFunctionTerm
, aInfo
);
3468 OSL_FAIL("Unknown ODBC escape");
3471 case OSQLParseNode::cast_spec
:
3473 if ( pNode
->count() != 6 || !SQL_ISTOKEN(pNode
->getChild(3), AS
) )
3475 OSL_FAIL("CAST not in recognised shape");
3478 const OSQLParseNode
*pCastTarget
= pNode
->getChild(4);
3479 if ( SQL_ISTOKENOR2(pCastTarget
, INTEGER
, INT
) )
3480 nDataType
= DataType::INTEGER
;
3481 else if ( SQL_ISTOKEN(pCastTarget
, SMALLINT
) )
3482 nDataType
= DataType::SMALLINT
;
3483 else if ( SQL_ISTOKEN(pCastTarget
, BIGINT
) )
3484 nDataType
= DataType::BIGINT
;
3485 else if ( SQL_ISTOKEN(pCastTarget
, FLOAT
) )
3486 nDataType
= DataType::FLOAT
;
3487 else if ( SQL_ISTOKEN(pCastTarget
, REAL
) )
3488 nDataType
= DataType::REAL
;
3489 else if ( SQL_ISTOKEN(pCastTarget
, DOUBLE
) )
3490 nDataType
= DataType::DOUBLE
;
3491 else if ( SQL_ISTOKEN(pCastTarget
, BOOLEAN
) )
3492 nDataType
= DataType::BOOLEAN
;
3493 else if ( SQL_ISTOKEN(pCastTarget
, DATE
) )
3494 nDataType
= DataType::DATE
;
3495 else if ( pCastTarget
->count() > 0 )
3497 const OSQLParseNode
*pDataType
= pCastTarget
->getChild(0);
3498 while (pDataType
->count() > 0)
3500 pCastTarget
= pDataType
;
3501 pDataType
= pDataType
->getChild(0);
3503 if ( SQL_ISTOKEN (pDataType
, TIME
) )
3504 nDataType
= DataType::TIME
;
3505 else if ( SQL_ISTOKEN (pDataType
, TIMESTAMP
) )
3506 nDataType
= DataType::TIMESTAMP
;
3507 else if ( SQL_ISTOKENOR3 (pDataType
, CHARACTER
, CHAR
, NCHAR
) )
3508 nDataType
= char_datatype(pCastTarget
, 0);
3509 else if ( SQL_ISTOKEN (pDataType
, VARCHAR
) )
3510 nDataType
= DataType::VARCHAR
;
3511 else if ( SQL_ISTOKEN (pDataType
, CLOB
) )
3512 nDataType
= DataType::CLOB
;
3513 else if ( SQL_ISTOKEN (pDataType
, NATIONAL
) )
3514 nDataType
= char_datatype(pCastTarget
, 1);
3515 else if ( SQL_ISTOKEN (pDataType
, BINARY
) )
3517 if ( pCastTarget
->count() > 2 && SQL_ISTOKEN(pCastTarget
->getChild(1), LARGE
) && SQL_ISTOKEN(pCastTarget
->getChild(2), OBJECT
) )
3518 nDataType
= DataType::BLOB
;
3519 else if ( pCastTarget
->count() > 1 && SQL_ISTOKEN(pCastTarget
->getChild(1), VARYING
) )
3520 nDataType
= DataType::VARBINARY
;
3522 nDataType
= DataType::BINARY
;
3524 else if ( SQL_ISTOKEN (pDataType
, VARBINARY
) )
3525 nDataType
= DataType::VARBINARY
;
3526 else if ( SQL_ISTOKEN (pDataType
, BLOB
) )
3527 nDataType
= DataType::BLOB
;
3528 else if ( SQL_ISTOKEN (pDataType
, NUMERIC
) )
3529 nDataType
= DataType::NUMERIC
;
3530 else if ( SQL_ISTOKENOR2 (pDataType
, DECIMAL
, DEC
) )
3531 nDataType
= DataType::DECIMAL
;
3532 else if ( SQL_ISTOKEN (pDataType
, FLOAT
) )
3533 nDataType
= DataType::FLOAT
;
3534 else if ( SQL_ISTOKEN (pDataType
, DOUBLE
) )
3535 nDataType
= DataType::DOUBLE
;
3536 else if ( SQL_ISTOKEN (pDataType
, INTERVAL
) )
3537 // Not in DataType published constant (because not in JDBC...)
3538 nDataType
= DataType::VARCHAR
;
3540 OSL_FAIL("Failed to decode CAST target");
3543 OSL_FAIL("Could not decipher CAST target");
3547 OSL_FAIL("Unknown SQL RuleID");
3552 OSL_FAIL("Unknown SQL Node Type");
3556 aInfo
->SetDataType(nDataType
);
3557 aInfo
->SetFieldType(TAB_NORMAL_FIELD
);
3558 aInfo
->SetField(sFunctionTerm
);
3559 aInfo
->SetTabWindow(NULL
);
3562 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */