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 <querycontroller.hxx>
24 #include <sqlbison.hxx>
25 #include <vcl/split.hxx>
26 #include <comphelper/diagnose_ex.hxx>
27 #include <o3tl/safeint.hxx>
28 #include <o3tl/string_view.hxx>
29 #include <osl/diagnose.h>
30 #include <vcl/svapp.hxx>
31 #include <vcl/weld.hxx>
32 #include <browserids.hxx>
33 #include "SelectionBrowseBox.hxx"
34 #include <strings.hrc>
35 #include <strings.hxx>
36 #include <comphelper/string.hxx>
37 #include <connectivity/dbtools.hxx>
38 #include <connectivity/dbexception.hxx>
39 #include <com/sun/star/sdbc/DataType.hpp>
40 #include <com/sun/star/container/XNameAccess.hpp>
41 #include <com/sun/star/sdbc/ColumnValue.hpp>
42 #include <connectivity/PColumn.hxx>
43 #include "QTableConnection.hxx"
44 #include <ConnectionLineData.hxx>
45 #include "QTableConnectionData.hxx"
46 #include <core_resource.hxx>
47 #include <UITools.hxx>
48 #include <querycontainerwindow.hxx>
49 #include <unotools/localedatawrapper.hxx>
50 #include <unotools/syslocale.hxx>
53 #include <string_view>
55 using namespace ::dbaui
;
56 using namespace ::utl
;
57 using namespace ::connectivity
;
58 using namespace ::dbtools
;
59 using namespace ::com::sun::star::uno
;
60 using namespace ::com::sun::star::lang
;
61 using namespace ::com::sun::star::i18n
;
62 using namespace ::com::sun::star::sdbc
;
63 using namespace ::com::sun::star::beans
;
64 using namespace ::com::sun::star::container
;
66 // here we define our functions used in the anonymous namespace to get our header file smaller
67 // please look at the book LargeScale C++ to know why
70 const char C_AND
[] = " AND ";
71 const char C_OR
[] = " OR ";
73 bool InsertJoin( const OQueryDesignView
* _pView
,
74 const ::connectivity::OSQLParseNode
*pNode
);
76 SqlParseError
InstallFields(OQueryDesignView
* _pView
,
77 const ::connectivity::OSQLParseNode
* pNode
,
78 OJoinTableView::OTableWindowMap
* pTabList
);
80 SqlParseError
GetGroupCriteria( OQueryDesignView
* _pView
,
81 OSelectionBrowseBox
* _pSelectionBrw
,
82 const ::connectivity::OSQLParseNode
* pSelectRoot
);
84 SqlParseError
GetHavingCriteria(OQueryDesignView
* _pView
,
85 OSelectionBrowseBox
* _pSelectionBrw
,
86 const ::connectivity::OSQLParseNode
* pSelectRoot
,
89 SqlParseError
GetOrderCriteria( OQueryDesignView
* _pView
,
90 OSelectionBrowseBox
* _pSelectionBrw
,
91 const ::connectivity::OSQLParseNode
* pParseRoot
);
93 SqlParseError
AddFunctionCondition(OQueryDesignView
const * _pView
,
94 OSelectionBrowseBox
* _pSelectionBrw
,
95 const ::connectivity::OSQLParseNode
* pCondition
,
96 const sal_uInt16 nLevel
,
98 bool _bAddOrOnOneLine
);
100 OUString
quoteTableAlias(bool _bQuote
, const OUString
& _sAliasName
, std::u16string_view _sQuote
)
103 if ( _bQuote
&& !_sAliasName
.isEmpty() )
105 sRet
= ::dbtools::quoteName(_sQuote
,_sAliasName
) + ".";
109 OUString
getTableRange(const OQueryDesignView
* _pView
,const ::connectivity::OSQLParseNode
* _pTableRef
)
111 Reference
< XConnection
> xConnection
= static_cast<OQueryController
&>(_pView
->getController()).getConnection();
112 OUString sTableRange
;
115 sTableRange
= ::connectivity::OSQLParseNode::getTableRange(_pTableRef
);
116 if ( sTableRange
.isEmpty() )
117 _pTableRef
->parseNodeToStr(sTableRange
,xConnection
,nullptr,false,false);
121 void insertConnection(const OQueryDesignView
* _pView
,const EJoinType
& _eJoinType
, const OTableFieldDescRef
& _aDragLeft
, const OTableFieldDescRef
& _aDragRight
, bool _bNatural
= false)
123 OQueryTableView
* pTableView
= static_cast<OQueryTableView
*>(_pView
->getTableView());
124 OQueryTableConnection
* pConn
= static_cast<OQueryTableConnection
*>( pTableView
->GetTabConn(static_cast<OTableWindow
*>(_aDragLeft
->GetTabWindow()),static_cast<OTableWindow
*>(_aDragRight
->GetTabWindow()),true));
128 auto xInfoData
= std::make_shared
<OQueryTableConnectionData
>();
129 xInfoData
->InitFromDrag(_aDragLeft
, _aDragRight
);
130 xInfoData
->SetJoinType(_eJoinType
);
134 xInfoData
->ResetConnLines();
135 xInfoData
->setNatural(_bNatural
);
138 Reference
<XNameAccess
> xReferencedTableColumns(xInfoData
->getReferencedTable()->getColumns());
139 Sequence
< OUString
> aSeq
= xInfoData
->getReferencingTable()->getColumns()->getElementNames();
140 const OUString
* pIter
= aSeq
.getConstArray();
141 const OUString
* pEnd
= pIter
+ aSeq
.getLength();
142 for(;pIter
!= pEnd
;++pIter
)
144 if ( xReferencedTableColumns
->hasByName(*pIter
) )
145 xInfoData
->AppendConnLine(*pIter
,*pIter
);
148 catch( const Exception
& )
150 DBG_UNHANDLED_EXCEPTION("dbaccess");
154 ScopedVclPtrInstance
< OQueryTableConnection
> aInfo(pTableView
, xInfoData
);
155 // Because OQueryTableConnection never takes ownership of the data passed to it, but only remembers the pointer,
156 // this pointer to a local variable is not critical, as xInfoData and aInfo have the same lifetime
157 pTableView
->NotifyTabConnection( *aInfo
);
161 OUString
aSourceFieldName(_aDragLeft
->GetField());
162 OUString
aDestFieldName(_aDragRight
->GetField());
163 // the connection could point on the other side
164 if(pConn
->GetSourceWin() == _aDragRight
->GetTabWindow())
166 OUString
aTmp(aSourceFieldName
);
167 aSourceFieldName
= aDestFieldName
;
168 aDestFieldName
= aTmp
;
170 pConn
->GetData()->AppendConnLine( aSourceFieldName
,aDestFieldName
);
171 pConn
->UpdateLineList();
175 pConn
->RecalcLines();
176 // for the following Invalidate, the new Connection must first be able
177 // to determine its BoundingRect
178 pConn
->InvalidateConnection();
181 OUString
ParseCondition( OQueryController
& rController
182 ,const ::connectivity::OSQLParseNode
* pCondition
183 ,const OUString
& _sDecimal
184 ,const css::lang::Locale
& _rLocale
185 ,sal_uInt32 _nStartIndex
)
188 Reference
< XConnection
> xConnection
= rController
.getConnection();
189 if ( xConnection
.is() )
191 sal_uInt32 nCount
= pCondition
->count();
192 for(sal_uInt32 i
= _nStartIndex
; i
< nCount
; ++i
)
193 pCondition
->getChild(i
)->parseNodeToPredicateStr(aCondition
,
195 rController
.getNumberFormatter(),
198 &rController
.getParser().getContext());
202 SqlParseError
FillOuterJoins(OQueryDesignView
const * _pView
,
203 const ::connectivity::OSQLParseNode
* pTableRefList
)
205 SqlParseError eErrorCode
= eOk
;
206 sal_uInt32 nCount
= pTableRefList
->count();
208 for (sal_uInt32 i
=0; !bError
&& i
< nCount
; ++i
)
210 const ::connectivity::OSQLParseNode
* pParseNode
= pTableRefList
->getChild(i
);
211 const ::connectivity::OSQLParseNode
* pJoinNode
= nullptr;
213 if ( SQL_ISRULE( pParseNode
, qualified_join
) || SQL_ISRULE( pParseNode
, joined_table
) || SQL_ISRULE( pParseNode
, cross_union
) )
214 pJoinNode
= pParseNode
;
215 else if( SQL_ISRULE(pParseNode
,table_ref
)
216 && pParseNode
->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
217 pJoinNode
= pParseNode
->getChild(2);
221 if ( !InsertJoin(_pView
,pJoinNode
) )
225 // check if error occurred
227 eErrorCode
= eIllegalJoin
;
232 /** FillDragInfo fills the field description out of the table
234 SqlParseError
FillDragInfo( const OQueryDesignView
* _pView
,
235 const ::connectivity::OSQLParseNode
* pColumnRef
,
236 OTableFieldDescRef
const & _rDragInfo
)
238 SqlParseError eErrorCode
= eOk
;
242 OUString aTableRange
,aColumnName
;
243 ::connectivity::OSQLParseTreeIterator
& rParseIter
= static_cast<OQueryController
&>(_pView
->getController()).getParseIterator();
244 rParseIter
.getColumnRange( pColumnRef
, aColumnName
, aTableRange
);
246 if ( !aTableRange
.isEmpty() )
248 OQueryTableWindow
* pSTW
= static_cast<OQueryTableView
*>(_pView
->getTableView())->FindTable( aTableRange
);
249 bErg
= (pSTW
&& pSTW
->ExistsField( aColumnName
, _rDragInfo
) );
253 sal_uInt16 nCntAccount
;
254 bErg
= static_cast<OQueryTableView
*>(_pView
->getTableView())->FindTableFromField(aColumnName
, _rDragInfo
, nCntAccount
);
256 bErg
= _pView
->HasFieldByAliasName(aColumnName
, _rDragInfo
);
260 eErrorCode
= eColumnNotFound
;
261 OUString
sError(DBA_RES(STR_QRY_COLUMN_NOT_FOUND
));
262 sError
= sError
.replaceFirst("$name$",aColumnName
);
263 _pView
->getController().appendError( sError
);
267 Reference
<XDatabaseMetaData
> xMeta
= _pView
->getController().getConnection()->getMetaData();
268 if ( xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers() )
269 _pView
->getController().appendError(DBA_RES(STR_QRY_CHECK_CASESENSITIVE
));
278 OUString
BuildJoinCriteria( const Reference
< XConnection
>& _xConnection
,
279 const OConnectionLineDataVec
* pLineDataList
,
280 const OQueryTableConnectionData
* pData
)
282 OUStringBuffer aCondition
;
283 if ( _xConnection
.is() )
287 const Reference
< XDatabaseMetaData
> xMetaData
= _xConnection
->getMetaData();
288 const OUString aQuote
= xMetaData
->getIdentifierQuoteString();
290 for (auto const& lineData
: *pLineDataList
)
292 if(!aCondition
.isEmpty())
293 aCondition
.append(C_AND
);
295 quoteTableAlias(true,pData
->GetAliasName(JTCS_FROM
),aQuote
)
296 + ::dbtools::quoteName(aQuote
, lineData
->GetFieldName(JTCS_FROM
) )
298 + quoteTableAlias(true,pData
->GetAliasName(JTCS_TO
),aQuote
)
299 + ::dbtools::quoteName(aQuote
, lineData
->GetFieldName(JTCS_TO
) ));
304 OSL_FAIL("Failure while building Join criteria!");
308 return aCondition
.makeStringAndClear();
310 /** JoinCycle looks for a join cycle and append it to the string
311 @param _xConnection the connection
312 @param _pEntryConn the table connection which holds the data
313 @param _pEntryTabTo the corresponding table window
314 @param _rJoin the String which will contain the resulting string
316 void JoinCycle( const Reference
< XConnection
>& _xConnection
,
317 OQueryTableConnection
* _pEntryConn
,
318 const OQueryTableWindow
* _pEntryTabTo
,
321 OSL_ENSURE(_pEntryConn
,"TableConnection can not be null!");
323 OQueryTableConnectionData
* pData
= static_cast< OQueryTableConnectionData
*>(_pEntryConn
->GetData().get());
324 if ( !(pData
->GetJoinType() != INNER_JOIN
&& _pEntryTabTo
->ExistsAVisitedConn()) )
328 if(_rJoin
.endsWith(")"))
331 _rJoin
= _rJoin
.replaceAt(_rJoin
.getLength()-1,1, u
" ");
333 _rJoin
+= C_AND
+ BuildJoinCriteria(_xConnection
,&pData
->GetConnLineDataList(),pData
);
336 _pEntryConn
->SetVisited(true);
338 OUString
BuildTable( const Reference
< XConnection
>& _xConnection
,
339 const OQueryTableWindow
* pEntryTab
,
343 OUString
aDBName(pEntryTab
->GetComposedName());
345 if( _xConnection
.is() )
349 Reference
< XDatabaseMetaData
> xMetaData
= _xConnection
->getMetaData();
351 OUString sCatalog
, sSchema
, sTable
;
352 ::dbtools::qualifiedNameComponents( xMetaData
, aDBName
, sCatalog
, sSchema
, sTable
, ::dbtools::EComposeRule::InDataManipulation
);
353 OUString aTableListStr
= ::dbtools::composeTableNameForSelect( _xConnection
, sCatalog
, sSchema
, sTable
);
355 OUString aQuote
= xMetaData
->getIdentifierQuoteString();
356 if ( _bForce
|| isAppendTableAliasEnabled( _xConnection
) || pEntryTab
->GetAliasName() != aDBName
)
358 aTableListStr
+= " ";
359 if ( generateAsBeforeTableAlias( _xConnection
) )
360 aTableListStr
+= "AS ";
361 aTableListStr
+= ::dbtools::quoteName( aQuote
, pEntryTab
->GetAliasName() );
363 aDBName
= aTableListStr
;
365 catch(const SQLException
&)
367 DBG_UNHANDLED_EXCEPTION("dbaccess");
372 OUString
BuildJoin( const Reference
< XConnection
>& _xConnection
,
374 std::u16string_view rRh
,
375 const OQueryTableConnectionData
* pData
)
379 if ( pData
->isNatural() && pData
->GetJoinType() != CROSS_JOIN
)
381 switch(pData
->GetJoinType())
384 aErg
+= " LEFT OUTER ";
387 aErg
+= " RIGHT OUTER ";
390 OSL_ENSURE(!pData
->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!");
394 OSL_ENSURE(pData
->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!");
398 aErg
+= " FULL OUTER ";
401 aErg
+= OUString::Concat("JOIN ") + rRh
;
402 if ( CROSS_JOIN
!= pData
->GetJoinType() && !pData
->isNatural() )
404 aErg
+= " ON " + BuildJoinCriteria(_xConnection
,&pData
->GetConnLineDataList(),pData
);
409 OUString
BuildJoin( const Reference
< XConnection
>& _xConnection
,
410 const OQueryTableWindow
* pLh
,
411 const OQueryTableWindow
* pRh
,
412 const OQueryTableConnectionData
* pData
415 bool bForce
= pData
->GetJoinType() == CROSS_JOIN
|| pData
->isNatural();
416 return BuildJoin(_xConnection
,BuildTable(_xConnection
,pLh
,bForce
),BuildTable(_xConnection
,pRh
,bForce
),pData
);
418 OUString
BuildJoin( const Reference
< XConnection
>& _xConnection
,
420 const OQueryTableWindow
* pRh
,
421 const OQueryTableConnectionData
* pData
424 return BuildJoin(_xConnection
,rLh
,BuildTable(_xConnection
,pRh
),pData
);
426 OUString
BuildJoin( const Reference
< XConnection
>& _xConnection
,
427 const OQueryTableWindow
* pLh
,
429 const OQueryTableConnectionData
* pData
433 // - does not support any bracketing of JOINS
434 // - supports nested joins only in the LEFT HAND SIDE
435 // In this case, we are trying to build a join with a nested join
436 // in the right hand side.
437 // So switch the direction of the join and both hand sides.
438 OQueryTableConnectionData
data(*pData
);
439 switch (data
.GetJoinType())
442 data
.SetJoinType(RIGHT_JOIN
);
445 data
.SetJoinType(LEFT_JOIN
);
448 // the other join types are symmetric, so nothing to change
451 return BuildJoin(_xConnection
, rRh
, BuildTable(_xConnection
,pLh
), &data
);
453 void addConnectionTableNames( const Reference
< XConnection
>& _xConnection
,
454 const OQueryTableConnection
* const pEntryConn
,
455 std::set
<OUString
> &_rTableNames
)
457 // insert tables into table list to avoid double entries
458 const OQueryTableWindow
* const pEntryTabFrom
= static_cast<OQueryTableWindow
*>(pEntryConn
->GetSourceWin());
459 const OQueryTableWindow
* const pEntryTabTo
= static_cast<OQueryTableWindow
*>(pEntryConn
->GetDestWin());
460 _rTableNames
.insert(BuildTable(_xConnection
,pEntryTabFrom
));
461 _rTableNames
.insert(BuildTable(_xConnection
,pEntryTabTo
));
463 void GetNextJoin( const Reference
< XConnection
>& _xConnection
,
464 OQueryTableConnection
* pEntryConn
,
465 OQueryTableWindow
const * pEntryTabTo
,
467 std::set
<OUString
> &_rTableNames
)
469 OQueryTableConnectionData
* pEntryConnData
= static_cast<OQueryTableConnectionData
*>(pEntryConn
->GetData().get());
470 if ( pEntryConnData
->GetJoinType() == INNER_JOIN
&& !pEntryConnData
->isNatural() )
475 addConnectionTableNames(_xConnection
, pEntryConn
, _rTableNames
);
476 OQueryTableWindow
* pEntryTabFrom
= static_cast<OQueryTableWindow
*>(pEntryConn
->GetSourceWin());
477 aJoin
= BuildJoin(_xConnection
,pEntryTabFrom
,pEntryTabTo
,pEntryConnData
);
479 else if(pEntryTabTo
== pEntryConn
->GetDestWin())
481 addConnectionTableNames(_xConnection
, pEntryConn
, _rTableNames
);
482 aJoin
= BuildJoin(_xConnection
,aJoin
,pEntryTabTo
,pEntryConnData
);
484 else if(pEntryTabTo
== pEntryConn
->GetSourceWin())
486 addConnectionTableNames(_xConnection
, pEntryConn
, _rTableNames
);
487 aJoin
= BuildJoin(_xConnection
,pEntryTabTo
,aJoin
,pEntryConnData
);
490 pEntryConn
->SetVisited(true);
492 // first search for the "to" window
493 const auto& rConnections
= pEntryConn
->GetParent()->getTableConnections();
495 for (auto const& connection
: rConnections
)
497 OQueryTableConnection
* pNext
= static_cast<OQueryTableConnection
*>(connection
.get());
498 if(!pNext
->IsVisited() && (pNext
->GetSourceWin() == pEntryTabTo
|| pNext
->GetDestWin() == pEntryTabTo
))
500 OQueryTableWindow
* pEntryTab
= pNext
->GetSourceWin() == pEntryTabTo
? static_cast<OQueryTableWindow
*>(pNext
->GetDestWin()) : static_cast<OQueryTableWindow
*>(pNext
->GetSourceWin());
501 // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
502 JoinCycle(_xConnection
,pNext
,pEntryTab
,aJoin
);
503 if(!pNext
->IsVisited())
504 GetNextJoin(_xConnection
, pNext
, pEntryTab
, aJoin
, _rTableNames
);
509 // when nothing found look for the "from" window
513 OQueryTableWindow
* pEntryTabFrom
= static_cast<OQueryTableWindow
*>(pEntryConn
->GetSourceWin());
514 for (auto const& connection
: rConnections
)
516 OQueryTableConnection
* pNext
= static_cast<OQueryTableConnection
*>(connection
.get());
517 if(!pNext
->IsVisited() && (pNext
->GetSourceWin() == pEntryTabFrom
|| pNext
->GetDestWin() == pEntryTabFrom
))
519 OQueryTableWindow
* pEntryTab
= pNext
->GetSourceWin() == pEntryTabFrom
? 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 SqlParseError
InsertJoinConnection( const OQueryDesignView
* _pView
,
528 const ::connectivity::OSQLParseNode
*pNode
,
529 const EJoinType
& _eJoinType
,
530 const ::connectivity::OSQLParseNode
*pLeftTable
,
531 const ::connectivity::OSQLParseNode
*pRightTable
)
533 SqlParseError eErrorCode
= eOk
;
534 if (pNode
->count() == 3 && // statement between brackets
535 SQL_ISPUNCTUATION(pNode
->getChild(0),"(") &&
536 SQL_ISPUNCTUATION(pNode
->getChild(2),")"))
538 eErrorCode
= InsertJoinConnection(_pView
,pNode
->getChild(1), _eJoinType
,pLeftTable
,pRightTable
);
540 else if (SQL_ISRULEOR2(pNode
,search_condition
,boolean_term
) && // AND/OR-joints:
543 // only allow AND joints
544 if (!SQL_ISTOKEN(pNode
->getChild(1),AND
))
545 eErrorCode
= eIllegalJoinCondition
;
546 else if ( eOk
== (eErrorCode
= InsertJoinConnection(_pView
,pNode
->getChild(0), _eJoinType
,pLeftTable
,pRightTable
)) )
547 eErrorCode
= InsertJoinConnection(_pView
,pNode
->getChild(2), _eJoinType
,pLeftTable
,pRightTable
);
549 else if (SQL_ISRULE(pNode
,comparison_predicate
))
551 // only the comparison of columns is allowed
552 OSL_ENSURE(pNode
->count() == 3,"OQueryDesignView::InsertJoinConnection: Error in Parse Tree");
553 if (!(SQL_ISRULE(pNode
->getChild(0),column_ref
) &&
554 SQL_ISRULE(pNode
->getChild(2),column_ref
) &&
555 pNode
->getChild(1)->getNodeType() == SQLNodeType::Equal
))
557 OUString
sError(DBA_RES(STR_QRY_JOIN_COLUMN_COMPARE
));
558 _pView
->getController().appendError( sError
);
562 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
563 OTableFieldDescRef aDragRight
= new OTableFieldDesc();
564 eErrorCode
= FillDragInfo(_pView
,pNode
->getChild(0),aDragLeft
);
565 if ( eOk
!= eErrorCode
)
567 eErrorCode
= FillDragInfo(_pView
,pNode
->getChild(2),aDragRight
);
568 if ( eOk
!= eErrorCode
)
573 OQueryTableWindow
* pLeftWindow
= static_cast<OQueryTableView
*>(_pView
->getTableView())->FindTable( getTableRange(_pView
,pLeftTable
->getByRule(OSQLParseNode::table_ref
) ));
574 if ( pLeftWindow
== aDragLeft
->GetTabWindow() )
575 insertConnection(_pView
,_eJoinType
,aDragLeft
,aDragRight
);
577 insertConnection(_pView
,_eJoinType
,aDragRight
,aDragLeft
);
580 insertConnection(_pView
,_eJoinType
,aDragLeft
,aDragRight
);
583 eErrorCode
= eIllegalJoin
;
586 bool GetInnerJoinCriteria( const OQueryDesignView
* _pView
,
587 const ::connectivity::OSQLParseNode
*pCondition
)
589 return InsertJoinConnection(_pView
,pCondition
, INNER_JOIN
,nullptr,nullptr) != eOk
;
591 OUString
GenerateSelectList( const OQueryDesignView
* _pView
,
592 OTableFields
& _rFieldList
,
595 Reference
< XConnection
> xConnection
= static_cast<OQueryController
&>(_pView
->getController()).getConnection();
596 if ( !xConnection
.is() )
599 OUStringBuffer aTmpStr
,aFieldListStr
;
601 bool bAsterisk
= false;
603 for (auto const& field
: _rFieldList
)
605 if ( field
->IsVisible() )
607 if ( field
->GetField().toChar() == '*' )
617 const Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
618 const OUString aQuote
= xMetaData
->getIdentifierQuoteString();
620 OJoinTableView::OTableWindowMap
& rTabList
= _pView
->getTableView()->GetTabWinMap();
622 for (auto const& field
: _rFieldList
)
624 OUString rFieldName
= field
->GetField();
625 if ( !rFieldName
.isEmpty() && field
->IsVisible() )
628 const OUString rAlias
= field
->GetAlias();
629 const OUString rFieldAlias
= field
->GetFieldAlias();
631 aTmpStr
.append(quoteTableAlias((bAlias
|| bAsterisk
),rAlias
,aQuote
));
633 // if we have a none numeric field, the table alias could be in the name
634 // otherwise we are not allowed to do this (e.g. 0.1 * PRICE )
635 if ( !field
->isOtherFunction() )
637 // we have to look if we have alias.* here but before we have to check if the column doesn't already exist
638 OTableFieldDescRef aInfo
= new OTableFieldDesc();
639 for (auto const& table
: rTabList
)
641 OQueryTableWindow
* pTabWin
= static_cast<OQueryTableWindow
*>(table
.second
.get());
643 if ( pTabWin
->ExistsField( rFieldName
, aInfo
) )
645 rFieldName
= aInfo
->GetField();
649 if ( ( rFieldName
.toChar() != '*' ) && ( rFieldName
.indexOf( aQuote
) == -1 ) )
651 OSL_ENSURE(!field
->GetTable().isEmpty(),"No table field name!");
652 aTmpStr
.append(::dbtools::quoteName(aQuote
, rFieldName
));
655 aTmpStr
.append(rFieldName
);
658 aTmpStr
.append(rFieldName
);
660 if ( field
->isAggregateFunction() )
662 OSL_ENSURE(!field
->GetFunction().isEmpty(),"Function name must not be empty! ;-(");
663 OUStringBuffer
aTmpStr2( field
->GetFunction() + "(" + aTmpStr
+ ")");
667 if (!rFieldAlias
.isEmpty() &&
668 (rFieldName
.toChar() != '*' ||
669 field
->isNumericOrAggregateFunction() ||
670 field
->isOtherFunction()))
672 aTmpStr
.append(" AS " + ::dbtools::quoteName(aQuote
, rFieldAlias
));
674 aFieldListStr
.append(aTmpStr
);
675 aTmpStr
.setLength(0);
676 aFieldListStr
.append(", ");
679 if(!aFieldListStr
.isEmpty())
680 aFieldListStr
.setLength(aFieldListStr
.getLength()-2);
684 OSL_FAIL("Failure while building select list!");
686 return aFieldListStr
.makeStringAndClear();
688 bool GenerateCriterias( OQueryDesignView
const * _pView
,
689 OUStringBuffer
& rRetStr
,
690 OUStringBuffer
& rHavingStr
,
691 OTableFields
& _rFieldList
,
694 Reference
< XConnection
> xConnection
= static_cast<OQueryController
&>(_pView
->getController()).getConnection();
695 if(!xConnection
.is())
698 OUString aFieldName
,aCriteria
,aWhereStr
,aHavingStr
,aWork
/*,aOrderStr*/;
699 // print line by line joined with AND
700 sal_uInt16 nMaxCriteria
= 0;
701 for (auto const& field
: _rFieldList
)
703 nMaxCriteria
= std::max
<sal_uInt16
>(nMaxCriteria
,static_cast<sal_uInt16
>(field
->GetCriteria().size()));
707 const Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
708 const OUString aQuote
= xMetaData
->getIdentifierQuoteString();
709 const IParseContext
& rContext
= static_cast<OQueryController
&>(_pView
->getController()).getParser().getContext();
710 // * must not contain a filter : have I already shown the correct warning ?
711 bool bCritsOnAsteriskWarning
= false; // ** TMFS **
713 for (sal_uInt16 i
=0 ; i
< nMaxCriteria
; i
++)
718 for (auto const& field
: _rFieldList
)
720 aFieldName
= field
->GetField();
722 if (aFieldName
.isEmpty())
724 aCriteria
= field
->GetCriteria( i
);
725 if ( !aCriteria
.isEmpty() )
727 // * is not allowed to contain any filter, only when used in combination an aggregate function
728 if ( aFieldName
.toChar() == '*' && field
->isNoneFunction() )
730 // only show the messagebox the first time
731 if (!bCritsOnAsteriskWarning
)
733 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(_pView
->GetFrameWeld(),
734 VclMessageType::Warning
, VclButtonsType::Ok
,
735 DBA_RES(STR_QRY_CRITERIA_ON_ASTERISK
)));
738 bCritsOnAsteriskWarning
= true;
741 aWork
= quoteTableAlias(bMulti
,field
->GetAlias(),aQuote
);
743 if ( (field
->GetFunctionType() & (FKT_OTHER
|FKT_NUMERIC
)) || (aFieldName
.toChar() == '*') )
746 aWork
+= ::dbtools::quoteName(aQuote
, aFieldName
);
748 if ( field
->isAggregateFunction() || field
->IsGroupBy() )
750 if (aHavingStr
.isEmpty()) // no more criteria
751 aHavingStr
+= "("; // bracket
755 if ( field
->isAggregateFunction() )
757 OSL_ENSURE(!field
->GetFunction().isEmpty(),"No function name for aggregate given!");
758 aHavingStr
+= field
->GetFunction() + "(" + aWork
+ ")"; // bracket
764 Reference
<XPropertySet
> xColumn
;
765 std::unique_ptr
< ::connectivity::OSQLParseNode
> pParseNode(_pView
->getPredicateTreeFromEntry(field
,aCriteria
,aErrorMsg
,xColumn
));
768 if (bMulti
&& !(field
->isOtherFunction() || (aFieldName
.toChar() == '*')))
769 pParseNode
->replaceNodeValue(field
->GetAlias(),aFieldName
);
770 OUString sHavingStr
= aHavingStr
;
772 sal_uInt32 nCount
= pParseNode
->count();
773 for( sal_uInt32 node
= 1 ; node
< nCount
; ++node
)
774 pParseNode
->getChild(node
)->parseNodeToStr( sHavingStr
,
778 !field
->isOtherFunction());
779 aHavingStr
= sHavingStr
;
782 aHavingStr
+= aCriteria
;
786 if ( aWhereStr
.isEmpty() ) // no more criteria
787 aWhereStr
+= "("; // bracket
792 // aCriteria could have some German numbers so I have to be sure here
794 Reference
<XPropertySet
> xColumn
;
795 std::unique_ptr
< ::connectivity::OSQLParseNode
> pParseNode( _pView
->getPredicateTreeFromEntry(field
,aCriteria
,aErrorMsg
,xColumn
));
798 if (bMulti
&& !(field
->isOtherFunction() || (aFieldName
.toChar() == '*')))
799 pParseNode
->replaceNodeValue(field
->GetAlias(),aFieldName
);
800 OUString aWhere
= aWhereStr
;
801 pParseNode
->parseNodeToStr( aWhere
,
805 !field
->isOtherFunction() );
810 aWhereStr
+= aWork
+ "=" + aCriteria
;
814 // only once for each field
815 else if ( !i
&& field
->isCondition() )
817 if (aWhereStr
.isEmpty()) // no more criteria
818 aWhereStr
+= "("; // bracket
821 aWhereStr
+= field
->GetField();
824 if (!aWhereStr
.isEmpty())
826 aWhereStr
+= ")"; // close bracket for the AND branch
827 if (!rRetStr
.isEmpty()) // are there conditions on the field?
828 rRetStr
.append(C_OR
);
829 else // open bracket for the OR branch
831 rRetStr
.append(aWhereStr
);
833 if (!aHavingStr
.isEmpty())
835 aHavingStr
+= ")"; // close bracket for the AND branch
836 if (!rHavingStr
.isEmpty()) // are there conditions on the field?
837 rHavingStr
.append(C_OR
);
838 else // Open bracket for the OR branch
839 rHavingStr
.append('(');
840 rHavingStr
.append(aHavingStr
);
844 if (!rRetStr
.isEmpty())
845 rRetStr
.append(')'); // close bracket for the OR branch
846 if (!rHavingStr
.isEmpty())
847 rHavingStr
.append(')'); // close bracket for the OR branch
851 OSL_FAIL("Failure while building where clause!");
855 SqlParseError
GenerateOrder( OQueryDesignView
const * _pView
,
856 OTableFields
& _rFieldList
,
860 const OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
861 const Reference
< XConnection
>& xConnection
= rController
.getConnection();
862 if ( !xConnection
.is() )
863 return eNoConnection
;
865 SqlParseError eErrorCode
= eOk
;
867 OUString aColumnName
;
871 const bool bColumnAliasInOrderBy
= rController
.getSdbMetaData().supportsColumnAliasInOrderBy();
872 Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
873 OUString aQuote
= xMetaData
->getIdentifierQuoteString();
874 // * must not contain filter - have I already shown the warning?
875 bool bCritsOnAsteriskWarning
= false; // ** TMFS **
876 for (auto const& field
: _rFieldList
)
878 EOrderDir eOrder
= field
->GetOrderDir();
879 // only create a sort expression when the table name and the sort criteria are defined
880 // otherwise they will be built in GenerateCriteria
881 if ( eOrder
!= ORDER_NONE
)
883 aColumnName
= field
->GetField();
884 if(aColumnName
.toChar() == '*')
886 // only show the MessageBox the first time
887 if (!bCritsOnAsteriskWarning
)
889 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(_pView
->GetFrameWeld(),
890 VclMessageType::Warning
, VclButtonsType::Ok
,
891 DBA_RES(STR_QRY_ORDERBY_ON_ASTERISK
)));
894 bCritsOnAsteriskWarning
= true;
898 if ( bColumnAliasInOrderBy
&& !field
->GetFieldAlias().isEmpty() )
900 aWorkStr
+= ::dbtools::quoteName(aQuote
, field
->GetFieldAlias());
902 else if ( field
->isNumericOrAggregateFunction() )
904 OSL_ENSURE(!field
->GetFunction().isEmpty(),"Function name cannot be empty! ;-(");
905 aWorkStr
+= field
->GetFunction() + "("
907 bMulti
, field
->GetAlias(), aQuote
);
908 // only quote column name when we don't have a numeric
909 if ( field
->isNumeric() )
910 aWorkStr
+= aColumnName
;
912 aWorkStr
+= ::dbtools::quoteName(aQuote
, aColumnName
);
916 else if ( field
->isOtherFunction() )
918 aWorkStr
+= aColumnName
;
922 aWorkStr
+= quoteTableAlias(bMulti
,field
->GetAlias(),aQuote
) + ::dbtools::quoteName(aQuote
, aColumnName
);
924 aWorkStr
+= OUString::Concat(" ") + o3tl::getToken( u
";ASC;DESC", static_cast<sal_uInt16
>(eOrder
), ';' ) + ",";
929 OUString
sTemp(comphelper::string::stripEnd(aWorkStr
, ','));
933 if ( !aWorkStr
.isEmpty() )
935 const sal_Int32 nMaxOrder
= xMetaData
->getMaxColumnsInOrderBy();
936 if ( nMaxOrder
&& nMaxOrder
< comphelper::string::getTokenCount(aWorkStr
, ',') )
937 eErrorCode
= eStatementTooLong
;
940 _rsRet
= " ORDER BY " + aWorkStr
;
946 OSL_FAIL("Failure while building group by!");
952 void GenerateInnerJoinCriterias(const Reference
< XConnection
>& _xConnection
,
953 OUString
& _rJoinCrit
,
954 const std::vector
<VclPtr
<OTableConnection
> >& _rConnList
)
956 for (auto const& connection
: _rConnList
)
958 const OQueryTableConnection
* pEntryConn
= static_cast<const OQueryTableConnection
*>(connection
.get());
959 OQueryTableConnectionData
* pEntryConnData
= static_cast<OQueryTableConnectionData
*>(pEntryConn
->GetData().get());
960 if ( pEntryConnData
->GetJoinType() == INNER_JOIN
&& !pEntryConnData
->isNatural() )
962 if(!_rJoinCrit
.isEmpty())
964 _rJoinCrit
+= BuildJoinCriteria(_xConnection
,&pEntryConnData
->GetConnLineDataList(),pEntryConnData
);
968 void searchAndAppendName(const Reference
< XConnection
>& _xConnection
,
969 const OQueryTableWindow
* _pTableWindow
,
970 std::set
<OUString
>& _rTableNames
,
971 OUString
& _rsTableListStr
974 OUString
sTabName(BuildTable(_xConnection
,_pTableWindow
));
976 if(_rTableNames
.insert(sTabName
).second
)
978 _rsTableListStr
+= sTabName
+ ",";
981 OUString
GenerateFromClause( const Reference
< XConnection
>& _xConnection
,
982 const OQueryTableView::OTableWindowMap
* pTabList
,
983 const std::vector
<VclPtr
<OTableConnection
> >& rConnList
987 OUString aTableListStr
;
988 // used to avoid putting a table twice in FROM clause
989 std::set
<OUString
> aTableNames
;
991 // generate outer join clause in from
992 if(!rConnList
.empty())
994 std::map
<OTableWindow
*,sal_Int32
> aConnectionCount
;
995 auto aEnd
= rConnList
.end();
996 for (auto const& connection
: rConnList
)
998 static_cast<OQueryTableConnection
*>(connection
.get())->SetVisited(false);
999 ++aConnectionCount
[connection
->GetSourceWin()];
1000 ++aConnectionCount
[connection
->GetDestWin()];
1002 std::multimap
<sal_Int32
, OTableWindow
*> aMulti
;
1003 for (auto const& elem
: aConnectionCount
)
1005 aMulti
.emplace(elem
.second
,elem
.first
);
1008 const bool bUseEscape
= ::dbtools::getBooleanDataSourceSetting( _xConnection
, PROPERTY_OUTERJOINESCAPE
);
1009 std::multimap
<sal_Int32
, OTableWindow
*>::const_reverse_iterator aRIter
= aMulti
.rbegin();
1010 std::multimap
<sal_Int32
, OTableWindow
*>::const_reverse_iterator aREnd
= aMulti
.rend();
1011 for(;aRIter
!= aREnd
;++aRIter
)
1013 auto aConIter
= aRIter
->second
->getTableView()->getTableConnections(aRIter
->second
);
1014 for(;aConIter
!= aEnd
;++aConIter
)
1016 OQueryTableConnection
* pEntryConn
= static_cast<OQueryTableConnection
*>((*aConIter
).get());
1017 if(!pEntryConn
->IsVisited() && pEntryConn
->GetSourceWin() == aRIter
->second
)
1020 GetNextJoin(_xConnection
,
1022 static_cast<OQueryTableWindow
*>(pEntryConn
->GetDestWin()),
1026 if(!aJoin
.isEmpty())
1029 switch(static_cast<OQueryTableConnectionData
*>(pEntryConn
->GetData().get())->GetJoinType())
1035 // create outer join
1048 aTableListStr
+= aStr
;
1054 // and now all inner joins
1055 // these are implemented as
1056 // "FROM tbl1, tbl2 WHERE tbl1.col1=tlb2.col2"
1058 // "FROM tbl1 INNER JOIN tbl2 ON tbl1.col1=tlb2.col2"
1059 for (auto const& connection
: rConnList
)
1061 OQueryTableConnection
* pEntryConn
= static_cast<OQueryTableConnection
*>(connection
.get());
1062 if(!pEntryConn
->IsVisited())
1064 searchAndAppendName(_xConnection
,
1065 static_cast<OQueryTableWindow
*>(pEntryConn
->GetSourceWin()),
1069 searchAndAppendName(_xConnection
,
1070 static_cast<OQueryTableWindow
*>(pEntryConn
->GetDestWin()),
1076 // all tables that haven't a connection to anyone
1077 for (auto const& table
: *pTabList
)
1079 const OQueryTableWindow
* pEntryTab
= static_cast<const OQueryTableWindow
*>(table
.second
.get());
1080 if(!pEntryTab
->ExistsAConn())
1082 aTableListStr
+= BuildTable(_xConnection
,pEntryTab
) + ",";
1086 if(!aTableListStr
.isEmpty())
1087 aTableListStr
= aTableListStr
.replaceAt(aTableListStr
.getLength()-1,1, u
"" );
1088 return aTableListStr
;
1090 OUString
GenerateGroupBy(const OQueryDesignView
* _pView
,OTableFields
& _rFieldList
, bool bMulti
)
1092 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
1093 const Reference
< XConnection
> xConnection
= rController
.getConnection();
1094 if(!xConnection
.is())
1097 std::map
< OUString
,bool> aGroupByNames
;
1099 OUString aGroupByStr
;
1102 const Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
1103 const OUString aQuote
= xMetaData
->getIdentifierQuoteString();
1105 for (auto const& field
: _rFieldList
)
1107 if ( field
->IsGroupBy() )
1109 OSL_ENSURE(!field
->GetField().isEmpty(),"No Field Name available!;-(");
1110 OUString sGroupByPart
= quoteTableAlias(bMulti
,field
->GetAlias(),aQuote
);
1112 // only quote the field name when it isn't calculated
1113 if ( field
->isNoneFunction() )
1115 sGroupByPart
+= ::dbtools::quoteName(aQuote
, field
->GetField());
1119 OUString aTmp
= field
->GetField();
1121 Reference
<XPropertySet
> xColumn
;
1122 std::unique_ptr
< ::connectivity::OSQLParseNode
> pParseNode(_pView
->getPredicateTreeFromEntry(field
,aTmp
,aErrorMsg
,xColumn
));
1126 pParseNode
->getChild(0)->parseNodeToStr( sGroupBy
,
1128 &rController
.getParser().getContext(),
1130 !field
->isOtherFunction());
1131 sGroupByPart
+= sGroupBy
;
1134 sGroupByPart
+= field
->GetField();
1136 if ( aGroupByNames
.find(sGroupByPart
) == aGroupByNames
.end() )
1138 aGroupByNames
.emplace(sGroupByPart
,true);
1139 aGroupByStr
+= sGroupByPart
+ ",";
1143 if ( !aGroupByStr
.isEmpty() )
1145 aGroupByStr
= aGroupByStr
.replaceAt(aGroupByStr
.getLength()-1,1, u
" " );
1146 OUString aGroupByStr2
= " GROUP BY " + aGroupByStr
;
1147 aGroupByStr
= aGroupByStr2
;
1150 catch(SQLException
&)
1152 OSL_FAIL("Failure while building group by!");
1156 SqlParseError
GetORCriteria(OQueryDesignView
* _pView
,
1157 OSelectionBrowseBox
* _pSelectionBrw
,
1158 const ::connectivity::OSQLParseNode
* pCondition
,
1159 sal_uInt16
& nLevel
,
1160 bool bHaving
= false,
1161 bool bAddOrOnOneLine
= false);
1162 SqlParseError
GetSelectionCriteria( OQueryDesignView
* _pView
,
1163 OSelectionBrowseBox
* _pSelectionBrw
,
1164 const ::connectivity::OSQLParseNode
* pNode
,
1165 sal_uInt16
& rLevel
)
1167 if (!pNode
|| !SQL_ISRULE(pNode
, select_statement
))
1168 return eNoSelectStatement
;
1170 // nyi: more checking for the correct structure!
1171 pNode
= pNode
->getChild(3)->getChild(1);
1172 // no where clause found
1173 if (!pNode
|| pNode
->isLeaf())
1176 // Next free sentence...
1177 SqlParseError eErrorCode
= eOk
;
1178 ::connectivity::OSQLParseNode
* pCondition
= pNode
->getChild(1);
1179 if ( pCondition
) // no where clause
1181 // now we have to check the other conditions
1182 // first make the logical easier
1183 ::connectivity::OSQLParseNode::negateSearchCondition(pCondition
);
1184 ::connectivity::OSQLParseNode
*pNodeTmp
= pNode
->getChild(1);
1186 ::connectivity::OSQLParseNode::disjunctiveNormalForm(pNodeTmp
);
1187 pNodeTmp
= pNode
->getChild(1);
1188 ::connectivity::OSQLParseNode::absorptions(pNodeTmp
);
1189 pNodeTmp
= pNode
->getChild(1);
1190 // compress sort the criteria @see https://bz.apache.org/ooo/show_bug.cgi?id=24079
1191 OSQLParseNode::compress(pNodeTmp
);
1192 pNodeTmp
= pNode
->getChild(1);
1194 // first extract the inner joins conditions
1195 GetInnerJoinCriteria(_pView
,pNodeTmp
);
1196 // now simplify again, join are checked in ComparisonPredicate
1197 ::connectivity::OSQLParseNode::absorptions(pNodeTmp
);
1198 pNodeTmp
= pNode
->getChild(1);
1200 // it could happen that pCondition is not more valid
1201 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pNodeTmp
, rLevel
);
1205 SqlParseError
GetANDCriteria( OQueryDesignView
* _pView
,
1206 OSelectionBrowseBox
* _pSelectionBrw
,
1207 const ::connectivity::OSQLParseNode
* pCondition
,
1210 bool bAddOrOnOneLine
);
1211 SqlParseError
ComparisonPredicate(OQueryDesignView
const * _pView
,
1212 OSelectionBrowseBox
* _pSelectionBrw
,
1213 const ::connectivity::OSQLParseNode
* pCondition
,
1214 const sal_uInt16 nLevel
,
1216 bool bAddOrOnOneLine
);
1217 SqlParseError
GetORCriteria(OQueryDesignView
* _pView
,
1218 OSelectionBrowseBox
* _pSelectionBrw
,
1219 const ::connectivity::OSQLParseNode
* pCondition
,
1220 sal_uInt16
& nLevel
,
1222 bool bAddOrOnOneLine
)
1224 SqlParseError eErrorCode
= eOk
;
1226 // round brackets around the printout
1227 if (pCondition
->count() == 3 &&
1228 SQL_ISPUNCTUATION(pCondition
->getChild(0),"(") &&
1229 SQL_ISPUNCTUATION(pCondition
->getChild(2),")"))
1231 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pCondition
->getChild(1),nLevel
,bHaving
,bAddOrOnOneLine
);
1234 // a searchcondition can only look like this: search_condition SQL_TOKEN_OR boolean_term
1235 else if (SQL_ISRULE(pCondition
,search_condition
))
1237 for (int i
= 0; i
< 3 && eErrorCode
== eOk
; i
+=2)
1239 const ::connectivity::OSQLParseNode
* pChild
= pCondition
->getChild(i
);
1240 if ( SQL_ISRULE(pChild
,search_condition
) )
1241 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pChild
,nLevel
,bHaving
,bAddOrOnOneLine
);
1244 eErrorCode
= GetANDCriteria(_pView
,_pSelectionBrw
,pChild
, nLevel
,bHaving
, i
!= 0 && bAddOrOnOneLine
);
1245 if ( !bAddOrOnOneLine
)
1251 eErrorCode
= GetANDCriteria( _pView
,_pSelectionBrw
,pCondition
, nLevel
, bHaving
,bAddOrOnOneLine
);
1255 bool CheckOrCriteria(const ::connectivity::OSQLParseNode
* _pCondition
,::connectivity::OSQLParseNode
* _pFirstColumnRef
)
1258 ::connectivity::OSQLParseNode
* pFirstColumnRef
= _pFirstColumnRef
;
1259 for (size_t i
= 0; bRet
&& i
< _pCondition
->count(); ++i
)
1261 const ::connectivity::OSQLParseNode
* pChild
= _pCondition
->getChild(i
);
1262 if ( pChild
->isToken() )
1264 else if ( SQL_ISRULE(pChild
,search_condition
) )
1265 bRet
= CheckOrCriteria(pChild
,pFirstColumnRef
);
1268 // this is a simple way to test columns are the same, may be we have to adjust this algo a little bit in future. :-)
1269 ::connectivity::OSQLParseNode
* pSecondColumnRef
= pChild
->getByRule(::connectivity::OSQLParseNode::column_ref
);
1270 if ( pFirstColumnRef
&& pSecondColumnRef
)
1271 bRet
= *pFirstColumnRef
== *pSecondColumnRef
;
1272 else if ( !pFirstColumnRef
)
1273 pFirstColumnRef
= pSecondColumnRef
;
1278 SqlParseError
GetANDCriteria( OQueryDesignView
* _pView
,
1279 OSelectionBrowseBox
* _pSelectionBrw
,
1280 const ::connectivity::OSQLParseNode
* pCondition
,
1283 bool bAddOrOnOneLine
)
1285 const css::lang::Locale aLocale
= _pView
->getLocale();
1286 const OUString sDecimal
= _pView
->getDecimalSeparator();
1288 // I will need a cast pointer to my css::sdbcx::Container
1289 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
1290 SqlParseError eErrorCode
= eOk
;
1293 if (SQL_ISRULE(pCondition
,boolean_primary
))
1295 // check if we have to put the or criteria on one line.
1296 const ::connectivity::OSQLParseNode
* pSearchCondition
= pCondition
->getChild(1);
1297 bool bMustAddOrOnOneLine
= CheckOrCriteria(pSearchCondition
,nullptr);
1298 if ( SQL_ISRULE( pSearchCondition
, search_condition
) ) // we have a or
1300 _pSelectionBrw
->DuplicateConditionLevel( nLevel
);
1301 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pSearchCondition
->getChild(0), nLevel
,bHaving
,bMustAddOrOnOneLine
);
1302 if ( eErrorCode
== eOk
)
1305 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pSearchCondition
->getChild(2), nLevel
,bHaving
,bMustAddOrOnOneLine
);
1309 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pSearchCondition
, nLevel
,bHaving
,bMustAddOrOnOneLine
);
1311 // The first element is (again) an AND condition
1312 else if ( SQL_ISRULE(pCondition
,boolean_term
) )
1314 OSL_ENSURE(pCondition
->count() == 3,"Illegal definition of boolean_term");
1315 eErrorCode
= GetANDCriteria(_pView
,_pSelectionBrw
,pCondition
->getChild(0), nLevel
,bHaving
,bAddOrOnOneLine
);
1316 if ( eErrorCode
== eOk
)
1317 eErrorCode
= GetANDCriteria(_pView
,_pSelectionBrw
,pCondition
->getChild(2), nLevel
,bHaving
,bAddOrOnOneLine
);
1319 else if (SQL_ISRULE( pCondition
, comparison_predicate
))
1321 eErrorCode
= ComparisonPredicate(_pView
,_pSelectionBrw
,pCondition
,nLevel
,bHaving
,bAddOrOnOneLine
);
1323 else if( SQL_ISRULE(pCondition
,like_predicate
) )
1325 const ::connectivity::OSQLParseNode
* pValueExp
= pCondition
->getChild(0);
1326 if (SQL_ISRULE(pValueExp
, column_ref
) )
1328 OUString aCondition
;
1329 Reference
< XConnection
> xConnection
= rController
.getConnection();
1330 if ( xConnection
.is() )
1332 OUString aColumnName
;
1333 // the international doesn't matter I have a string
1334 pCondition
->parseNodeToPredicateStr(aCondition
,
1336 rController
.getNumberFormatter(),
1339 &rController
.getParser().getContext());
1341 pValueExp
->parseNodeToPredicateStr( aColumnName
,
1343 rController
.getNumberFormatter(),
1346 &rController
.getParser().getContext());
1348 // don't display the column name
1349 aCondition
= aCondition
.copy(aColumnName
.getLength());
1350 aCondition
= aCondition
.trim();
1353 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1354 if ( eOk
== ( eErrorCode
= FillDragInfo(_pView
,pValueExp
,aDragLeft
) ))
1357 aDragLeft
->SetGroupBy(true);
1358 _pSelectionBrw
->AddCondition(aDragLeft
, aCondition
, nLevel
,bAddOrOnOneLine
);
1361 else if(SQL_ISRULEOR3(pValueExp
, general_set_fct
, set_fct_spec
, position_exp
) ||
1362 SQL_ISRULEOR3(pValueExp
, extract_exp
, fold
, char_substring_fct
) ||
1363 SQL_ISRULEOR2(pValueExp
, length_exp
, char_value_fct
))
1365 AddFunctionCondition( _pView
,
1374 eErrorCode
= eNoColumnInLike
;
1375 OUString
sError(DBA_RES(STR_QRY_LIKE_LEFT_NO_COLUMN
));
1376 _pView
->getController().appendError( sError
);
1379 else if( SQL_ISRULEOR2(pCondition
,test_for_null
,in_predicate
)
1380 || SQL_ISRULEOR2(pCondition
,all_or_any_predicate
,between_predicate
))
1382 if ( SQL_ISRULEOR2(pCondition
->getChild(0), set_fct_spec
, general_set_fct
) )
1384 AddFunctionCondition( _pView
,
1391 else if ( SQL_ISRULE(pCondition
->getChild(0), column_ref
) )
1394 OUString sCondition
= ParseCondition(rController
,pCondition
,sDecimal
,aLocale
,1);
1395 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1396 if ( eOk
== ( eErrorCode
= FillDragInfo(_pView
,pCondition
->getChild(0),aDragLeft
)) )
1399 aDragLeft
->SetGroupBy(true);
1400 _pSelectionBrw
->AddCondition(aDragLeft
, sCondition
, nLevel
,bAddOrOnOneLine
);
1405 // Parse the function condition
1406 OUString sCondition
= ParseCondition(rController
,pCondition
,sDecimal
,aLocale
,1);
1407 Reference
< XConnection
> xConnection
= rController
.getConnection();
1408 // the international doesn't matter I have a string
1410 pCondition
->getChild(0)->parseNodeToPredicateStr(sName
,
1412 rController
.getNumberFormatter(),
1415 &rController
.getParser().getContext());
1417 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1418 aDragLeft
->SetField(sName
);
1419 aDragLeft
->SetFunctionType(FKT_OTHER
);
1422 aDragLeft
->SetGroupBy(true);
1423 _pSelectionBrw
->AddCondition(aDragLeft
, sCondition
, nLevel
,bAddOrOnOneLine
);
1426 else if( SQL_ISRULEOR2(pCondition
,existence_test
,unique_test
) )
1428 // Parse the function condition
1429 OUString aCondition
= ParseCondition(rController
,pCondition
,sDecimal
,aLocale
,0);
1431 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1432 aDragLeft
->SetField(aCondition
);
1433 aDragLeft
->SetFunctionType(FKT_CONDITION
);
1435 eErrorCode
= _pSelectionBrw
->InsertField(aDragLeft
,BROWSER_INVALIDID
,false).is() ? eOk
: eTooManyColumns
;
1437 else //! TODO not supported yet
1438 eErrorCode
= eStatementTooComplex
;
1439 // Pass on the error code
1442 SqlParseError
AddFunctionCondition(OQueryDesignView
const * _pView
,
1443 OSelectionBrowseBox
* _pSelectionBrw
,
1444 const ::connectivity::OSQLParseNode
* pCondition
,
1445 const sal_uInt16 nLevel
,
1447 bool bAddOrOnOneLine
)
1449 SqlParseError eErrorCode
= eOk
;
1450 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
1452 OSQLParseNode
* pFunction
= pCondition
->getChild(0);
1454 OSL_ENSURE(SQL_ISRULEOR3(pFunction
, general_set_fct
, set_fct_spec
, position_exp
) ||
1455 SQL_ISRULEOR3(pFunction
, extract_exp
, fold
, char_substring_fct
) ||
1456 SQL_ISRULEOR2(pFunction
,length_exp
,char_value_fct
),
1459 Reference
< XConnection
> xConnection
= rController
.getConnection();
1460 if(xConnection
.is())
1462 OUString aCondition
;
1463 OUString aColumnName
;
1464 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1465 pCondition
->parseNodeToPredicateStr(aCondition
,
1467 rController
.getNumberFormatter(),
1468 _pView
->getLocale(),
1469 _pView
->getDecimalSeparator(),
1470 &rController
.getParser().getContext());
1472 pFunction
->parseNodeToStr( aColumnName
,
1474 &rController
.getParser().getContext(),
1475 true); // quote is to true because we need quoted elements inside the function
1476 // don't display the column name
1477 aCondition
= aCondition
.copy(aColumnName
.getLength());
1478 aCondition
= aCondition
.trim();
1479 if ( aCondition
.startsWith("=") ) // ignore the equal sign
1480 aCondition
= aCondition
.copy(1);
1482 if ( SQL_ISRULE(pFunction
, general_set_fct
) )
1484 sal_Int32 nFunctionType
= FKT_AGGREGATE
;
1485 OSQLParseNode
* pParamNode
= pFunction
->getChild(pFunction
->count()-2);
1486 if ( pParamNode
&& pParamNode
->getTokenValue().toChar() == '*' )
1488 OJoinTableView::OTableWindowMap
& rTabList
= _pView
->getTableView()->GetTabWinMap();
1489 for (auto const& table
: rTabList
)
1491 OQueryTableWindow
* pTabWin
= static_cast<OQueryTableWindow
*>(table
.second
.get());
1492 if (pTabWin
->ExistsField( "*", aDragLeft
))
1494 aDragLeft
->SetAlias(OUString());
1495 aDragLeft
->SetTable(OUString());
1500 else if (pParamNode
)
1502 eErrorCode
= FillDragInfo(_pView
,pParamNode
,aDragLeft
);
1503 if ( eOk
!= eErrorCode
&& SQL_ISRULE(pParamNode
,num_value_exp
))
1505 OUString sParameterValue
;
1506 pParamNode
->parseNodeToStr( sParameterValue
,
1508 &rController
.getParser().getContext());
1509 nFunctionType
|= FKT_NUMERIC
;
1510 aDragLeft
->SetField(sParameterValue
);
1514 aDragLeft
->SetFunctionType(nFunctionType
);
1516 aDragLeft
->SetGroupBy(true);
1517 aDragLeft
->SetFunction(aColumnName
.getToken(0, '('));
1521 // for an unknown function we write the whole text in the field
1522 aDragLeft
->SetField(aColumnName
);
1524 aDragLeft
->SetGroupBy(true);
1525 aDragLeft
->SetFunctionType(FKT_OTHER
|FKT_NUMERIC
);
1527 _pSelectionBrw
->AddCondition(aDragLeft
, aCondition
, nLevel
,bAddOrOnOneLine
);
1532 SqlParseError
ComparisonPredicate(OQueryDesignView
const * _pView
,
1533 OSelectionBrowseBox
* _pSelectionBrw
,
1534 const ::connectivity::OSQLParseNode
* pCondition
,
1535 const sal_uInt16 nLevel
,
1537 ,bool bAddOrOnOneLine
)
1539 SqlParseError eErrorCode
= eOk
;
1540 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
1542 OSL_ENSURE(SQL_ISRULE( pCondition
, comparison_predicate
),"ComparisonPredicate: pCondition is not a Comparison Predicate");
1543 if ( SQL_ISRULE(pCondition
->getChild(0), column_ref
)
1544 || SQL_ISRULE(pCondition
->getChild(pCondition
->count()-1), column_ref
) )
1546 OUString aCondition
;
1547 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1549 if ( SQL_ISRULE(pCondition
->getChild(0), column_ref
) && SQL_ISRULE(pCondition
->getChild(pCondition
->count()-1), column_ref
) )
1551 OTableFieldDescRef aDragRight
= new OTableFieldDesc();
1552 eErrorCode
= FillDragInfo(_pView
,pCondition
->getChild(0),aDragLeft
);
1553 if (eOk
!= eErrorCode
)
1555 eErrorCode
= FillDragInfo(_pView
,pCondition
->getChild(2),aDragRight
);
1556 if (eOk
!= eErrorCode
)
1559 OQueryTableConnection
* pConn
= static_cast<OQueryTableConnection
*>(
1560 _pView
->getTableView()->GetTabConn(static_cast<OQueryTableWindow
*>(aDragLeft
->GetTabWindow()),
1561 static_cast<OQueryTableWindow
*>(aDragRight
->GetTabWindow()),
1565 OConnectionLineDataVec
& rLineDataList
= pConn
->GetData()->GetConnLineDataList();
1566 for (auto const& lineData
: rLineDataList
)
1568 if(lineData
->GetSourceFieldName() == aDragLeft
->GetField() ||
1569 lineData
->GetDestFieldName() == aDragLeft
->GetField() )
1575 sal_uInt32 nPos
= 0;
1576 if(SQL_ISRULE(pCondition
->getChild(0), column_ref
))
1581 // don't display the equal
1582 if (pCondition
->getChild(i
)->getNodeType() == SQLNodeType::Equal
)
1585 // parse the condition
1586 aCondition
= ParseCondition(rController
1588 ,_pView
->getDecimalSeparator()
1589 ,_pView
->getLocale()
1592 else if( SQL_ISRULE(pCondition
->getChild(pCondition
->count()-1), column_ref
) )
1594 nPos
= pCondition
->count()-1;
1596 sal_Int32 i
= static_cast<sal_Int32
>(pCondition
->count() - 2);
1597 switch (pCondition
->getChild(i
)->getNodeType())
1599 case SQLNodeType::Equal
:
1600 // don't display the equal
1603 case SQLNodeType::Less
:
1604 // take the opposite as we change the order
1608 case SQLNodeType::LessEq
:
1609 // take the opposite as we change the order
1613 case SQLNodeType::Great
:
1614 // take the opposite as we change the order
1618 case SQLNodeType::GreatEq
:
1619 // take the opposite as we change the order
1628 Reference
< XConnection
> xConnection
= rController
.getConnection();
1629 if(xConnection
.is())
1632 pCondition
->getChild(i
)->parseNodeToPredicateStr(aCondition
,
1634 rController
.getNumberFormatter(),
1635 _pView
->getLocale(),
1636 _pView
->getDecimalSeparator(),
1637 &rController
.getParser().getContext());
1642 if( eOk
== ( eErrorCode
= FillDragInfo(_pView
,pCondition
->getChild(nPos
),aDragLeft
)))
1645 aDragLeft
->SetGroupBy(true);
1646 _pSelectionBrw
->AddCondition(aDragLeft
, aCondition
, nLevel
,bAddOrOnOneLine
);
1649 else if( SQL_ISRULEOR2(pCondition
->getChild(0), set_fct_spec
, general_set_fct
) )
1651 AddFunctionCondition( _pView
,
1658 else // it can only be an Expr
1660 OUString aName
,aCondition
;
1663 Reference
< XConnection
> xConnection
= rController
.getConnection();
1664 if(xConnection
.is())
1666 ::connectivity::OSQLParseNode
*pLhs
= pCondition
->getChild(0);
1667 ::connectivity::OSQLParseNode
*pRhs
= pCondition
->getChild(2);
1668 pLhs
->parseNodeToStr(aName
,
1670 &rController
.getParser().getContext(),
1673 aCondition
= pCondition
->getChild(1)->getTokenValue();
1674 pRhs
->parseNodeToPredicateStr(aCondition
,
1676 rController
.getNumberFormatter(),
1677 _pView
->getLocale(),
1678 _pView
->getDecimalSeparator(),
1679 &rController
.getParser().getContext());
1682 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1683 aDragLeft
->SetField(aName
);
1684 aDragLeft
->SetFunctionType(FKT_OTHER
|FKT_NUMERIC
);
1686 _pSelectionBrw
->AddCondition(aDragLeft
, aCondition
, nLevel
,bAddOrOnOneLine
);
1691 OQueryTableWindow
* lcl_findColumnInTables( const OUString
& _rColumName
, const OJoinTableView::OTableWindowMap
& _rTabList
, OTableFieldDescRef
const & _rInfo
)
1693 for (auto const& table
: _rTabList
)
1695 OQueryTableWindow
* pTabWin
= static_cast< OQueryTableWindow
* >( table
.second
.get() );
1696 if ( pTabWin
&& pTabWin
->ExistsField( _rColumName
, _rInfo
) )
1702 void InsertColumnRef(const OQueryDesignView
* _pView
,
1703 const ::connectivity::OSQLParseNode
* pColumnRef
,
1704 OUString
& aColumnName
,
1705 const OUString
& aColumnAlias
,
1706 OUString
& aTableRange
,
1707 OTableFieldDescRef
const & _raInfo
,
1708 OJoinTableView::OTableWindowMap
const * pTabList
)
1711 // Put the table names together
1712 ::connectivity::OSQLParseTreeIterator
& rParseIter
= static_cast<OQueryController
&>(_pView
->getController()).getParseIterator();
1713 rParseIter
.getColumnRange( pColumnRef
, aColumnName
, aTableRange
);
1716 OSL_ENSURE(!aColumnName
.isEmpty(),"Column name must not be empty");
1717 if (aTableRange
.isEmpty())
1719 // SELECT column, ...
1720 bFound
= nullptr != lcl_findColumnInTables( aColumnName
, *pTabList
, _raInfo
);
1721 if ( bFound
&& ( aColumnName
.toChar() != '*' ) )
1722 _raInfo
->SetFieldAlias(aColumnAlias
);
1726 // SELECT range.column, ...
1727 OQueryTableWindow
* pTabWin
= static_cast<OQueryTableView
*>(_pView
->getTableView())->FindTable(aTableRange
);
1729 if (pTabWin
&& pTabWin
->ExistsField(aColumnName
, _raInfo
))
1731 if(aColumnName
.toChar() != '*')
1732 _raInfo
->SetFieldAlias(aColumnAlias
);
1738 _raInfo
->SetTable(OUString());
1739 _raInfo
->SetAlias(OUString());
1740 _raInfo
->SetField(aColumnName
);
1741 _raInfo
->SetFieldAlias(aColumnAlias
); // nyi : here it continues Expr_1, Expr_2 ...
1742 _raInfo
->SetFunctionType(FKT_OTHER
);
1745 bool checkJoinConditions( const OQueryDesignView
* _pView
,
1746 const ::connectivity::OSQLParseNode
* _pNode
)
1748 const ::connectivity::OSQLParseNode
* pJoinNode
= nullptr;
1750 if (SQL_ISRULE(_pNode
,qualified_join
))
1752 else if (SQL_ISRULE(_pNode
,table_ref
)
1753 && _pNode
->count() == 3
1754 && SQL_ISPUNCTUATION(_pNode
->getChild(0),"(")
1755 && SQL_ISPUNCTUATION(_pNode
->getChild(2),")") ) // '(' joined_table ')'
1756 pJoinNode
= _pNode
->getChild(1);
1757 else if (! ( SQL_ISRULE(_pNode
, table_ref
) && _pNode
->count() == 2) ) // table_node table_primary_as_range_column
1760 if (pJoinNode
&& !InsertJoin(_pView
,pJoinNode
))
1764 bool InsertJoin(const OQueryDesignView
* _pView
,
1765 const ::connectivity::OSQLParseNode
*pNode
)
1767 OSL_ENSURE( SQL_ISRULE( pNode
, qualified_join
) || SQL_ISRULE( pNode
, joined_table
) || SQL_ISRULE( pNode
, cross_union
),
1768 "OQueryDesignView::InsertJoin: Error in the Parse Tree");
1770 if (SQL_ISRULE(pNode
,joined_table
))
1771 return InsertJoin(_pView
,pNode
->getChild(1));
1773 // first check the left and right side
1774 const ::connectivity::OSQLParseNode
* pRightTableRef
= pNode
->getChild(3); // table_ref
1775 if ( SQL_ISRULE(pNode
, qualified_join
) && SQL_ISTOKEN(pNode
->getChild(1),NATURAL
) )
1776 pRightTableRef
= pNode
->getChild(4); // table_ref
1778 if ( !checkJoinConditions(_pView
,pNode
->getChild(0)) || !checkJoinConditions(_pView
,pRightTableRef
))
1781 // named column join may be implemented later
1782 // SQL_ISRULE(pNode->getChild(4),named_columns_join)
1783 EJoinType eJoinType
= INNER_JOIN
;
1784 bool bNatural
= false;
1785 if ( SQL_ISRULE(pNode
, qualified_join
) )
1787 ::connectivity::OSQLParseNode
* pJoinType
= pNode
->getChild(1); // join_type
1788 if ( SQL_ISTOKEN(pJoinType
,NATURAL
) )
1791 pJoinType
= pNode
->getChild(2);
1794 if (SQL_ISRULE(pJoinType
,join_type
) && (!pJoinType
->count() || SQL_ISTOKEN(pJoinType
->getChild(0),INNER
)))
1796 eJoinType
= INNER_JOIN
;
1800 if (SQL_ISRULE(pJoinType
,join_type
)) // one level deeper
1801 pJoinType
= pJoinType
->getChild(0);
1803 if (SQL_ISTOKEN(pJoinType
->getChild(0),LEFT
))
1804 eJoinType
= LEFT_JOIN
;
1805 else if(SQL_ISTOKEN(pJoinType
->getChild(0),RIGHT
))
1806 eJoinType
= RIGHT_JOIN
;
1808 eJoinType
= FULL_JOIN
;
1810 if ( SQL_ISRULE(pNode
->getChild(4),join_condition
) )
1812 if ( InsertJoinConnection(_pView
,pNode
->getChild(4)->getChild(1), eJoinType
,pNode
->getChild(0),pRightTableRef
) != eOk
)
1816 else if ( SQL_ISRULE(pNode
, cross_union
) )
1818 eJoinType
= CROSS_JOIN
;
1819 pRightTableRef
= pNode
->getChild(pNode
->count() - 1);
1824 if ( eJoinType
!= CROSS_JOIN
&& !bNatural
)
1827 OQueryTableWindow
* pLeftWindow
= static_cast<OQueryTableView
*>(_pView
->getTableView())->FindTable( getTableRange(_pView
,pNode
->getChild(0)) );
1828 OQueryTableWindow
* pRightWindow
= static_cast<OQueryTableView
*>(_pView
->getTableView())->FindTable( getTableRange(_pView
,pRightTableRef
) );
1829 OSL_ENSURE(pLeftWindow
&& pRightWindow
,"Table Windows could not be found!");
1830 if ( !pLeftWindow
|| !pRightWindow
)
1833 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
1834 aDragLeft
->SetTabWindow(pLeftWindow
);
1835 aDragLeft
->SetTable(pLeftWindow
->GetTableName());
1836 aDragLeft
->SetAlias(pLeftWindow
->GetAliasName());
1838 OTableFieldDescRef aDragRight
= new OTableFieldDesc();
1839 aDragRight
->SetTabWindow(pRightWindow
);
1840 aDragRight
->SetTable(pRightWindow
->GetTableName());
1841 aDragRight
->SetAlias(pRightWindow
->GetAliasName());
1843 insertConnection(_pView
,eJoinType
,aDragLeft
,aDragRight
,bNatural
);
1847 void insertUnUsedFields(OQueryDesignView
const * _pView
,OSelectionBrowseBox
* _pSelectionBrw
)
1849 // now we have to insert the fields which aren't in the statement
1850 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
1851 OTableFields
& rUnUsedFields
= rController
.getUnUsedFields();
1852 for (auto & unusedField
: rUnUsedFields
)
1853 if(_pSelectionBrw
->InsertField(unusedField
,BROWSER_INVALIDID
,false,false).is())
1854 unusedField
= nullptr;
1855 OTableFields().swap( rUnUsedFields
);
1858 SqlParseError
InitFromParseNodeImpl(OQueryDesignView
* _pView
,OSelectionBrowseBox
* _pSelectionBrw
)
1860 SqlParseError eErrorCode
= eOk
;
1862 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
1864 _pSelectionBrw
->PreFill();
1865 _pSelectionBrw
->SetReadOnly(rController
.isReadOnly());
1866 _pSelectionBrw
->Fill();
1868 ::connectivity::OSQLParseTreeIterator
& aIterator
= rController
.getParseIterator();
1869 const ::connectivity::OSQLParseNode
* pParseTree
= aIterator
.getParseTree();
1875 // now we have to insert the fields which aren't in the statement
1876 insertUnUsedFields(_pView
,_pSelectionBrw
);
1880 if ( !rController
.isEscapeProcessing() ) // not allowed in this mode
1882 eErrorCode
= eNativeMode
;
1886 if ( !( SQL_ISRULE( pParseTree
, select_statement
) ) )
1888 eErrorCode
= eNoSelectStatement
;
1892 const OSQLParseNode
* pTableExp
= pParseTree
->getChild(3);
1893 if ( pTableExp
->getChild(7)->count() > 0 || pTableExp
->getChild(8)->count() > 0)
1895 eErrorCode
= eStatementTooComplex
;
1899 Reference
< XConnection
> xConnection
= rController
.getConnection();
1900 if ( !xConnection
.is() )
1902 OSL_FAIL( "InitFromParseNodeImpl: no connection? no connection!" );
1906 const OSQLTables
& aMap
= aIterator
.getTables();
1907 ::comphelper::UStringMixLess
aTmp(aMap
.key_comp());
1908 ::comphelper::UStringMixEqual
aKeyComp( aTmp
.isCaseSensitive() );
1910 Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
1913 sal_Int32 nMax
= xMetaData
->getMaxTablesInSelect();
1914 if ( nMax
&& nMax
< static_cast<sal_Int32
>(aMap
.size()) )
1916 eErrorCode
= eTooManyTables
;
1920 OUString sComposedName
;
1923 OQueryTableView
* pTableView
= static_cast<OQueryTableView
*>(_pView
->getTableView());
1924 pTableView
->clearLayoutInformation();
1925 for (auto const& elem
: aMap
)
1927 OSQLTable xTable
= elem
.second
;
1928 Reference
< XPropertySet
> xTableProps( xTable
, UNO_QUERY_THROW
);
1930 sAlias
= elem
.first
;
1932 // check whether this is a query
1933 Reference
< XPropertySetInfo
> xPSI
= xTableProps
->getPropertySetInfo();
1934 bool bIsQuery
= xPSI
.is() && xPSI
->hasPropertyByName( PROPERTY_COMMAND
);
1937 OSL_VERIFY( xTableProps
->getPropertyValue( PROPERTY_NAME
) >>= sComposedName
);
1940 sComposedName
= ::dbtools::composeTableName( xMetaData
, xTableProps
, ::dbtools::EComposeRule::InDataManipulation
, false );
1942 // if the alias is the complete (composed) table, then shorten it
1943 if ( aKeyComp( sComposedName
, elem
.first
) )
1945 OUString sCatalog
, sSchema
, sTable
;
1946 ::dbtools::qualifiedNameComponents( xMetaData
, sComposedName
, sCatalog
, sSchema
, sTable
, ::dbtools::EComposeRule::InDataManipulation
);
1951 // find the existent window for this alias
1952 OQueryTableWindow
* pExistentWin
= pTableView
->FindTable( sAlias
);
1953 if ( !pExistentWin
)
1955 pTableView
->AddTabWin( sComposedName
, sAlias
); // don't create data here
1959 // there already exists a window for this alias...
1960 if ( !aKeyComp( pExistentWin
->GetData()->GetComposedName(), sComposedName
) )
1961 // ... but for another complete table name -> new window
1962 pTableView
->AddTabWin(sComposedName
, sAlias
);
1966 // now delete the data for which we haven't any tablewindow
1967 OJoinTableView::OTableWindowMap
aTableMap(pTableView
->GetTabWinMap());
1968 for (auto const& table
: aTableMap
)
1970 if(aMap
.find(table
.second
->GetComposedName()) == aMap
.end() &&
1971 aMap
.find(table
.first
) == aMap
.end())
1972 pTableView
->RemoveTabWin(table
.second
);
1975 if ( eOk
== (eErrorCode
= FillOuterJoins(_pView
,pTableExp
->getChild(0)->getChild(1))) )
1977 // check if we have a distinct statement
1978 if(SQL_ISTOKEN(pParseTree
->getChild(1),DISTINCT
))
1980 rController
.setDistinct(true);
1981 rController
.InvalidateFeature(SID_QUERY_DISTINCT_VALUES
);
1985 rController
.setDistinct(false);
1988 ///check if query has a limit
1989 if( pTableExp
->getChild(6)->count() >= 2 && pTableExp
->getChild(6)->getChild(1) )
1991 rController
.setLimit(
1992 pTableExp
->getChild(6)->getChild(1)->getTokenValue().toInt64() );
1996 rController
.setLimit(-1);
1999 if ( (eErrorCode
= InstallFields(_pView
, pParseTree
, &pTableView
->GetTabWinMap())) == eOk
)
2001 // GetSelectionCriteria must be called before GetHavingCriteria
2002 sal_uInt16 nLevel
=0;
2004 if ( eOk
== (eErrorCode
= GetSelectionCriteria(_pView
,_pSelectionBrw
,pParseTree
,nLevel
)) )
2006 if ( eOk
== (eErrorCode
= GetGroupCriteria(_pView
,_pSelectionBrw
,pParseTree
)) )
2008 if ( eOk
== (eErrorCode
= GetHavingCriteria(_pView
,_pSelectionBrw
,pParseTree
,nLevel
)) )
2010 if ( eOk
== (eErrorCode
= GetOrderCriteria(_pView
,_pSelectionBrw
,pParseTree
)) )
2011 insertUnUsedFields(_pView
,_pSelectionBrw
);
2018 catch(SQLException
&)
2020 OSL_FAIL("getMaxTablesInSelect!");
2025 // New Undo-Actions were created in the Manager by the regeneration
2026 rController
.ClearUndoManager();
2027 _pSelectionBrw
->Invalidate();
2030 /** fillSelectSubList
2032 <TRUE/> when columns could be inserted otherwise <FALSE/>
2034 SqlParseError
fillSelectSubList( OQueryDesignView
* _pView
,
2035 OJoinTableView::OTableWindowMap
* _pTabList
)
2037 SqlParseError eErrorCode
= eOk
;
2038 bool bFirstField
= true;
2039 for (auto const& table
: *_pTabList
)
2041 OQueryTableWindow
* pTabWin
= static_cast<OQueryTableWindow
*>(table
.second
.get());
2042 OTableFieldDescRef aInfo
= new OTableFieldDesc();
2043 if (pTabWin
->ExistsField( "*", aInfo
))
2045 eErrorCode
= _pView
->InsertField(aInfo
, bFirstField
);
2046 bFirstField
= false;
2047 if (eErrorCode
!= eOk
)
2053 SqlParseError
InstallFields(OQueryDesignView
* _pView
,
2054 const ::connectivity::OSQLParseNode
* pNode
,
2055 OJoinTableView::OTableWindowMap
* pTabList
)
2057 if( pNode
==nullptr || !SQL_ISRULE(pNode
,select_statement
))
2058 return eNoSelectStatement
;
2060 ::connectivity::OSQLParseNode
* pParseTree
= pNode
->getChild(2); // selection
2061 bool bFirstField
= true; // When initializing, the first field must be reactivated
2063 SqlParseError eErrorCode
= eOk
;
2065 if ( pParseTree
->isRule() && SQL_ISPUNCTUATION(pParseTree
->getChild(0),"*") )
2068 eErrorCode
= fillSelectSubList(_pView
,pTabList
);
2070 else if (SQL_ISRULE(pParseTree
,scalar_exp_commalist
) )
2072 // SELECT column, ...
2073 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
2074 Reference
< XConnection
> xConnection
= rController
.getConnection();
2076 OUString aColumnName
,aTableRange
;
2077 for (size_t i
= 0; i
< pParseTree
->count() && eOk
== eErrorCode
; ++i
)
2079 ::connectivity::OSQLParseNode
* pColumnRef
= pParseTree
->getChild(i
);
2083 if ( SQL_ISRULE(pColumnRef
,select_sublist
) )
2085 eErrorCode
= fillSelectSubList(_pView
,pTabList
);
2089 if ( SQL_ISRULE(pColumnRef
,derived_column
) )
2091 OUString
aColumnAlias(connectivity::OSQLParseTreeIterator::getColumnAlias(pColumnRef
)); // might be empty
2092 pColumnRef
= pColumnRef
->getChild(0);
2093 OTableFieldDescRef aInfo
= new OTableFieldDesc();
2095 if ( pColumnRef
->getKnownRuleID() != OSQLParseNode::subquery
&&
2096 pColumnRef
->count() == 3 &&
2097 SQL_ISPUNCTUATION(pColumnRef
->getChild(0),"(") &&
2098 SQL_ISPUNCTUATION(pColumnRef
->getChild(2),")")
2100 pColumnRef
= pColumnRef
->getChild(1);
2102 if (SQL_ISRULE(pColumnRef
,column_ref
))
2104 InsertColumnRef(_pView
,pColumnRef
,aColumnName
,aColumnAlias
,aTableRange
,aInfo
,pTabList
);
2105 eErrorCode
= _pView
->InsertField(aInfo
, bFirstField
);
2106 bFirstField
= false;
2108 else if(SQL_ISRULEOR3(pColumnRef
, general_set_fct
, set_fct_spec
, position_exp
) ||
2109 SQL_ISRULEOR3(pColumnRef
, extract_exp
, fold
, char_substring_fct
) ||
2110 SQL_ISRULEOR2(pColumnRef
,length_exp
,char_value_fct
))
2113 pColumnRef
->parseNodeToPredicateStr(aColumns
,
2115 rController
.getNumberFormatter(),
2116 _pView
->getLocale(),
2117 _pView
->getDecimalSeparator(),
2118 &rController
.getParser().getContext());
2120 sal_Int32 nFunctionType
= FKT_NONE
;
2121 ::connectivity::OSQLParseNode
* pParamRef
= nullptr;
2122 sal_Int32 nColumnRefPos
= pColumnRef
->count() - 2;
2123 if ( nColumnRefPos
>= 0 && o3tl::make_unsigned(nColumnRefPos
) < pColumnRef
->count() )
2124 pParamRef
= pColumnRef
->getChild(nColumnRefPos
);
2126 if ( SQL_ISRULE(pColumnRef
,general_set_fct
)
2127 && pParamRef
&& SQL_ISRULE(pParamRef
,column_ref
) )
2129 // Check the parameters for Column references
2130 InsertColumnRef(_pView
,pParamRef
,aColumnName
,aColumnAlias
,aTableRange
,aInfo
,pTabList
);
2132 else if ( SQL_ISRULE(pColumnRef
,general_set_fct
) )
2134 if ( pParamRef
&& pParamRef
->getTokenValue().toChar() == '*' )
2136 for (auto const& table
: *pTabList
)
2138 OQueryTableWindow
* pTabWin
= static_cast<OQueryTableWindow
*>(table
.second
.get());
2139 if (pTabWin
->ExistsField( "*", aInfo
))
2141 aInfo
->SetAlias(OUString());
2142 aInfo
->SetTable(OUString());
2149 OUString sFieldName
= aColumns
;
2151 { // we got an aggregate function but without column name inside
2152 // so we set the whole argument of the function as field name
2153 nFunctionType
|= FKT_NUMERIC
;
2155 pParamRef
->parseNodeToStr( sFieldName
,
2157 &rController
.getParser().getContext(),
2158 true); // quote is to true because we need quoted elements inside the function
2160 aInfo
->SetDataType(DataType::DOUBLE
);
2161 aInfo
->SetFieldType(TAB_NORMAL_FIELD
);
2162 aInfo
->SetField(sFieldName
);
2164 aInfo
->SetTabWindow(nullptr);
2165 aInfo
->SetFieldAlias(aColumnAlias
);
2169 _pView
->fillFunctionInfo(pColumnRef
,aColumns
,aInfo
);
2170 aInfo
->SetFieldAlias(aColumnAlias
);
2173 if ( SQL_ISRULE(pColumnRef
,general_set_fct
) )
2175 aInfo
->SetFunctionType(nFunctionType
|FKT_AGGREGATE
);
2176 aInfo
->SetFunction(OUString(comphelper::string::stripEnd(o3tl::getToken(aColumns
,0,'('), ' ')));
2179 aInfo
->SetFunctionType(nFunctionType
|FKT_OTHER
);
2181 eErrorCode
= _pView
->InsertField(aInfo
, bFirstField
);
2182 bFirstField
= false;
2187 pColumnRef
->parseNodeToStr( aColumns
,
2189 &rController
.getParser().getContext(),
2190 true); // quote is to true because we need quoted elements inside the function
2192 aInfo
->SetTabWindow( nullptr );
2194 // since we support queries in queries, the thingie might belong to an existing "table"
2195 OQueryTableWindow
* pExistingTable
= lcl_findColumnInTables( aColumns
, *pTabList
, aInfo
);
2196 if ( pExistingTable
)
2198 aInfo
->SetTabWindow( pExistingTable
);
2199 aInfo
->SetTable( pExistingTable
->GetTableName() );
2200 aInfo
->SetAlias( pExistingTable
->GetAliasName() );
2203 aInfo
->SetDataType(DataType::DOUBLE
);
2204 aInfo
->SetFieldType(TAB_NORMAL_FIELD
);
2205 aInfo
->SetField(aColumns
);
2206 aInfo
->SetFieldAlias(aColumnAlias
);
2207 aInfo
->SetFunctionType(FKT_NUMERIC
| FKT_OTHER
);
2209 eErrorCode
= _pView
->InsertField(aInfo
, bFirstField
);
2210 bFirstField
= false;
2216 OSL_FAIL( "InstallFields: don't know how to interpret this parse node!" );
2222 eErrorCode
= eStatementTooComplex
;
2226 SqlParseError
GetOrderCriteria( OQueryDesignView
* _pView
,
2227 OSelectionBrowseBox
* _pSelectionBrw
,
2228 const ::connectivity::OSQLParseNode
* pParseRoot
)
2230 SqlParseError eErrorCode
= eOk
;
2231 if (!pParseRoot
->getChild(3)->getChild(ORDER_BY_CHILD_POS
)->isLeaf())
2233 ::connectivity::OSQLParseNode
* pNode
= pParseRoot
->getChild(3)->getChild(ORDER_BY_CHILD_POS
)->getChild(2);
2234 ::connectivity::OSQLParseNode
* pParamRef
= nullptr;
2236 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
2237 EOrderDir eOrderDir
;
2238 for( size_t i
=0 ; i
<pNode
->count() ; i
++ )
2240 OTableFieldDescRef aDragLeft
= new OTableFieldDesc();
2241 eOrderDir
= ORDER_ASC
;
2242 ::connectivity::OSQLParseNode
* pChild
= pNode
->getChild( i
);
2244 if (SQL_ISTOKEN( pChild
->getChild(1), DESC
) )
2245 eOrderDir
= ORDER_DESC
;
2247 ::connectivity::OSQLParseNode
* pArgument
= pChild
->getChild(0);
2249 if(SQL_ISRULE(pArgument
,column_ref
))
2251 if( eOk
== FillDragInfo(_pView
,pArgument
,aDragLeft
))
2252 _pSelectionBrw
->AddOrder( aDragLeft
, eOrderDir
, i
);
2253 else // it could be an alias name for a field
2255 OUString aTableRange
,aColumnName
;
2256 ::connectivity::OSQLParseTreeIterator
& rParseIter
= rController
.getParseIterator();
2257 rParseIter
.getColumnRange( pArgument
, aColumnName
, aTableRange
);
2259 OTableFields
& aList
= rController
.getTableFieldDesc();
2260 for (auto const& elem
: aList
)
2262 if(elem
.is() && elem
->GetFieldAlias() == aColumnName
)
2263 elem
->SetOrderDir( eOrderDir
);
2267 else if(SQL_ISRULE(pArgument
, general_set_fct
) &&
2268 SQL_ISRULE(pParamRef
= pArgument
->getChild(pArgument
->count()-2),column_ref
) &&
2269 eOk
== FillDragInfo(_pView
,pParamRef
,aDragLeft
))
2270 _pSelectionBrw
->AddOrder( aDragLeft
, eOrderDir
, i
);
2271 else if( SQL_ISRULE(pArgument
, set_fct_spec
) )
2274 Reference
< XConnection
> xConnection
= rController
.getConnection();
2275 if(xConnection
.is())
2277 OUString sCondition
;
2278 pArgument
->parseNodeToPredicateStr(sCondition
,
2280 rController
.getNumberFormatter(),
2281 _pView
->getLocale(),
2282 _pView
->getDecimalSeparator(),
2283 &rController
.getParser().getContext());
2284 _pView
->fillFunctionInfo(pArgument
,sCondition
,aDragLeft
);
2285 aDragLeft
->SetFunctionType(FKT_OTHER
);
2286 aDragLeft
->SetOrderDir(eOrderDir
);
2287 aDragLeft
->SetVisible(false);
2288 _pSelectionBrw
->AddOrder( aDragLeft
, eOrderDir
, i
);
2291 eErrorCode
= eColumnNotFound
;
2294 eErrorCode
= eColumnNotFound
;
2299 SqlParseError
GetHavingCriteria( OQueryDesignView
* _pView
,
2300 OSelectionBrowseBox
* _pSelectionBrw
,
2301 const ::connectivity::OSQLParseNode
* pSelectRoot
,
2302 sal_uInt16
& rLevel
)
2304 SqlParseError eErrorCode
= eOk
;
2305 if (!pSelectRoot
->getChild(3)->getChild(3)->isLeaf())
2306 eErrorCode
= GetORCriteria(_pView
,_pSelectionBrw
,pSelectRoot
->getChild(3)->getChild(3)->getChild(1),rLevel
, true);
2309 SqlParseError
GetGroupCriteria( OQueryDesignView
* _pView
,
2310 OSelectionBrowseBox
* _pSelectionBrw
,
2311 const ::connectivity::OSQLParseNode
* pSelectRoot
)
2313 SqlParseError eErrorCode
= eOk
;
2314 if (!pSelectRoot
->getChild(3)->getChild(2)->isLeaf()) // opt_group_by_clause
2316 OQueryController
& rController
= static_cast<OQueryController
&>(_pView
->getController());
2317 ::connectivity::OSQLParseNode
* pGroupBy
= pSelectRoot
->getChild(3)->getChild(2)->getChild(2);
2319 for( size_t i
=0 ; i
< pGroupBy
->count() && eOk
== eErrorCode
; ++i
)
2321 OTableFieldDescRef aDragInfo
= new OTableFieldDesc();
2322 ::connectivity::OSQLParseNode
* pParamRef
= nullptr;
2323 ::connectivity::OSQLParseNode
* pArgument
= pGroupBy
->getChild( i
);
2324 if(SQL_ISRULE(pArgument
,column_ref
))
2326 if ( eOk
== (eErrorCode
= FillDragInfo(_pView
,pArgument
,aDragInfo
)) )
2328 aDragInfo
->SetGroupBy(true);
2329 _pSelectionBrw
->AddGroupBy(aDragInfo
);
2332 else if(SQL_ISRULE(pArgument
, general_set_fct
) &&
2333 SQL_ISRULE(pParamRef
= pArgument
->getChild(pArgument
->count()-2),column_ref
) &&
2334 eOk
== FillDragInfo(_pView
,pParamRef
,aDragInfo
))
2336 aDragInfo
->SetGroupBy(true);
2337 _pSelectionBrw
->AddGroupBy( aDragInfo
);
2339 else if( SQL_ISRULE(pArgument
, set_fct_spec
) )
2341 Reference
< XConnection
> xConnection
= rController
.getConnection();
2342 if(xConnection
.is())
2344 OUString sGroupByExpression
;
2345 pArgument
->parseNodeToStr( sGroupByExpression
,
2347 &rController
.getParser().getContext(),
2348 true); // quote is to true because we need quoted elements inside the function
2349 _pView
->fillFunctionInfo(pArgument
,sGroupByExpression
,aDragInfo
);
2350 aDragInfo
->SetFunctionType(FKT_OTHER
);
2351 aDragInfo
->SetGroupBy(true);
2352 aDragInfo
->SetVisible(false);
2353 _pSelectionBrw
->AddGroupBy( aDragInfo
);
2356 eErrorCode
= eColumnNotFound
;
2363 OUString
getParseErrorMessage( SqlParseError _eErrorCode
)
2366 switch (_eErrorCode
)
2369 pResId
= STR_QRY_ILLEGAL_JOIN
;
2371 case eStatementTooLong
:
2372 pResId
= STR_QRY_TOO_LONG_STATEMENT
;
2375 pResId
= STR_QRY_SYNTAX
;
2377 case eNoSelectStatement
:
2378 pResId
= STR_QRY_NOSELECT
;
2380 case eNoColumnInLike
:
2381 pResId
= STR_QRY_SYNTAX
;
2383 case eColumnNotFound
:
2384 pResId
= STR_QRY_SYNTAX
;
2387 pResId
= STR_QRY_NATIVE
;
2389 case eTooManyTables
:
2390 pResId
= STR_QRY_TOO_MANY_TABLES
;
2392 case eTooManyColumns
:
2393 pResId
= STR_QRY_TOO_MANY_COLUMNS
;
2395 case eStatementTooComplex
:
2396 pResId
= STR_QRY_TOOCOMPLEX
;
2399 pResId
= STR_QRY_SYNTAX
;
2402 return DBA_RES(pResId
);
2406 // end of anonymous namespace
2408 OQueryDesignView::OQueryDesignView( OQueryContainerWindow
* _pParent
,
2409 OQueryController
& _rController
,
2410 const Reference
< XComponentContext
>& _rxContext
)
2411 :OJoinDesignView( _pParent
, _rController
, _rxContext
)
2412 ,m_aSplitter( VclPtr
<Splitter
>::Create(this) )
2413 ,m_eChildFocus(NONE
)
2414 ,m_bInSplitHandler( false )
2419 SvtSysLocale aSysLocale
;
2420 m_aLocale
= aSysLocale
.GetLanguageTag().getLocale();
2421 m_sDecimalSep
= aSysLocale
.GetLocaleData().getNumDecimalSep();
2427 m_pSelectionBox
= VclPtr
<OSelectionBrowseBox
>::Create(this);
2429 setNoneVisibleRow(static_cast<OQueryController
&>(getController()).getVisibleRows());
2430 m_pSelectionBox
->Show();
2432 m_aSplitter
->SetSplitHdl(LINK(this, OQueryDesignView
,SplitHdl
));
2433 m_aSplitter
->Show();
2437 OQueryDesignView::~OQueryDesignView()
2442 void OQueryDesignView::dispose()
2445 ::dbaui::notifySystemWindow(this,m_pTableView
,::comphelper::mem_fun(&TaskPaneList::RemoveWindow
));
2446 m_pSelectionBox
.disposeAndClear();
2447 m_aSplitter
.disposeAndClear();
2448 OJoinDesignView::dispose();
2451 IMPL_LINK_NOARG( OQueryDesignView
, SplitHdl
, Splitter
*, void )
2453 if (!getController().isReadOnly())
2455 m_bInSplitHandler
= true;
2456 m_aSplitter
->SetPosPixel( Point( m_aSplitter
->GetPosPixel().X(),m_aSplitter
->GetSplitPosPixel() ) );
2457 static_cast<OQueryController
&>(getController()).setSplitPos(m_aSplitter
->GetSplitPosPixel());
2458 static_cast<OQueryController
&>(getController()).setModified( true );
2460 m_bInSplitHandler
= true;
2464 void OQueryDesignView::Construct()
2466 m_pTableView
= VclPtr
<OQueryTableView
>::Create(m_pScrollWindow
,this);
2467 ::dbaui::notifySystemWindow(this,m_pTableView
,::comphelper::mem_fun(&TaskPaneList::AddWindow
));
2468 OJoinDesignView::Construct();
2471 void OQueryDesignView::initialize()
2473 if(static_cast<OQueryController
&>(getController()).getSplitPos() != -1)
2475 m_aSplitter
->SetPosPixel( Point( m_aSplitter
->GetPosPixel().X(),static_cast<OQueryController
&>(getController()).getSplitPos() ) );
2476 m_aSplitter
->SetSplitPosPixel(static_cast<OQueryController
&>(getController()).getSplitPos());
2478 m_pSelectionBox
->initialize();
2482 void OQueryDesignView::resizeDocumentView(tools::Rectangle
& _rPlayground
)
2484 Point
aPlaygroundPos( _rPlayground
.TopLeft() );
2485 Size
aPlaygroundSize( _rPlayground
.GetSize() );
2487 // calc the split pos, and forward it to the controller
2488 sal_Int32 nSplitPos
= static_cast<OQueryController
&>(getController()).getSplitPos();
2489 if ( 0 != aPlaygroundSize
.Height() )
2491 if ( ( -1 == nSplitPos
)
2492 || ( nSplitPos
>= aPlaygroundSize
.Height() )
2495 // let the selection browse box determine an optimal size
2496 Size aSelectionBoxSize
= m_pSelectionBox
->CalcOptimalSize( aPlaygroundSize
);
2497 nSplitPos
= aPlaygroundSize
.Height() - aSelectionBoxSize
.Height() - m_aSplitter
->GetSizePixel().Height();
2498 // still an invalid size?
2499 if ( nSplitPos
== -1 || nSplitPos
>= aPlaygroundSize
.Height() )
2500 nSplitPos
= sal_Int32(aPlaygroundSize
.Height()*0.6);
2502 static_cast<OQueryController
&>(getController()).setSplitPos(nSplitPos
);
2505 if ( !m_bInSplitHandler
)
2506 { // the resize is triggered by something else than the split handler
2507 // our main focus is to try to preserve the size of the selectionbrowse box
2508 Size aSelBoxSize
= m_pSelectionBox
->GetSizePixel();
2509 if ( aSelBoxSize
.Height() )
2511 // keep the size of the sel box constant
2512 nSplitPos
= aPlaygroundSize
.Height() - m_aSplitter
->GetSizePixel().Height() - aSelBoxSize
.Height();
2514 // and if the box is smaller than the optimal size, try to do something about it
2515 Size aSelBoxOptSize
= m_pSelectionBox
->CalcOptimalSize( aPlaygroundSize
);
2516 if ( aSelBoxOptSize
.Height() > aSelBoxSize
.Height() )
2518 nSplitPos
= aPlaygroundSize
.Height() - m_aSplitter
->GetSizePixel().Height() - aSelBoxOptSize
.Height();
2521 static_cast< OQueryController
& >(getController()).setSplitPos( nSplitPos
);
2526 // normalize the split pos
2527 Point
aSplitPos( _rPlayground
.Left(), nSplitPos
);
2528 Size
aSplitSize( _rPlayground
.GetSize().Width(), m_aSplitter
->GetSizePixel().Height() );
2530 if( ( aSplitPos
.Y() + aSplitSize
.Height() ) > ( aPlaygroundSize
.Height() ))
2531 aSplitPos
.setY( aPlaygroundSize
.Height() - aSplitSize
.Height() );
2533 if( aSplitPos
.Y() <= aPlaygroundPos
.Y() )
2534 aSplitPos
.setY( aPlaygroundPos
.Y() + sal_Int32(aPlaygroundSize
.Height() * 0.2) );
2536 // position the table
2537 Size
aTableViewSize(aPlaygroundSize
.Width(), aSplitPos
.Y() - aPlaygroundPos
.Y());
2538 m_pScrollWindow
->SetPosSizePixel(aPlaygroundPos
, aTableViewSize
);
2540 // position the selection browse box
2541 Point
aPos( aPlaygroundPos
.X(), aSplitPos
.Y() + aSplitSize
.Height() );
2542 m_pSelectionBox
->SetPosSizePixel( aPos
, Size( aPlaygroundSize
.Width(), aPlaygroundSize
.Height() - aSplitSize
.Height() - aTableViewSize
.Height() ));
2544 // set the size of the splitter
2545 m_aSplitter
->SetPosSizePixel( aSplitPos
, aSplitSize
);
2546 m_aSplitter
->SetDragRectPixel( _rPlayground
);
2548 // just for completeness: there is no space left, we occupied it all ...
2549 _rPlayground
.SetPos( _rPlayground
.BottomRight() );
2550 _rPlayground
.SetSize( Size( 0, 0 ) );
2553 void OQueryDesignView::setReadOnly(bool _bReadOnly
)
2555 m_pSelectionBox
->SetReadOnly(_bReadOnly
);
2558 void OQueryDesignView::clear()
2560 m_pSelectionBox
->ClearAll(); // clear the whole selection
2561 m_pTableView
->ClearAll();
2564 void OQueryDesignView::copy()
2566 if( m_eChildFocus
== SELECTION
)
2567 m_pSelectionBox
->copy();
2570 bool OQueryDesignView::isCutAllowed() const
2572 bool bAllowed
= false;
2573 if ( SELECTION
== m_eChildFocus
)
2574 bAllowed
= m_pSelectionBox
->isCutAllowed();
2578 bool OQueryDesignView::isPasteAllowed() const
2580 bool bAllowed
= false;
2581 if ( SELECTION
== m_eChildFocus
)
2582 bAllowed
= m_pSelectionBox
->isPasteAllowed();
2586 bool OQueryDesignView::isCopyAllowed() const
2588 bool bAllowed
= false;
2589 if ( SELECTION
== m_eChildFocus
)
2590 bAllowed
= m_pSelectionBox
->isCopyAllowed();
2594 void OQueryDesignView::stopTimer()
2596 m_pSelectionBox
->stopTimer();
2599 void OQueryDesignView::startTimer()
2601 m_pSelectionBox
->startTimer();
2604 void OQueryDesignView::cut()
2606 if( m_eChildFocus
== SELECTION
)
2608 m_pSelectionBox
->cut();
2609 static_cast<OQueryController
&>(getController()).setModified(true);
2613 void OQueryDesignView::paste()
2615 if( m_eChildFocus
== SELECTION
)
2617 m_pSelectionBox
->paste();
2618 static_cast<OQueryController
&>(getController()).setModified(true);
2622 void OQueryDesignView::TableDeleted(const OUString
& rAliasName
)
2624 // message that the table was removed from the window
2625 m_pSelectionBox
->DeleteFields( rAliasName
);
2626 static_cast<OQueryController
&>(getController()).InvalidateFeature(ID_BROWSER_ADDTABLE
); // inform the view again
2629 bool OQueryDesignView::HasFieldByAliasName(std::u16string_view rFieldName
, OTableFieldDescRef
const & rInfo
) const
2631 return m_pSelectionBox
->HasFieldByAliasName( rFieldName
, rInfo
);
2634 SqlParseError
OQueryDesignView::InsertField( const OTableFieldDescRef
& rInfo
, bool bActivate
)
2636 return m_pSelectionBox
->InsertField( rInfo
, BROWSER_INVALIDID
, true/*bVis*/, bActivate
).is() ? eOk
: eTooManyColumns
;
2639 sal_Int32
OQueryDesignView::getColWidth(sal_uInt16 _nColPos
) const
2641 static sal_Int32 s_nDefaultWidth
= GetTextWidth("0") * 15;
2642 sal_Int32 nWidth
= static_cast<OQueryController
&>(getController()).getColWidth(_nColPos
);
2644 nWidth
= s_nDefaultWidth
;
2648 void OQueryDesignView::fillValidFields(std::u16string_view sAliasName
, weld::ComboBox
& rFieldList
)
2652 bool bAllTables
= sAliasName
.empty();
2654 OJoinTableView::OTableWindowMap
& rTabWins
= m_pTableView
->GetTabWinMap();
2655 OUString strCurrentPrefix
;
2656 std::vector
< OUString
> aFields
;
2657 for (auto const& tabWin
: rTabWins
)
2659 OQueryTableWindow
* pCurrentWin
= static_cast<OQueryTableWindow
*>(tabWin
.second
.get());
2660 if (bAllTables
|| (pCurrentWin
->GetAliasName() == sAliasName
))
2662 strCurrentPrefix
= pCurrentWin
->GetAliasName() + ".";
2664 pCurrentWin
->EnumValidFields(aFields
);
2666 for (auto const& field
: aFields
)
2668 if (bAllTables
|| field
.toChar() == '*')
2669 rFieldList
.append_text(strCurrentPrefix
+ field
);
2671 rFieldList
.append_text(field
);
2675 // this means that I came into this block because the table name was exactly what I was looking for so I can end here
2676 // (and I prevent that fields get added more than once, if a table is repeated in TabWin)
2682 bool OQueryDesignView::PreNotify(NotifyEvent
& rNEvt
)
2684 if (rNEvt
.GetType() == NotifyEventType::GETFOCUS
)
2686 if ( m_pSelectionBox
&& m_pSelectionBox
->HasChildPathFocus() )
2687 m_eChildFocus
= SELECTION
;
2689 m_eChildFocus
= TABLEVIEW
;
2692 return OJoinDesignView::PreNotify(rNEvt
);
2695 // check if the statement is correct when not returning false
2696 bool OQueryDesignView::checkStatement()
2699 if ( m_pSelectionBox
)
2700 bRet
= m_pSelectionBox
->Save(); // an error occurred so we return no
2704 OUString
OQueryDesignView::getStatement()
2706 OQueryController
& rController
= static_cast<OQueryController
&>(getController());
2707 m_rController
.clearError();
2708 // used for fields which aren't any longer in the statement
2709 OTableFields
& rUnUsedFields
= rController
.getUnUsedFields();
2710 OTableFields().swap( rUnUsedFields
);
2712 // create the select columns
2713 sal_uInt32 nFieldcount
= 0;
2714 OTableFields
& rFieldList
= rController
.getTableFieldDesc();
2715 for (auto const& field
: rFieldList
)
2717 if (!field
->GetField().isEmpty() && field
->IsVisible() )
2719 else if (!field
->GetField().isEmpty() &&
2720 !field
->HasCriteria() &&
2721 field
->isNoneFunction() &&
2722 field
->GetOrderDir() == ORDER_NONE
&&
2723 !field
->IsGroupBy() &&
2724 field
->GetFunction().isEmpty() )
2725 rUnUsedFields
.push_back(field
);
2727 if ( !nFieldcount
) // no visible fields so return
2729 rUnUsedFields
= rFieldList
;
2733 OQueryTableView::OTableWindowMap
& rTabList
= m_pTableView
->GetTabWinMap();
2734 sal_uInt32 nTabcount
= rTabList
.size();
2736 OUString
aFieldListStr(GenerateSelectList(this,rFieldList
,nTabcount
>1));
2737 if( aFieldListStr
.isEmpty() )
2740 // Exception handling, if no fields have been passed we should not
2741 // change the tab page
2742 // TabBarSelectHdl will query the SQL-OUString for STATEMENT_NOFIELDS
2743 // and trigger an error message
2744 // ----------------- Build table list ----------------------
2746 const auto& rConnList
= m_pTableView
->getTableConnections();
2747 Reference
< XConnection
> xConnection
= rController
.getConnection();
2748 OUString
aTableListStr(GenerateFromClause(xConnection
,&rTabList
,rConnList
));
2749 OSL_ENSURE(!aTableListStr
.isEmpty(), "OQueryDesignView::getStatement() : unexpected : have Fields, but no Tables !");
2750 // if fields exist now, these only can be created by inserting from an already existing table; if on the other hand
2751 // a table is deleted, also the belonging fields will be deleted -> therefore it CANNOT occur that fields
2752 // exist but no tables exist (and aFieldListStr has its length, I secure this above)
2753 OUStringBuffer aHavingStr
,aCriteriaListStr
;
2755 // ----------------- build the criteria ----------------------
2756 if (!GenerateCriterias(this,aCriteriaListStr
,aHavingStr
,rFieldList
, nTabcount
> 1))
2760 GenerateInnerJoinCriterias(xConnection
,aJoinCrit
,rConnList
);
2761 if(!aJoinCrit
.isEmpty())
2763 OUString aTmp
= "( " + aJoinCrit
+ " )";
2764 if(!aCriteriaListStr
.isEmpty())
2768 aCriteriaListStr
.insert(0, aTmp
);
2770 // ----------------- construct statement ----------------------
2771 OUStringBuffer
aSqlCmd("SELECT ");
2772 if(rController
.isDistinct())
2773 aSqlCmd
.append(" DISTINCT ");
2774 aSqlCmd
.append(aFieldListStr
+ " FROM " + aTableListStr
);
2776 if (!aCriteriaListStr
.isEmpty())
2778 aSqlCmd
.append(" WHERE " + aCriteriaListStr
);
2780 Reference
<XDatabaseMetaData
> xMeta
;
2781 if ( xConnection
.is() )
2782 xMeta
= xConnection
->getMetaData();
2783 bool bUseAlias
= nTabcount
> 1;
2785 bUseAlias
= bUseAlias
|| !xMeta
->supportsGroupByUnrelated();
2787 aSqlCmd
.append(GenerateGroupBy(this,rFieldList
,bUseAlias
));
2788 // ----------------- construct GroupBy and attach ------------
2789 if(!aHavingStr
.isEmpty())
2791 aSqlCmd
.append(" HAVING " + aHavingStr
);
2793 // ----------------- construct sorting and attach ------------
2795 SqlParseError eErrorCode
= eOk
;
2796 if ( (eErrorCode
= GenerateOrder(this,rFieldList
,nTabcount
> 1,sOrder
)) == eOk
)
2797 aSqlCmd
.append(sOrder
);
2800 if ( !m_rController
.hasError() )
2801 m_rController
.appendError( getParseErrorMessage( eErrorCode
) );
2803 m_rController
.displayError();
2805 // --------------------- Limit Clause -------------------
2807 const sal_Int64 nLimit
= rController
.getLimit();
2810 aSqlCmd
.append( " LIMIT " + OUString::number(nLimit
) );
2814 OUString sSQL
= aSqlCmd
.makeStringAndClear();
2815 if ( xConnection
.is() )
2817 ::connectivity::OSQLParser
& rParser( rController
.getParser() );
2818 OUString sErrorMessage
;
2819 std::unique_ptr
<OSQLParseNode
> pParseNode( rParser
.parseTree( sErrorMessage
, sSQL
, true ) );
2822 OSQLParseNode
* pNode
= pParseNode
->getChild(3)->getChild(1);
2823 if ( pNode
->count() > 1 )
2825 ::connectivity::OSQLParseNode
* pCondition
= pNode
->getChild(1);
2826 if ( pCondition
) // no where clause
2828 OSQLParseNode::compress(pCondition
);
2830 pParseNode
->parseNodeToStr(sTemp
,xConnection
);
2839 void OQueryDesignView::setSlotEnabled(sal_Int32 _nSlotId
, bool _bEnable
)
2844 case SID_QUERY_VIEW_FUNCTIONS
:
2845 nRow
= BROW_FUNCTION_ROW
;
2847 case SID_QUERY_VIEW_TABLES
:
2848 nRow
= BROW_TABLE_ROW
;
2850 case SID_QUERY_VIEW_ALIASES
:
2851 nRow
= BROW_COLUMNALIAS_ROW
;
2858 m_pSelectionBox
->SetRowVisible(nRow
,_bEnable
);
2859 m_pSelectionBox
->Invalidate();
2862 bool OQueryDesignView::isSlotEnabled(sal_Int32 _nSlotId
)
2867 case SID_QUERY_VIEW_FUNCTIONS
:
2868 nRow
= BROW_FUNCTION_ROW
;
2870 case SID_QUERY_VIEW_TABLES
:
2871 nRow
= BROW_TABLE_ROW
;
2873 case SID_QUERY_VIEW_ALIASES
:
2874 nRow
= BROW_COLUMNALIAS_ROW
;
2881 return m_pSelectionBox
->IsRowVisible(nRow
);
2884 void OQueryDesignView::SaveUIConfig()
2886 OQueryController
& rCtrl
= static_cast<OQueryController
&>(getController());
2887 rCtrl
.SaveTabWinsPosSize( &m_pTableView
->GetTabWinMap(), m_pScrollWindow
->GetHScrollBar().GetThumbPos(), m_pScrollWindow
->GetVScrollBar().GetThumbPos() );
2888 rCtrl
.setVisibleRows( m_pSelectionBox
->GetNoneVisibleRows() );
2889 if ( m_aSplitter
->GetSplitPosPixel() != 0 )
2890 rCtrl
.setSplitPos( m_aSplitter
->GetSplitPosPixel() );
2893 std::unique_ptr
<OSQLParseNode
> OQueryDesignView::getPredicateTreeFromEntry(const OTableFieldDescRef
& pEntry
,
2894 const OUString
& _sCriteria
,
2895 OUString
& _rsErrorMessage
,
2896 Reference
<XPropertySet
>& _rxColumn
) const
2898 OSL_ENSURE(pEntry
.is(),"Entry is null!");
2901 Reference
< XConnection
> xConnection
= static_cast<OQueryController
&>(getController()).getConnection();
2902 if(!xConnection
.is())
2905 ::connectivity::OSQLParser
& rParser( static_cast<OQueryController
&>(getController()).getParser() );
2906 OQueryTableWindow
* pWin
= static_cast<OQueryTableWindow
*>(pEntry
->GetTabWindow());
2908 // special handling for functions
2909 if ( pEntry
->GetFunctionType() & (FKT_OTHER
| FKT_AGGREGATE
| FKT_NUMERIC
) )
2911 // we have a function here so we have to distinguish the type of return value
2913 if ( pEntry
->isNumericOrAggregateFunction() )
2914 sFunction
= pEntry
->GetFunction().getToken(0, '(');
2916 if ( sFunction
.isEmpty() )
2917 sFunction
= pEntry
->GetField().getToken(0, '(');
2919 sal_Int32 nType
= ::connectivity::OSQLParser::getFunctionReturnType(sFunction
,&rParser
.getContext());
2920 if ( nType
== DataType::OTHER
|| (sFunction
.isEmpty() && pEntry
->isNumericOrAggregateFunction()) )
2922 // first try the international version
2923 OUString sSql
= "SELECT * FROM x WHERE " + pEntry
->GetField() + _sCriteria
;
2924 std::unique_ptr
<OSQLParseNode
> pParseNode( rParser
.parseTree( _rsErrorMessage
, sSql
, true ) );
2925 nType
= DataType::DOUBLE
;
2928 OSQLParseNode
* pColumnRef
= pParseNode
->getByRule(OSQLParseNode::column_ref
);
2931 OTableFieldDescRef aField
= new OTableFieldDesc();
2932 if ( eOk
== FillDragInfo(this,pColumnRef
,aField
) )
2934 nType
= aField
->GetDataType();
2940 Reference
<XDatabaseMetaData
> xMeta
= xConnection
->getMetaData();
2941 rtl::Reference
<parse::OParseColumn
> pColumn
= new parse::OParseColumn( pEntry
->GetField(),
2945 ColumnValue::NULLABLE_UNKNOWN
,
2951 xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers(),
2955 _rxColumn
= pColumn
;
2956 pColumn
->setFunction(true);
2957 pColumn
->setRealName(pEntry
->GetField());
2963 Reference
<XNameAccess
> xColumns
= pWin
->GetOriginalColumns();
2964 if (xColumns
.is() && xColumns
->hasByName(pEntry
->GetField()))
2965 xColumns
->getByName(pEntry
->GetField()) >>= _rxColumn
;
2969 // _rxColumn, if it is a "lookup" column, not a computed column,
2970 // is guaranteed to be the column taken from the *source* of the column,
2971 // that is either a table or another query.
2972 // _rxColumn is *not* taken from the columns of the query we are constructing
2973 // (and rightfully so, since it may not be part of these columns; SELECT A FROM t WHERE B = foo)
2974 // If it is a computed column, we just constructed it above, with same Name and RealName.
2975 // In all cases, we should use the "external" name of the column, not the "RealName";
2976 // the latter is the name that the column had in the source of the source query.
2977 // An example: we are designing "SELECT A, B FROM q WHERE C='foo'"
2978 // q itself is query "SELECT aye AS A, bee as B, cee as C FROM t"
2979 // We are currently treating the entry "C='foo'"
2980 // Then _rxColumn has Name "C" and RealName "cee". We should *obviously* use "C", not "cee".
2981 std::unique_ptr
<OSQLParseNode
> pParseNode
= rParser
.predicateTree( _rsErrorMessage
,
2983 static_cast<OQueryController
&>(getController()).getNumberFormatter(),
2989 void OQueryDesignView::GetFocus()
2991 OJoinDesignView::GetFocus();
2992 if ( m_pSelectionBox
&& !m_pSelectionBox
->HasChildPathFocus() )
2994 // first we have to deactivate the current cell to refill when necessary
2995 m_pSelectionBox
->DeactivateCell();
2996 m_pSelectionBox
->ActivateCell(m_pSelectionBox
->GetCurRow(), m_pSelectionBox
->GetCurColumnId());
2997 m_pSelectionBox
->GrabFocus();
3001 void OQueryDesignView::reset()
3003 m_pTableView
->ClearAll();
3004 m_pTableView
->ReSync();
3007 void OQueryDesignView::setNoneVisibleRow(sal_Int32 _nRows
)
3009 m_pSelectionBox
->SetNoneVisibleRow(_nRows
);
3012 void OQueryDesignView::initByFieldDescriptions( const Sequence
< PropertyValue
>& i_rFieldDescriptions
)
3014 OQueryController
& rController
= static_cast< OQueryController
& >( getController() );
3016 m_pSelectionBox
->PreFill();
3017 m_pSelectionBox
->SetReadOnly( rController
.isReadOnly() );
3018 m_pSelectionBox
->Fill();
3020 for ( auto const & field
: i_rFieldDescriptions
)
3022 ::rtl::Reference
< OTableFieldDesc
> pField( new OTableFieldDesc() );
3023 pField
->Load( field
, true );
3024 InsertField( pField
, false );
3027 rController
.ClearUndoManager();
3028 m_pSelectionBox
->Invalidate();
3031 bool OQueryDesignView::initByParseIterator( ::dbtools::SQLExceptionInfo
* _pErrorInfo
)
3033 SqlParseError eErrorCode
= eNativeMode
;
3034 m_rController
.clearError();
3038 eErrorCode
= InitFromParseNodeImpl( this, m_pSelectionBox
);
3040 if ( eErrorCode
!= eOk
)
3042 if ( !m_rController
.hasError() )
3043 m_rController
.appendError( getParseErrorMessage( eErrorCode
) );
3047 *_pErrorInfo
= m_rController
.getError();
3051 m_rController
.displayError();
3055 catch ( const Exception
& )
3057 DBG_UNHANDLED_EXCEPTION("dbaccess");
3059 return eErrorCode
== eOk
;
3062 // Utility function for fillFunctionInfo
3064 sal_Int32
char_datatype(const::connectivity::OSQLParseNode
* pDataType
, const unsigned int offset
) {
3065 int cnt
= pDataType
->count() - offset
;
3068 OSL_FAIL("internal error in decoding character datatype specification");
3069 return DataType::VARCHAR
;
3071 else if ( cnt
== 0 )
3075 // The datatype is the node itself
3076 if ( SQL_ISTOKENOR2 (pDataType
, CHARACTER
, CHAR
) )
3077 return DataType::CHAR
;
3078 else if ( SQL_ISTOKEN (pDataType
, VARCHAR
) )
3079 return DataType::VARCHAR
;
3080 else if ( SQL_ISTOKEN (pDataType
, CLOB
) )
3081 return DataType::CLOB
;
3084 OSL_FAIL("unknown/unexpected token in decoding character datatype specification");
3085 return DataType::VARCHAR
;
3090 // No child left to read!
3091 OSL_FAIL("incomplete datatype in decoding character datatype specification");
3092 return DataType::VARCHAR
;
3096 if ( SQL_ISTOKEN(pDataType
->getChild(offset
), NATIONAL
) )
3097 return char_datatype(pDataType
, offset
+1);
3098 else if ( SQL_ISTOKENOR3(pDataType
->getChild(offset
), CHARACTER
, CHAR
, NCHAR
) )
3100 if ( cnt
> 2 && SQL_ISTOKEN(pDataType
->getChild(offset
+1), LARGE
) && SQL_ISTOKEN(pDataType
->getChild(offset
+2), OBJECT
) )
3101 return DataType::CLOB
;
3102 else if ( cnt
> 1 && SQL_ISTOKEN(pDataType
->getChild(offset
+1), VARYING
) )
3103 return DataType::VARCHAR
;
3105 return DataType::CHAR
;
3107 else if ( SQL_ISTOKEN (pDataType
->getChild(offset
), VARCHAR
) )
3108 return DataType::VARCHAR
;
3109 else if ( SQL_ISTOKENOR2 (pDataType
->getChild(offset
), CLOB
, NCLOB
) )
3110 return DataType::CLOB
;
3112 OSL_FAIL("unrecognised character datatype");
3113 return DataType::VARCHAR
;
3117 // Try to guess the type of an expression in simple cases.
3118 // Originally meant to be called only on a function call (hence the misnomer),
3119 // but now tries to do the best it can also in other cases.
3120 // Don't completely rely on fillFunctionInfo,
3121 // it won't look at the function's arguments to find the return type
3122 // (in particular, in the case of general_set_fct,
3123 // the return type is the type of the argument;
3124 // if that is (as is typical) a column reference,
3125 // it is the type of the column).
3126 // TODO: There is similar "guess the expression's type" code in several places:
3127 // SelectionBrowseBox.cxx: OSelectionBrowseBox::saveField
3128 // QueryDesignView.cxx: InstallFields, GetOrderCriteria, GetGroupCriteria
3129 // If possible, they should be factorised into this function
3130 // (which should then be renamed...)
3132 void OQueryDesignView::fillFunctionInfo( const ::connectivity::OSQLParseNode
* pNode
3133 ,const OUString
& sFunctionTerm
3134 ,OTableFieldDescRef
& aInfo
)
3136 // get the type of the expression, as far as easily possible
3137 OQueryController
& rController
= static_cast<OQueryController
&>(getController());
3138 sal_Int32 nDataType
= DataType::DOUBLE
;
3139 switch(pNode
->getNodeType())
3141 case SQLNodeType::Concat
:
3142 case SQLNodeType::String
:
3143 nDataType
= DataType::VARCHAR
;
3145 case SQLNodeType::IntNum
:
3146 nDataType
= DataType::INTEGER
;
3148 case SQLNodeType::ApproxNum
:
3149 nDataType
= DataType::DOUBLE
;
3151 case SQLNodeType::AccessDate
:
3152 nDataType
= DataType::TIMESTAMP
;
3154 case SQLNodeType::Equal
:
3155 case SQLNodeType::Less
:
3156 case SQLNodeType::Great
:
3157 case SQLNodeType::LessEq
:
3158 case SQLNodeType::GreatEq
:
3159 case SQLNodeType::NotEqual
:
3160 nDataType
= DataType::BOOLEAN
;
3162 case SQLNodeType::Name
:
3163 case SQLNodeType::ListRule
:
3164 case SQLNodeType::CommaListRule
:
3165 case SQLNodeType::Keyword
:
3166 case SQLNodeType::Punctuation
:
3167 OSL_FAIL("Unexpected SQL Node Type");
3169 case SQLNodeType::Rule
:
3170 switch(pNode
->getKnownRuleID())
3172 case OSQLParseNode::select_statement
:
3173 case OSQLParseNode::table_exp
:
3174 case OSQLParseNode::table_ref_commalist
:
3175 case OSQLParseNode::table_ref
:
3176 case OSQLParseNode::catalog_name
:
3177 case OSQLParseNode::schema_name
:
3178 case OSQLParseNode::table_name
:
3179 case OSQLParseNode::opt_column_commalist
:
3180 case OSQLParseNode::column_commalist
:
3181 case OSQLParseNode::column_ref_commalist
:
3182 case OSQLParseNode::column_ref
:
3183 case OSQLParseNode::opt_order_by_clause
:
3184 case OSQLParseNode::ordering_spec_commalist
:
3185 case OSQLParseNode::ordering_spec
:
3186 case OSQLParseNode::opt_asc_desc
:
3187 case OSQLParseNode::where_clause
:
3188 case OSQLParseNode::opt_where_clause
:
3189 case OSQLParseNode::opt_escape
:
3190 case OSQLParseNode::scalar_exp_commalist
:
3191 case OSQLParseNode::scalar_exp
: // Seems to never be generated?
3192 case OSQLParseNode::parameter_ref
:
3193 case OSQLParseNode::parameter
:
3194 case OSQLParseNode::range_variable
:
3195 case OSQLParseNode::delete_statement_positioned
:
3196 case OSQLParseNode::delete_statement_searched
:
3197 case OSQLParseNode::update_statement_positioned
:
3198 case OSQLParseNode::update_statement_searched
:
3199 case OSQLParseNode::assignment_commalist
:
3200 case OSQLParseNode::assignment
:
3201 case OSQLParseNode::insert_statement
:
3202 case OSQLParseNode::insert_atom_commalist
:
3203 case OSQLParseNode::insert_atom
:
3204 case OSQLParseNode::from_clause
:
3205 case OSQLParseNode::qualified_join
:
3206 case OSQLParseNode::cross_union
:
3207 case OSQLParseNode::select_sublist
:
3208 case OSQLParseNode::join_type
:
3209 case OSQLParseNode::named_columns_join
:
3210 case OSQLParseNode::joined_table
:
3211 case OSQLParseNode::sql_not
:
3212 case OSQLParseNode::manipulative_statement
:
3213 case OSQLParseNode::value_exp_commalist
:
3214 case OSQLParseNode::union_statement
:
3215 case OSQLParseNode::outer_join_type
:
3216 case OSQLParseNode::selection
:
3217 case OSQLParseNode::base_table_def
:
3218 case OSQLParseNode::base_table_element_commalist
:
3219 case OSQLParseNode::data_type
:
3220 case OSQLParseNode::column_def
:
3221 case OSQLParseNode::table_node
:
3222 case OSQLParseNode::as_clause
:
3223 case OSQLParseNode::opt_as
:
3224 case OSQLParseNode::op_column_commalist
:
3225 case OSQLParseNode::table_primary_as_range_column
:
3226 case OSQLParseNode::character_string_type
:
3227 case OSQLParseNode::comparison
:
3228 OSL_FAIL("Unexpected SQL RuleID");
3230 case OSQLParseNode::column
:
3231 case OSQLParseNode::column_val
:
3232 OSL_FAIL("Cannot guess column type");
3234 case OSQLParseNode::values_or_query_spec
:
3235 OSL_FAIL("Cannot guess VALUES type");
3237 case OSQLParseNode::derived_column
:
3238 OSL_FAIL("Cannot guess computed column type");
3240 case OSQLParseNode::subquery
:
3241 OSL_FAIL("Cannot guess subquery return type");
3243 case OSQLParseNode::search_condition
:
3244 case OSQLParseNode::comparison_predicate
:
3245 case OSQLParseNode::between_predicate
:
3246 case OSQLParseNode::like_predicate
:
3247 case OSQLParseNode::test_for_null
:
3248 case OSQLParseNode::boolean_term
:
3249 case OSQLParseNode::boolean_primary
:
3250 case OSQLParseNode::in_predicate
:
3251 case OSQLParseNode::existence_test
:
3252 case OSQLParseNode::unique_test
:
3253 case OSQLParseNode::all_or_any_predicate
:
3254 case OSQLParseNode::join_condition
:
3255 case OSQLParseNode::boolean_factor
:
3256 case OSQLParseNode::comparison_predicate_part_2
:
3257 case OSQLParseNode::parenthesized_boolean_value_expression
:
3258 case OSQLParseNode::other_like_predicate_part_2
:
3259 case OSQLParseNode::between_predicate_part_2
:
3260 nDataType
= DataType::BOOLEAN
;
3262 case OSQLParseNode::num_value_exp
:
3263 case OSQLParseNode::extract_exp
:
3264 case OSQLParseNode::term
:
3265 case OSQLParseNode::factor
:
3266 // Might by an integer or a float; take the most generic
3267 nDataType
= DataType::DOUBLE
;
3269 case OSQLParseNode::value_exp_primary
:
3270 case OSQLParseNode::value_exp
:
3271 case OSQLParseNode::odbc_call_spec
:
3272 // Really, we don't know. Let the default.
3274 case OSQLParseNode::position_exp
:
3275 case OSQLParseNode::length_exp
:
3276 nDataType
= DataType::INTEGER
;
3278 case OSQLParseNode::char_value_exp
:
3279 case OSQLParseNode::char_value_fct
:
3280 case OSQLParseNode::fold
:
3281 case OSQLParseNode::char_substring_fct
:
3282 case OSQLParseNode::char_factor
:
3283 case OSQLParseNode::concatenation
:
3284 nDataType
= DataType::VARCHAR
;
3286 case OSQLParseNode::datetime_primary
:
3287 nDataType
= DataType::TIMESTAMP
;
3289 case OSQLParseNode::bit_value_fct
:
3290 nDataType
= DataType::BINARY
;
3292 case OSQLParseNode::general_set_fct
: // May depend on argument; ignore that for now
3293 case OSQLParseNode::set_fct_spec
:
3295 if (pNode
->count() == 0)
3297 // This is not a function call, no sense to continue with a function return type lookup
3298 OSL_FAIL("Got leaf SQL node where non-leaf expected");
3301 const OSQLParseNode
* pFunctionName
= pNode
->getChild(0);
3302 if ( SQL_ISPUNCTUATION(pFunctionName
,"{") )
3304 if ( pNode
->count() == 3 )
3305 return fillFunctionInfo( pNode
->getChild(1), sFunctionTerm
, aInfo
);
3307 OSL_FAIL("ODBC escape not in recognised form");
3312 if ( SQL_ISRULEOR2(pNode
,length_exp
,char_value_fct
) )
3313 pFunctionName
= pFunctionName
->getChild(0);
3315 OUString sFunctionName
= pFunctionName
->getTokenValue();
3316 if ( sFunctionName
.isEmpty() )
3317 sFunctionName
= OStringToOUString(OSQLParser::TokenIDToStr(pFunctionName
->getTokenID()),RTL_TEXTENCODING_UTF8
);
3319 nDataType
= OSQLParser::getFunctionReturnType(
3321 ,&rController
.getParser().getContext());
3325 case OSQLParseNode::odbc_fct_spec
:
3327 if (pNode
->count() != 2)
3329 OSL_FAIL("interior of ODBC escape not in recognised shape");
3333 const OSQLParseNode
* const pEscapeType
= pNode
->getChild(0);
3334 if (SQL_ISTOKEN(pEscapeType
, TS
))
3335 nDataType
= DataType::TIMESTAMP
;
3336 else if (SQL_ISTOKEN(pEscapeType
, D
))
3337 nDataType
= DataType::DATE
;
3338 else if (SQL_ISTOKEN(pEscapeType
, T
))
3339 nDataType
= DataType::TIME
;
3340 else if (SQL_ISTOKEN(pEscapeType
, FN
))
3341 return fillFunctionInfo( pNode
->getChild(1), sFunctionTerm
, aInfo
);
3343 OSL_FAIL("Unknown ODBC escape");
3346 case OSQLParseNode::cast_spec
:
3348 if ( pNode
->count() != 6 || !SQL_ISTOKEN(pNode
->getChild(3), AS
) )
3350 OSL_FAIL("CAST not in recognised shape");
3353 const OSQLParseNode
*pCastTarget
= pNode
->getChild(4);
3354 if ( SQL_ISTOKENOR2(pCastTarget
, INTEGER
, INT
) )
3355 nDataType
= DataType::INTEGER
;
3356 else if ( SQL_ISTOKEN(pCastTarget
, SMALLINT
) )
3357 nDataType
= DataType::SMALLINT
;
3358 else if ( SQL_ISTOKEN(pCastTarget
, BIGINT
) )
3359 nDataType
= DataType::BIGINT
;
3360 else if ( SQL_ISTOKEN(pCastTarget
, FLOAT
) )
3361 nDataType
= DataType::FLOAT
;
3362 else if ( SQL_ISTOKEN(pCastTarget
, REAL
) )
3363 nDataType
= DataType::REAL
;
3364 else if ( SQL_ISTOKEN(pCastTarget
, DOUBLE
) )
3365 nDataType
= DataType::DOUBLE
;
3366 else if ( SQL_ISTOKEN(pCastTarget
, BOOLEAN
) )
3367 nDataType
= DataType::BOOLEAN
;
3368 else if ( SQL_ISTOKEN(pCastTarget
, DATE
) )
3369 nDataType
= DataType::DATE
;
3370 else if ( pCastTarget
->count() > 0 )
3372 const OSQLParseNode
*pDataType
= pCastTarget
->getChild(0);
3373 while (pDataType
->count() > 0)
3375 pCastTarget
= pDataType
;
3376 pDataType
= pDataType
->getChild(0);
3378 if ( SQL_ISTOKEN (pDataType
, TIME
) )
3379 nDataType
= DataType::TIME
;
3380 else if ( SQL_ISTOKEN (pDataType
, TIMESTAMP
) )
3381 nDataType
= DataType::TIMESTAMP
;
3382 else if ( SQL_ISTOKENOR3 (pDataType
, CHARACTER
, CHAR
, NCHAR
) )
3383 nDataType
= char_datatype(pCastTarget
, 0);
3384 else if ( SQL_ISTOKEN (pDataType
, VARCHAR
) )
3385 nDataType
= DataType::VARCHAR
;
3386 else if ( SQL_ISTOKEN (pDataType
, CLOB
) )
3387 nDataType
= DataType::CLOB
;
3388 else if ( SQL_ISTOKEN (pDataType
, NATIONAL
) )
3389 nDataType
= char_datatype(pCastTarget
, 1);
3390 else if ( SQL_ISTOKEN (pDataType
, BINARY
) )
3392 if ( pCastTarget
->count() > 2 && SQL_ISTOKEN(pCastTarget
->getChild(1), LARGE
) && SQL_ISTOKEN(pCastTarget
->getChild(2), OBJECT
) )
3393 nDataType
= DataType::BLOB
;
3394 else if ( pCastTarget
->count() > 1 && SQL_ISTOKEN(pCastTarget
->getChild(1), VARYING
) )
3395 nDataType
= DataType::VARBINARY
;
3397 nDataType
= DataType::BINARY
;
3399 else if ( SQL_ISTOKEN (pDataType
, VARBINARY
) )
3400 nDataType
= DataType::VARBINARY
;
3401 else if ( SQL_ISTOKEN (pDataType
, BLOB
) )
3402 nDataType
= DataType::BLOB
;
3403 else if ( SQL_ISTOKEN (pDataType
, NUMERIC
) )
3404 nDataType
= DataType::NUMERIC
;
3405 else if ( SQL_ISTOKENOR2 (pDataType
, DECIMAL
, DEC
) )
3406 nDataType
= DataType::DECIMAL
;
3407 else if ( SQL_ISTOKEN (pDataType
, FLOAT
) )
3408 nDataType
= DataType::FLOAT
;
3409 else if ( SQL_ISTOKEN (pDataType
, DOUBLE
) )
3410 nDataType
= DataType::DOUBLE
;
3411 else if ( SQL_ISTOKEN (pDataType
, INTERVAL
) )
3412 // Not in DataType published constant (because not in JDBC...)
3413 nDataType
= DataType::VARCHAR
;
3415 OSL_FAIL("Failed to decode CAST target");
3418 OSL_FAIL("Could not decipher CAST target");
3422 OSL_FAIL("Unknown SQL RuleID");
3427 OSL_FAIL("Unknown SQL Node Type");
3431 aInfo
->SetDataType(nDataType
);
3432 aInfo
->SetFieldType(TAB_NORMAL_FIELD
);
3433 aInfo
->SetField(sFunctionTerm
);
3434 aInfo
->SetTabWindow(nullptr);
3437 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */