Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name QueryDesignView.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D DBACCESS_DLLIMPLEMENTATION -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/external/unixODBC/inc -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/dbaccess/inc -I /home/maarten/src/libreoffice/core/dbaccess/source/inc -I /home/maarten/src/libreoffice/core/dbaccess/source/ui/inc -I /home/maarten/src/libreoffice/core/workdir/YaccTarget/connectivity/source/parse -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx

/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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 <tools/diagnose_ex.h>
27#include <o3tl/safeint.hxx>
28#include <osl/diagnose.h>
29#include <vcl/svapp.hxx>
30#include <vcl/weld.hxx>
31#include <browserids.hxx>
32#include "SelectionBrowseBox.hxx"
33#include <strings.hrc>
34#include <strings.hxx>
35#include <comphelper/string.hxx>
36#include <connectivity/dbtools.hxx>
37#include <connectivity/dbexception.hxx>
38#include <com/sun/star/sdbc/DataType.hpp>
39#include <com/sun/star/container/XNameAccess.hpp>
40#include <com/sun/star/sdbc/ColumnValue.hpp>
41#include <connectivity/PColumn.hxx>
42#include "QTableConnection.hxx"
43#include <ConnectionLineData.hxx>
44#include "QTableConnectionData.hxx"
45#include <core_resource.hxx>
46#include <UITools.hxx>
47#include <querycontainerwindow.hxx>
48#include <unotools/localedatawrapper.hxx>
49#include <unotools/syslocale.hxx>
50#include <memory>
51#include <set>
52
53using namespace ::dbaui;
54using namespace ::utl;
55using namespace ::connectivity;
56using namespace ::dbtools;
57using namespace ::com::sun::star::uno;
58using namespace ::com::sun::star::lang;
59using namespace ::com::sun::star::i18n;
60using namespace ::com::sun::star::sdbc;
61using namespace ::com::sun::star::beans;
62using namespace ::com::sun::star::container;
63
64// here we define our functions used in the anonymous namespace to get our header file smaller
65// please look at the book LargeScale C++ to know why
66namespace
67{
68 const char C_AND[] = " AND ";
69 const char C_OR[] = " OR ";
70
71 bool InsertJoin( const OQueryDesignView* _pView,
72 const ::connectivity::OSQLParseNode *pNode);
73
74 SqlParseError InstallFields(OQueryDesignView* _pView,
75 const ::connectivity::OSQLParseNode* pNode,
76 OJoinTableView::OTableWindowMap* pTabList );
77
78 SqlParseError GetGroupCriteria( OQueryDesignView* _pView,
79 OSelectionBrowseBox* _pSelectionBrw,
80 const ::connectivity::OSQLParseNode* pSelectRoot );
81
82 SqlParseError GetHavingCriteria(OQueryDesignView* _pView,
83 OSelectionBrowseBox* _pSelectionBrw,
84 const ::connectivity::OSQLParseNode* pSelectRoot,
85 sal_uInt16& rLevel );
86
87 SqlParseError GetOrderCriteria( OQueryDesignView* _pView,
88 OSelectionBrowseBox* _pSelectionBrw,
89 const ::connectivity::OSQLParseNode* pParseRoot );
90
91 SqlParseError AddFunctionCondition(OQueryDesignView const * _pView,
92 OSelectionBrowseBox* _pSelectionBrw,
93 const ::connectivity::OSQLParseNode * pCondition,
94 const sal_uInt16 nLevel,
95 bool bHaving,
96 bool _bAddOrOnOneLine);
97
98 OUString quoteTableAlias(bool _bQuote, const OUString& _sAliasName, const OUString& _sQuote)
99 {
100 OUString sRet;
101 if ( _bQuote && !_sAliasName.isEmpty() )
102 {
103 sRet = ::dbtools::quoteName(_sQuote,_sAliasName) + ".";
104 }
105 return sRet;
106 }
107 OUString getTableRange(const OQueryDesignView* _pView,const ::connectivity::OSQLParseNode* _pTableRef)
108 {
109 Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
110 OUString sTableRange;
111 if ( _pTableRef )
112 {
113 sTableRange = ::connectivity::OSQLParseNode::getTableRange(_pTableRef);
114 if ( sTableRange.isEmpty() )
115 _pTableRef->parseNodeToStr(sTableRange,xConnection,nullptr,false,false);
116 }
117 return sTableRange;
118 }
119 void insertConnection(const OQueryDesignView* _pView,const EJoinType& _eJoinType, const OTableFieldDescRef& _aDragLeft, const OTableFieldDescRef& _aDragRight, bool _bNatural = false)
120 {
121 OQueryTableView* pTableView = static_cast<OQueryTableView*>(_pView->getTableView());
122 OQueryTableConnection* pConn = static_cast<OQueryTableConnection*>( pTableView->GetTabConn(static_cast<OTableWindow*>(_aDragLeft->GetTabWindow()),static_cast<OTableWindow*>(_aDragRight->GetTabWindow()),true));
123
124 if ( !pConn )
125 {
126 auto xInfoData = std::make_shared<OQueryTableConnectionData>();
127 xInfoData->InitFromDrag(_aDragLeft, _aDragRight);
128 xInfoData->SetJoinType(_eJoinType);
129
130 if ( _bNatural )
131 {
132 xInfoData->ResetConnLines();
133 xInfoData->setNatural(_bNatural);
134 try
135 {
136 Reference<XNameAccess> xReferencedTableColumns(xInfoData->getReferencedTable()->getColumns());
137 Sequence< OUString> aSeq = xInfoData->getReferencingTable()->getColumns()->getElementNames();
138 const OUString* pIter = aSeq.getConstArray();
139 const OUString* pEnd = pIter + aSeq.getLength();
140 for(;pIter != pEnd;++pIter)
141 {
142 if ( xReferencedTableColumns->hasByName(*pIter) )
143 xInfoData->AppendConnLine(*pIter,*pIter);
144 }
145 }
146 catch( const Exception& )
147 {
148 DBG_UNHANDLED_EXCEPTION("dbaccess")DbgUnhandledException( DbgGetCaughtException(), __func__, "/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "148" ": ", "dbaccess" );
;
149 }
150 }
151
152 ScopedVclPtrInstance< OQueryTableConnection > aInfo(pTableView, xInfoData);
153 // Because OQueryTableConnection never takes ownership of the data passed to it, but only remembers the pointer,
154 // this pointer to a local variable is not critical, as xInfoData and aInfo have the same lifetime
155 pTableView->NotifyTabConnection( *aInfo );
156 }
157 else
158 {
159 OUString aSourceFieldName(_aDragLeft->GetField());
160 OUString aDestFieldName(_aDragRight->GetField());
161 // the connection could point on the other side
162 if(pConn->GetSourceWin() == _aDragRight->GetTabWindow())
163 {
164 OUString aTmp(aSourceFieldName);
165 aSourceFieldName = aDestFieldName;
166 aDestFieldName = aTmp;
167 }
168 pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName);
169 pConn->UpdateLineList();
170 // Modified-Flag
171 // SetModified();
172 // and redraw
173 pConn->RecalcLines();
174 // for the following Invalidate, the new Connection must first be able
175 // to determine its BoundingRect
176 pConn->InvalidateConnection();
177 }
178 }
179 OUString ParseCondition( OQueryController& rController
180 ,const ::connectivity::OSQLParseNode* pCondition
181 ,const OUString& _sDecimal
182 ,const css::lang::Locale& _rLocale
183 ,sal_uInt32 _nStartIndex)
184 {
185 OUString aCondition;
186 Reference< XConnection> xConnection = rController.getConnection();
187 if ( xConnection.is() )
188 {
189 sal_uInt32 nCount = pCondition->count();
190 for(sal_uInt32 i = _nStartIndex ; i < nCount ; ++i)
191 pCondition->getChild(i)->parseNodeToPredicateStr(aCondition,
192 xConnection,
193 rController.getNumberFormatter(),
194 _rLocale,
195 _sDecimal,
196 &rController.getParser().getContext());
197 }
198 return aCondition;
199 }
200 SqlParseError FillOuterJoins(OQueryDesignView const * _pView,
201 const ::connectivity::OSQLParseNode* pTableRefList)
202 {
203 SqlParseError eErrorCode = eOk;
204 sal_uInt32 nCount = pTableRefList->count();
205 bool bError = false;
206 for (sal_uInt32 i=0; !bError && i < nCount; ++i)
207 {
208 const ::connectivity::OSQLParseNode* pParseNode = pTableRefList->getChild(i);
209 const ::connectivity::OSQLParseNode* pJoinNode = nullptr;
210
211 if ( SQL_ISRULE( pParseNode, qualified_join )((pParseNode)->isRule() && (pParseNode)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::qualified_join))
|| SQL_ISRULE( pParseNode, joined_table )((pParseNode)->isRule() && (pParseNode)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::joined_table))
|| SQL_ISRULE( pParseNode, cross_union )((pParseNode)->isRule() && (pParseNode)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::cross_union))
)
212 pJoinNode = pParseNode;
213 else if( SQL_ISRULE(pParseNode,table_ref)((pParseNode)->isRule() && (pParseNode)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::table_ref))
214 && pParseNode->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
215 pJoinNode = pParseNode->getChild(2);
216
217 if ( pJoinNode )
218 {
219 if ( !InsertJoin(_pView,pJoinNode) )
220 bError = true;
221 }
222 }
223 // check if error occurred
224 if ( bError )
225 eErrorCode = eIllegalJoin;
226
227 return eErrorCode;
228 }
229
230 /** FillDragInfo fills the field description out of the table
231 */
232 SqlParseError FillDragInfo( const OQueryDesignView* _pView,
233 const ::connectivity::OSQLParseNode* pColumnRef,
234 OTableFieldDescRef const & _rDragInfo)
235 {
236 SqlParseError eErrorCode = eOk;
237
238 bool bErg = false;
239
240 OUString aTableRange,aColumnName;
241 ::connectivity::OSQLParseTreeIterator& rParseIter = static_cast<OQueryController&>(_pView->getController()).getParseIterator();
242 rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange );
243
244 if ( !aTableRange.isEmpty() )
245 {
246 OQueryTableWindow* pSTW = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( aTableRange );
247 bErg = (pSTW && pSTW->ExistsField( aColumnName, _rDragInfo ) );
248 }
249 if ( !bErg )
250 {
251 sal_uInt16 nCntAccount;
252 bErg = static_cast<OQueryTableView*>(_pView->getTableView())->FindTableFromField(aColumnName, _rDragInfo, nCntAccount);
253 if ( !bErg )
254 bErg = _pView->HasFieldByAliasName(aColumnName, _rDragInfo);
255 }
256 if ( !bErg )
257 {
258 eErrorCode = eColumnNotFound;
259 OUString sError(DBA_RES(STR_QRY_COLUMN_NOT_FOUND)::dbaccess::ResourceManager::loadString( reinterpret_cast<
char const *>("STR_QRY_COLUMN_NOT_FOUND" "\004" u8"The column '$name$' is unknown."
) )
);
260 sError = sError.replaceFirst("$name$",aColumnName);
261 _pView->getController().appendError( sError );
262
263 try
264 {
265 Reference<XDatabaseMetaData> xMeta = _pView->getController().getConnection()->getMetaData();
266 if ( xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() )
267 _pView->getController().appendError(DBA_RES(STR_QRY_CHECK_CASESENSITIVE)::dbaccess::ResourceManager::loadString( reinterpret_cast<
char const *>("STR_QRY_CHECK_CASESENSITIVE" "\004" u8"The column could not be found. Please note that the database is case-sensitive."
) )
);
268 }
269 catch(Exception&)
270 {
271 }
272 }
273
274 return eErrorCode;
275 }
276 OUString BuildJoinCriteria( const Reference< XConnection>& _xConnection,
277 const OConnectionLineDataVec* pLineDataList,
278 const OQueryTableConnectionData* pData)
279 {
280 OUStringBuffer aCondition;
281 if ( _xConnection.is() )
282 {
283 try
284 {
285 const Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData();
286 const OUString aQuote = xMetaData->getIdentifierQuoteString();
287
288 for (auto const& lineData : *pLineDataList)
289 {
290 if(!aCondition.isEmpty())
291 aCondition.append(C_AND);
292 aCondition.append(quoteTableAlias(true,pData->GetAliasName(JTCS_FROM),aQuote));
293 aCondition.append(::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_FROM) ));
294 aCondition.append(" = ");
295 aCondition.append(quoteTableAlias(true,pData->GetAliasName(JTCS_TO),aQuote));
296 aCondition.append(::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_TO) ));
297 }
298 }
299 catch(SQLException&)
300 {
301 OSL_FAIL("Failure while building Join criteria!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "301" ": "), "%s", "Failure while building Join criteria!"
); } } while (false)
;
302 }
303 }
304
305 return aCondition.makeStringAndClear();
306 }
307 /** JoinCycle looks for a join cycle and append it to the string
308 @param _xConnection the connection
309 @param _pEntryConn the table connection which holds the data
310 @param _pEntryTabTo the corresponding table window
311 @param _rJoin the String which will contain the resulting string
312 */
313 void JoinCycle( const Reference< XConnection>& _xConnection,
314 OQueryTableConnection* _pEntryConn,
315 const OQueryTableWindow* _pEntryTabTo,
316 OUString& _rJoin )
317 {
318 OSL_ENSURE(_pEntryConn,"TableConnection can not be null!")do { if (true && (!(_pEntryConn))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "318" ": "), "%s", "TableConnection can not be null!"); }
} while (false)
;
319
320 OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pEntryConn->GetData().get());
321 if ( !(pData->GetJoinType() != INNER_JOIN && _pEntryTabTo->ExistsAVisitedConn()) )
322 return;
323
324 bool bBrace = false;
325 if(_rJoin.endsWith(")"))
326 {
327 bBrace = true;
328 _rJoin = _rJoin.replaceAt(_rJoin.getLength()-1,1,OUString(' '));
329 }
330 _rJoin += C_AND + BuildJoinCriteria(_xConnection,&pData->GetConnLineDataList(),pData);
331 if(bBrace)
332 _rJoin += ")";
333 _pEntryConn->SetVisited(true);
334 }
335 OUString BuildTable( const Reference< XConnection>& _xConnection,
336 const OQueryTableWindow* pEntryTab,
337 bool _bForce = false
338 )
339 {
340 OUString aDBName(pEntryTab->GetComposedName());
341
342 if( _xConnection.is() )
343 {
344 try
345 {
346 Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData();
347
348 OUString sCatalog, sSchema, sTable;
349 ::dbtools::qualifiedNameComponents( xMetaData, aDBName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
350 OUString aTableListStr = ::dbtools::composeTableNameForSelect( _xConnection, sCatalog, sSchema, sTable );
351
352 OUString aQuote = xMetaData->getIdentifierQuoteString();
353 if ( _bForce || isAppendTableAliasEnabled( _xConnection ) || pEntryTab->GetAliasName() != aDBName )
354 {
355 aTableListStr += " ";
356 if ( generateAsBeforeTableAlias( _xConnection ) )
357 aTableListStr += "AS ";
358 aTableListStr += ::dbtools::quoteName( aQuote, pEntryTab->GetAliasName() );
359 }
360 aDBName = aTableListStr;
361 }
362 catch(const SQLException&)
363 {
364 DBG_UNHANDLED_EXCEPTION("dbaccess")DbgUnhandledException( DbgGetCaughtException(), __func__, "/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "364" ": ", "dbaccess" );
;
365 }
366 }
367 return aDBName;
368 }
369 OUString BuildJoin( const Reference< XConnection>& _xConnection,
370 const OUString& rLh,
371 const OUString& rRh,
372 const OQueryTableConnectionData* pData)
373 {
374
375 OUString aErg(rLh);
376 if ( pData->isNatural() && pData->GetJoinType() != CROSS_JOIN )
377 aErg += " NATURAL ";
378 switch(pData->GetJoinType())
379 {
380 case LEFT_JOIN:
381 aErg += " LEFT OUTER ";
382 break;
383 case RIGHT_JOIN:
384 aErg += " RIGHT OUTER ";
385 break;
386 case CROSS_JOIN:
387 OSL_ENSURE(!pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!")do { if (true && (!(!pData->isNatural()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "387" ": "), "%s", "OQueryDesignView::BuildJoin: This should not happen!"
); } } while (false)
;
388 aErg += " CROSS ";
389 break;
390 case INNER_JOIN:
391 OSL_ENSURE(pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!")do { if (true && (!(pData->isNatural()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "391" ": "), "%s", "OQueryDesignView::BuildJoin: This should not happen!"
); } } while (false)
;
392 aErg += " INNER ";
393 break;
394 default:
395 aErg += " FULL OUTER ";
396 break;
397 }
398 aErg += "JOIN " + rRh;
399 if ( CROSS_JOIN != pData->GetJoinType() && !pData->isNatural() )
400 {
401 aErg += " ON " + BuildJoinCriteria(_xConnection,&pData->GetConnLineDataList(),pData);
402 }
403
404 return aErg;
405 }
406 OUString BuildJoin( const Reference< XConnection>& _xConnection,
407 const OQueryTableWindow* pLh,
408 const OQueryTableWindow* pRh,
409 const OQueryTableConnectionData* pData
410 )
411 {
412 bool bForce = pData->GetJoinType() == CROSS_JOIN || pData->isNatural();
413 return BuildJoin(_xConnection,BuildTable(_xConnection,pLh,bForce),BuildTable(_xConnection,pRh,bForce),pData);
414 }
415 OUString BuildJoin( const Reference< XConnection>& _xConnection,
416 const OUString &rLh,
417 const OQueryTableWindow* pRh,
418 const OQueryTableConnectionData* pData
419 )
420 {
421 return BuildJoin(_xConnection,rLh,BuildTable(_xConnection,pRh),pData);
422 }
423 OUString BuildJoin( const Reference< XConnection>& _xConnection,
424 const OQueryTableWindow* pLh,
425 const OUString &rRh,
426 const OQueryTableConnectionData* pData
427 )
428 {
429 // strict ANSI SQL:
430 // - does not support any bracketing of JOINS
431 // - supports nested joins only in the LEFT HAND SIDE
432 // In this case, we are trying to build a join with a nested join
433 // in the right hand side.
434 // So switch the direction of the join and both hand sides.
435 OQueryTableConnectionData data(*pData);
436 switch (data.GetJoinType())
437 {
438 case LEFT_JOIN:
439 data.SetJoinType(RIGHT_JOIN);
440 break;
441 case RIGHT_JOIN:
442 data.SetJoinType(LEFT_JOIN);
443 break;
444 default:
445 // the other join types are symmetric, so nothing to change
446 break;
447 }
448 return BuildJoin(_xConnection, rRh, BuildTable(_xConnection,pLh), &data);
449 }
450 void addConnectionTableNames( const Reference< XConnection>& _xConnection,
451 const OQueryTableConnection* const pEntryConn,
452 std::set<OUString> &_rTableNames )
453 {
454 // insert tables into table list to avoid double entries
455 const OQueryTableWindow* const pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
456 const OQueryTableWindow* const pEntryTabTo = static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin());
457 _rTableNames.insert(BuildTable(_xConnection,pEntryTabFrom));
458 _rTableNames.insert(BuildTable(_xConnection,pEntryTabTo));
459 }
460 void GetNextJoin( const Reference< XConnection>& _xConnection,
461 OQueryTableConnection* pEntryConn,
462 OQueryTableWindow const * pEntryTabTo,
463 OUString &aJoin,
464 std::set<OUString> &_rTableNames)
465 {
466 OQueryTableConnectionData* pEntryConnData = static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get());
467 if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() )
468 return;
469
470 if(aJoin.isEmpty())
471 {
472 addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
473 OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
474 aJoin = BuildJoin(_xConnection,pEntryTabFrom,pEntryTabTo,pEntryConnData);
475 }
476 else if(pEntryTabTo == pEntryConn->GetDestWin())
477 {
478 addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
479 aJoin = BuildJoin(_xConnection,aJoin,pEntryTabTo,pEntryConnData);
480 }
481 else if(pEntryTabTo == pEntryConn->GetSourceWin())
482 {
483 addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
484 aJoin = BuildJoin(_xConnection,pEntryTabTo,aJoin,pEntryConnData);
485 }
486
487 pEntryConn->SetVisited(true);
488
489 // first search for the "to" window
490 const auto& rConnections = pEntryConn->GetParent()->getTableConnections();
491 bool bFound = false;
492 for (auto const& connection : rConnections)
493 {
494 OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(connection.get());
495 if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabTo || pNext->GetDestWin() == pEntryTabTo))
496 {
497 OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabTo ? static_cast<OQueryTableWindow*>(pNext->GetDestWin()) : static_cast<OQueryTableWindow*>(pNext->GetSourceWin());
498 // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
499 JoinCycle(_xConnection,pNext,pEntryTab,aJoin);
500 if(!pNext->IsVisited())
501 GetNextJoin(_xConnection, pNext, pEntryTab, aJoin, _rTableNames);
502 bFound = true;
503 }
504 }
505
506 // when nothing found look for the "from" window
507 if(bFound)
508 return;
509
510 OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
511 for (auto const& connection : rConnections)
512 {
513 OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(connection.get());
514 if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabFrom || pNext->GetDestWin() == pEntryTabFrom))
515 {
516 OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabFrom ? static_cast<OQueryTableWindow*>(pNext->GetDestWin()) : static_cast<OQueryTableWindow*>(pNext->GetSourceWin());
517 // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
518 JoinCycle(_xConnection,pNext,pEntryTab,aJoin);
519 if(!pNext->IsVisited())
520 GetNextJoin(_xConnection, pNext, pEntryTab, aJoin, _rTableNames);
521 }
522 }
523 }
524 SqlParseError InsertJoinConnection( const OQueryDesignView* _pView,
525 const ::connectivity::OSQLParseNode *pNode,
526 const EJoinType& _eJoinType,
527 const ::connectivity::OSQLParseNode *pLeftTable,
528 const ::connectivity::OSQLParseNode *pRightTable)
529 {
530 SqlParseError eErrorCode = eOk;
531 if (pNode->count() == 3 && // statement between brackets
532 SQL_ISPUNCTUATION(pNode->getChild(0),"(")((pNode->getChild(0))->getNodeType() == SQLNodeType::Punctuation
&& (pNode->getChild(0))->getTokenValue() == ("("
))
&&
533 SQL_ISPUNCTUATION(pNode->getChild(2),")")((pNode->getChild(2))->getNodeType() == SQLNodeType::Punctuation
&& (pNode->getChild(2))->getTokenValue() == (")"
))
)
534 {
535 eErrorCode = InsertJoinConnection(_pView,pNode->getChild(1), _eJoinType,pLeftTable,pRightTable);
536 }
537 else if (SQL_ISRULEOR2(pNode,search_condition,boolean_term)((pNode)->isRule() && ( (pNode)->getRuleID() ==
OSQLParser::RuleID(OSQLParseNode::search_condition) || (pNode
)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::boolean_term
)))
&& // AND/OR-joints:
538 pNode->count() == 3)
539 {
540 // only allow AND joints
541 if (!SQL_ISTOKEN(pNode->getChild(1),AND)((pNode->getChild(1))->isToken() && (pNode->
getChild(1))->getTokenID() == SQL_TOKEN_AND)
)
542 eErrorCode = eIllegalJoinCondition;
543 else if ( eOk == (eErrorCode = InsertJoinConnection(_pView,pNode->getChild(0), _eJoinType,pLeftTable,pRightTable)) )
544 eErrorCode = InsertJoinConnection(_pView,pNode->getChild(2), _eJoinType,pLeftTable,pRightTable);
545 }
546 else if (SQL_ISRULE(pNode,comparison_predicate)((pNode)->isRule() && (pNode)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::comparison_predicate))
)
547 {
548 // only the comparison of columns is allowed
549 OSL_ENSURE(pNode->count() == 3,"OQueryDesignView::InsertJoinConnection: Error in Parse Tree")do { if (true && (!(pNode->count() == 3))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "549" ": "), "%s", "OQueryDesignView::InsertJoinConnection: Error in Parse Tree"
); } } while (false)
;
550 if (!(SQL_ISRULE(pNode->getChild(0),column_ref)((pNode->getChild(0))->isRule() && (pNode->getChild
(0))->getRuleID() == OSQLParser::RuleID(OSQLParseNode::column_ref
))
&&
551 SQL_ISRULE(pNode->getChild(2),column_ref)((pNode->getChild(2))->isRule() && (pNode->getChild
(2))->getRuleID() == OSQLParser::RuleID(OSQLParseNode::column_ref
))
&&
552 pNode->getChild(1)->getNodeType() == SQLNodeType::Equal))
553 {
554 OUString sError(DBA_RES(STR_QRY_JOIN_COLUMN_COMPARE)::dbaccess::ResourceManager::loadString( reinterpret_cast<
char const *>("STR_QRY_JOIN_COLUMN_COMPARE" "\004" u8"Columns can only be compared using '='."
) )
);
555 _pView->getController().appendError( sError );
556 return eIllegalJoin;
557 }
558
559 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
560 OTableFieldDescRef aDragRight = new OTableFieldDesc();
561 eErrorCode = FillDragInfo(_pView,pNode->getChild(0),aDragLeft);
562 if ( eOk != eErrorCode )
563 return eErrorCode;
564 eErrorCode = FillDragInfo(_pView,pNode->getChild(2),aDragRight);
565 if ( eOk != eErrorCode )
566 return eErrorCode;
567
568 if ( pLeftTable )
569 {
570 OQueryTableWindow* pLeftWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pLeftTable->getByRule(OSQLParseNode::table_ref) ));
571 if ( pLeftWindow == aDragLeft->GetTabWindow() )
572 insertConnection(_pView,_eJoinType,aDragLeft,aDragRight);
573 else
574 insertConnection(_pView,_eJoinType,aDragRight,aDragLeft);
575 }
576 else
577 insertConnection(_pView,_eJoinType,aDragLeft,aDragRight);
578 }
579 else
580 eErrorCode = eIllegalJoin;
581 return eErrorCode;
582 }
583 bool GetInnerJoinCriteria( const OQueryDesignView* _pView,
584 const ::connectivity::OSQLParseNode *pCondition)
585 {
586 return InsertJoinConnection(_pView,pCondition, INNER_JOIN,nullptr,nullptr) != eOk;
587 }
588 OUString GenerateSelectList( const OQueryDesignView* _pView,
589 OTableFields& _rFieldList,
590 bool bAlias)
591 {
592 Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
593 if ( !xConnection.is() )
594 return OUString();
595
596 OUStringBuffer aTmpStr,aFieldListStr;
597
598 bool bAsterisk = false;
599 int nVis = 0;
600 for (auto const& field : _rFieldList)
601 {
602 if ( field->IsVisible() )
603 {
604 if ( field->GetField().toChar() == '*' )
605 bAsterisk = true;
606 ++nVis;
607 }
608 }
609 if(nVis == 1)
610 bAsterisk = false;
611
612 try
613 {
614 const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
615 const OUString aQuote = xMetaData->getIdentifierQuoteString();
616
617 OJoinTableView::OTableWindowMap& rTabList = _pView->getTableView()->GetTabWinMap();
618
619 for (auto const& field : _rFieldList)
620 {
621 OUString rFieldName = field->GetField();
622 if ( !rFieldName.isEmpty() && field->IsVisible() )
623 {
624 aTmpStr = "";
625 const OUString rAlias = field->GetAlias();
626 const OUString rFieldAlias = field->GetFieldAlias();
627
628 aTmpStr.append(quoteTableAlias((bAlias || bAsterisk),rAlias,aQuote));
629
630 // if we have a none numeric field, the table alias could be in the name
631 // otherwise we are not allowed to do this (e.g. 0.1 * PRICE )
632 if ( !field->isOtherFunction() )
633 {
634 // we have to look if we have alias.* here but before we have to check if the column doesn't already exist
635 OTableFieldDescRef aInfo = new OTableFieldDesc();
636 for (auto const& table : rTabList)
637 {
638 OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get());
639
640 if ( pTabWin->ExistsField( rFieldName, aInfo ) )
641 {
642 rFieldName = aInfo->GetField();
643 break;
644 }
645 }
646 if ( ( rFieldName.toChar() != '*' ) && ( rFieldName.indexOf( aQuote ) == -1 ) )
647 {
648 OSL_ENSURE(!field->GetTable().isEmpty(),"No table field name!")do { if (true && (!(!field->GetTable().isEmpty()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "648" ": "), "%s", "No table field name!"); } } while (false
)
;
649 aTmpStr.append(::dbtools::quoteName(aQuote, rFieldName));
650 }
651 else
652 aTmpStr.append(rFieldName);
653 }
654 else
655 aTmpStr.append(rFieldName);
656
657 if ( field->isAggregateFunction() )
658 {
659 OSL_ENSURE(!field->GetFunction().isEmpty(),"Function name must not be empty! ;-(")do { if (true && (!(!field->GetFunction().isEmpty(
)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "659" ": "), "%s", "Function name must not be empty! ;-("
); } } while (false)
;
660 OUStringBuffer aTmpStr2( field->GetFunction());
661 aTmpStr2.append("(");
662 aTmpStr2.append(aTmpStr.makeStringAndClear());
663 aTmpStr2.append(")");
664 aTmpStr = aTmpStr2;
665 }
666
667 if (!rFieldAlias.isEmpty() &&
668 (rFieldName.toChar() != '*' ||
669 field->isNumericOrAggregateFunction() ||
670 field->isOtherFunction()))
671 {
672 aTmpStr.append(" AS ");
673 aTmpStr.append(::dbtools::quoteName(aQuote, rFieldAlias));
674 }
675 aFieldListStr.append(aTmpStr.makeStringAndClear());
676 aFieldListStr.append(", ");
677 }
678 }
679 if(!aFieldListStr.isEmpty())
680 aFieldListStr.setLength(aFieldListStr.getLength()-2);
681 }
682 catch(SQLException&)
683 {
684 OSL_FAIL("Failure while building select list!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "684" ": "), "%s", "Failure while building select list!"
); } } while (false)
;
685 }
686 return aFieldListStr.makeStringAndClear();
687 }
688 bool GenerateCriterias( OQueryDesignView const * _pView,
689 OUStringBuffer& rRetStr,
690 OUStringBuffer& rHavingStr,
691 OTableFields& _rFieldList,
692 bool bMulti )
693 {
694 Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
695 if(!xConnection.is())
696 return false;
697
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)
702 {
703 nMaxCriteria = std::max<sal_uInt16>(nMaxCriteria,static_cast<sal_uInt16>(field->GetCriteria().size()));
704 }
705 try
706 {
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 **
712
713 for (sal_uInt16 i=0 ; i < nMaxCriteria ; i++)
714 {
715 aHavingStr.clear();
716 aWhereStr.clear();
717
718 for (auto const& field : _rFieldList)
719 {
720 aFieldName = field->GetField();
721
722 if (aFieldName.isEmpty())
723 continue;
724 aCriteria = field->GetCriteria( i );
725 if ( !aCriteria.isEmpty() )
726 {
727 // * is not allowed to contain any filter, only when used in combination an aggregate function
728 if ( aFieldName.toChar() == '*' && field->isNoneFunction() )
729 {
730 // only show the messagebox the first time
731 if (!bCritsOnAsteriskWarning)
732 {
733 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(_pView->GetFrameWeld(),
734 VclMessageType::Warning, VclButtonsType::Ok,
735 DBA_RES(STR_QRY_CRITERIA_ON_ASTERISK)::dbaccess::ResourceManager::loadString( reinterpret_cast<
char const *>("STR_QRY_CRITERIA_ON_ASTERISK" "\004" u8"A condition cannot be applied to field [*]"
) )
));
736 xBox->run();
737 }
738 bCritsOnAsteriskWarning = true;
739 continue;
740 }
741 aWork = quoteTableAlias(bMulti,field->GetAlias(),aQuote);
742
743 if ( (field->GetFunctionType() & (FKT_OTHER|FKT_NUMERIC)) || (aFieldName.toChar() == '*') )
744 aWork += aFieldName;
745 else
746 aWork += ::dbtools::quoteName(aQuote, aFieldName);
747
748 if ( field->isAggregateFunction() || field->IsGroupBy() )
749 {
750 if (aHavingStr.isEmpty()) // no more criteria
751 aHavingStr += "("; // bracket
752 else
753 aHavingStr += C_AND;
754
755 if ( field->isAggregateFunction() )
756 {
757 OSL_ENSURE(!field->GetFunction().isEmpty(),"No function name for aggregate given!")do { if (true && (!(!field->GetFunction().isEmpty(
)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "757" ": "), "%s", "No function name for aggregate given!"
); } } while (false)
;
758 aHavingStr += field->GetFunction() + "(" + aWork + ")"; // bracket
759 }
760 else
761 aHavingStr += aWork;
762
763 OUString aErrorMsg;
764 Reference<XPropertySet> xColumn;
765 std::unique_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(field,aCriteria,aErrorMsg,xColumn));
766 if (pParseNode)
767 {
768 if (bMulti && !(field->isOtherFunction() || (aFieldName.toChar() == '*')))
769 pParseNode->replaceNodeValue(field->GetAlias(),aFieldName);
770 OUString sHavingStr = aHavingStr;
771
772 sal_uInt32 nCount = pParseNode->count();
773 for( sal_uInt32 node = 1 ; node < nCount ; ++node)
774 pParseNode->getChild(node)->parseNodeToStr( sHavingStr,
775 xConnection,
776 &rContext,
777 false,
778 !field->isOtherFunction());
779 aHavingStr = sHavingStr;
780 }
781 else
782 aHavingStr += aCriteria;
783 }
784 else
785 {
786 if ( aWhereStr.isEmpty() ) // no more criteria
787 aWhereStr += "("; // bracket
788 else
789 aWhereStr += C_AND;
790
791 aWhereStr += " ";
792 // aCriteria could have some German numbers so I have to be sure here
793 OUString aErrorMsg;
794 Reference<XPropertySet> xColumn;
795 std::unique_ptr< ::connectivity::OSQLParseNode> pParseNode( _pView->getPredicateTreeFromEntry(field,aCriteria,aErrorMsg,xColumn));
796 if (pParseNode)
797 {
798 if (bMulti && !(field->isOtherFunction() || (aFieldName.toChar() == '*')))
799 pParseNode->replaceNodeValue(field->GetAlias(),aFieldName);
800 OUString aWhere = aWhereStr;
801 pParseNode->parseNodeToStr( aWhere,
802 xConnection,
803 &rContext,
804 false,
805 !field->isOtherFunction() );
806 aWhereStr = aWhere;
807 }
808 else
809 {
810 aWhereStr += aWork + "=" + aCriteria;
811 }
812 }
813 }
814 // only once for each field
815 else if ( !i && field->isCondition() )
816 {
817 if (aWhereStr.isEmpty()) // no more criteria
818 aWhereStr += "("; // bracket
819 else
820 aWhereStr += C_AND;
821 aWhereStr += field->GetField();
822 }
823 }
824 if (!aWhereStr.isEmpty())
825 {
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
830 rRetStr.append('(');
831 rRetStr.append(aWhereStr);
832 }
833 if (!aHavingStr.isEmpty())
834 {
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);
841 }
842 }
843
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
848 }
849 catch(SQLException&)
850 {
851 OSL_FAIL("Failure while building where clause!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "851" ": "), "%s", "Failure while building where clause!"
); } } while (false)
;
852 }
853 return true;
854 }
855 SqlParseError GenerateOrder( OQueryDesignView const * _pView,
856 OTableFields& _rFieldList,
857 bool bMulti,
858 OUString& _rsRet)
859 {
860 const OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
861 const Reference< XConnection>& xConnection = rController.getConnection();
862 if ( !xConnection.is() )
863 return eNoConnection;
864
865 SqlParseError eErrorCode = eOk;
866
867 OUString aColumnName;
868 OUString aWorkStr;
869 try
870 {
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)
877 {
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 )
882 {
883 aColumnName = field->GetField();
884 if(aColumnName.toChar() == '*')
885 {
886 // only show the MessageBox the first time
887 if (!bCritsOnAsteriskWarning)
888 {
889 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(_pView->GetFrameWeld(),
890 VclMessageType::Warning, VclButtonsType::Ok,
891 DBA_RES(STR_QRY_ORDERBY_ON_ASTERISK)::dbaccess::ResourceManager::loadString( reinterpret_cast<
char const *>("STR_QRY_ORDERBY_ON_ASTERISK" "\004" u8"[*] cannot be used as a sort criterion."
) )
));
892 xBox->run();
893 }
894 bCritsOnAsteriskWarning = true;
895 continue;
896 }
897
898 if ( bColumnAliasInOrderBy && !field->GetFieldAlias().isEmpty() )
899 {
900 aWorkStr += ::dbtools::quoteName(aQuote, field->GetFieldAlias());
901 }
902 else if ( field->isNumericOrAggregateFunction() )
903 {
904 OSL_ENSURE(!field->GetFunction().isEmpty(),"Function name cannot be empty! ;-(")do { if (true && (!(!field->GetFunction().isEmpty(
)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "904" ": "), "%s", "Function name cannot be empty! ;-(")
; } } while (false)
;
905 aWorkStr += field->GetFunction() + "("
906 + quoteTableAlias(
907 bMulti, field->GetAlias(), aQuote);
908 // only quote column name when we don't have a numeric
909 if ( field->isNumeric() )
910 aWorkStr += aColumnName;
911 else
912 aWorkStr += ::dbtools::quoteName(aQuote, aColumnName);
913
914 aWorkStr += ")";
915 }
916 else if ( field->isOtherFunction() )
917 {
918 aWorkStr += aColumnName;
919 }
920 else
921 {
922 aWorkStr += quoteTableAlias(bMulti,field->GetAlias(),aQuote) + ::dbtools::quoteName(aQuote, aColumnName);
923 }
924 aWorkStr += " " + OUString( ";ASC;DESC" ).getToken( static_cast<sal_uInt16>(eOrder), ';' ) + ",";
925 }
926 }
927
928 {
929 OUString sTemp(comphelper::string::stripEnd(aWorkStr, ','));
930 aWorkStr = sTemp;
931 }
932
933 if ( !aWorkStr.isEmpty() )
934 {
935 const sal_Int32 nMaxOrder = xMetaData->getMaxColumnsInOrderBy();
936 if ( nMaxOrder && nMaxOrder < comphelper::string::getTokenCount(aWorkStr, ',') )
937 eErrorCode = eStatementTooLong;
938 else
939 {
940 _rsRet = " ORDER BY " + aWorkStr;
941 }
942 }
943 }
944 catch(SQLException&)
945 {
946 OSL_FAIL("Failure while building group by!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "946" ": "), "%s", "Failure while building group by!"); }
} while (false)
;
947 }
948
949 return eErrorCode;
950 }
951
952 void GenerateInnerJoinCriterias(const Reference< XConnection>& _xConnection,
953 OUString& _rJoinCrit,
954 const std::vector<VclPtr<OTableConnection> >& _rConnList)
955 {
956 for (auto const& connection : _rConnList)
957 {
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() )
961 {
962 if(!_rJoinCrit.isEmpty())
963 _rJoinCrit += C_AND;
964 _rJoinCrit += BuildJoinCriteria(_xConnection,&pEntryConnData->GetConnLineDataList(),pEntryConnData);
965 }
966 }
967 }
968 void searchAndAppendName(const Reference< XConnection>& _xConnection,
969 const OQueryTableWindow* _pTableWindow,
970 std::set<OUString>& _rTableNames,
971 OUString& _rsTableListStr
972 )
973 {
974 OUString sTabName(BuildTable(_xConnection,_pTableWindow));
975
976 if(_rTableNames.insert(sTabName).second)
977 {
978 _rsTableListStr += sTabName + ",";
979 }
980 }
981 OUString GenerateFromClause( const Reference< XConnection>& _xConnection,
982 const OQueryTableView::OTableWindowMap* pTabList,
983 const std::vector<VclPtr<OTableConnection> >& rConnList
984 )
985 {
986
987 OUString aTableListStr;
988 // used to avoid putting a table twice in FROM clause
989 std::set<OUString> aTableNames;
990
991 // generate outer join clause in from
992 if(!rConnList.empty())
993 {
994 std::map<OTableWindow*,sal_Int32> aConnectionCount;
995 auto aEnd = rConnList.end();
996 for (auto const& connection : rConnList)
997 {
998 static_cast<OQueryTableConnection*>(connection.get())->SetVisited(false);
999 ++aConnectionCount[connection->GetSourceWin()];
1000 ++aConnectionCount[connection->GetDestWin()];
1001 }
1002 std::multimap<sal_Int32 , OTableWindow*> aMulti;
1003 for (auto const& elem : aConnectionCount)
1004 {
1005 aMulti.emplace(elem.second,elem.first);
1006 }
1007
1008 const bool bUseEscape = ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_OUTERJOINESCAPE"EnableOuterJoinEscape" );
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)
1012 {
1013 auto aConIter = aRIter->second->getTableView()->getTableConnections(aRIter->second);
1014 for(;aConIter != aEnd;++aConIter)
1015 {
1016 OQueryTableConnection* pEntryConn = static_cast<OQueryTableConnection*>((*aConIter).get());
1017 if(!pEntryConn->IsVisited() && pEntryConn->GetSourceWin() == aRIter->second )
1018 {
1019 OUString aJoin;
1020 GetNextJoin(_xConnection,
1021 pEntryConn,
1022 static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin()),
1023 aJoin,
1024 aTableNames);
1025
1026 if(!aJoin.isEmpty())
1027 {
1028 OUString aStr;
1029 switch(static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get())->GetJoinType())
1030 {
1031 case LEFT_JOIN:
1032 case RIGHT_JOIN:
1033 case FULL_JOIN:
1034 {
1035 // create outer join
1036 if ( bUseEscape )
1037 aStr += "{ oj ";
1038 aStr += aJoin;
1039 if ( bUseEscape )
1040 aStr += " }";
1041 }
1042 break;
1043 default:
1044 aStr += aJoin;
1045 break;
1046 }
1047 aStr += ",";
1048 aTableListStr += aStr;
1049 }
1050 }
1051 }
1052 }
1053
1054 // and now all inner joins
1055 // these are implemented as
1056 // "FROM tbl1, tbl2 WHERE tbl1.col1=tlb2.col2"
1057 // rather than
1058 // "FROM tbl1 INNER JOIN tbl2 ON tbl1.col1=tlb2.col2"
1059 for (auto const& connection : rConnList)
1060 {
1061 OQueryTableConnection* pEntryConn = static_cast<OQueryTableConnection*>(connection.get());
1062 if(!pEntryConn->IsVisited())
1063 {
1064 searchAndAppendName(_xConnection,
1065 static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin()),
1066 aTableNames,
1067 aTableListStr);
1068
1069 searchAndAppendName(_xConnection,
1070 static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin()),
1071 aTableNames,
1072 aTableListStr);
1073 }
1074 }
1075 }
1076 // all tables that haven't a connection to anyone
1077 for (auto const& table : *pTabList)
1078 {
1079 const OQueryTableWindow* pEntryTab = static_cast<const OQueryTableWindow*>(table.second.get());
1080 if(!pEntryTab->ExistsAConn())
1081 {
1082 aTableListStr += BuildTable(_xConnection,pEntryTab) + ",";
1083 }
1084 }
1085
1086 if(!aTableListStr.isEmpty())
1087 aTableListStr = aTableListStr.replaceAt(aTableListStr.getLength()-1,1, OUString() );
1088 return aTableListStr;
1089 }
1090 OUString GenerateGroupBy(const OQueryDesignView* _pView,OTableFields& _rFieldList, bool bMulti )
1091 {
1092 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1093 const Reference< XConnection> xConnection = rController.getConnection();
1094 if(!xConnection.is())
1095 return OUString();
1096
1097 std::map< OUString,bool> aGroupByNames;
1098
1099 OUString aGroupByStr;
1100 try
1101 {
1102 const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
1103 const OUString aQuote = xMetaData->getIdentifierQuoteString();
1104
1105 for (auto const& field : _rFieldList)
1106 {
1107 if ( field->IsGroupBy() )
1108 {
1109 OSL_ENSURE(!field->GetField().isEmpty(),"No Field Name available!;-(")do { if (true && (!(!field->GetField().isEmpty()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1109" ": "), "%s", "No Field Name available!;-("); } } while
(false)
;
1110 OUString sGroupByPart = quoteTableAlias(bMulti,field->GetAlias(),aQuote);
1111
1112 // only quote the field name when it isn't calculated
1113 if ( field->isNoneFunction() )
1114 {
1115 sGroupByPart += ::dbtools::quoteName(aQuote, field->GetField());
1116 }
1117 else
1118 {
1119 OUString aTmp = field->GetField();
1120 OUString aErrorMsg;
1121 Reference<XPropertySet> xColumn;
1122 std::unique_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(field,aTmp,aErrorMsg,xColumn));
1123 if (pParseNode)
1124 {
1125 OUString sGroupBy;
1126 pParseNode->getChild(0)->parseNodeToStr( sGroupBy,
1127 xConnection,
1128 &rController.getParser().getContext(),
1129 false,
1130 !field->isOtherFunction());
1131 sGroupByPart += sGroupBy;
1132 }
1133 else
1134 sGroupByPart += field->GetField();
1135 }
1136 if ( aGroupByNames.find(sGroupByPart) == aGroupByNames.end() )
1137 {
1138 aGroupByNames.emplace(sGroupByPart,true);
1139 aGroupByStr += sGroupByPart + ",";
1140 }
1141 }
1142 }
1143 if ( !aGroupByStr.isEmpty() )
1144 {
1145 aGroupByStr = aGroupByStr.replaceAt(aGroupByStr.getLength()-1,1, OUString(' ') );
1146 OUString aGroupByStr2 = " GROUP BY " + aGroupByStr;
1147 aGroupByStr = aGroupByStr2;
1148 }
1149 }
1150 catch(SQLException&)
1151 {
1152 OSL_FAIL("Failure while building group by!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1152" ": "), "%s", "Failure while building group by!");
} } while (false)
;
1153 }
1154 return aGroupByStr;
1155 }
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 )
1166 {
1167 if (!pNode || !SQL_ISRULE(pNode, select_statement)((pNode)->isRule() && (pNode)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::select_statement))
)
1168 return eNoSelectStatement;
1169
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())
1174 return eOk;
1175
1176 // Next free sentence...
1177 SqlParseError eErrorCode = eOk;
1178 ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1);
1179 if ( pCondition ) // no where clause
1180 {
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);
1185
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);
1193
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);
1199
1200 // it could happen that pCondition is not more valid
1201 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pNodeTmp, rLevel);
1202 }
1203 return eErrorCode;
1204 }
1205 SqlParseError GetANDCriteria( OQueryDesignView* _pView,
1206 OSelectionBrowseBox* _pSelectionBrw,
1207 const ::connectivity::OSQLParseNode * pCondition,
1208 sal_uInt16& nLevel,
1209 bool bHaving,
1210 bool bAddOrOnOneLine);
1211 SqlParseError ComparisonPredicate(OQueryDesignView const * _pView,
1212 OSelectionBrowseBox* _pSelectionBrw,
1213 const ::connectivity::OSQLParseNode * pCondition,
1214 const sal_uInt16 nLevel,
1215 bool bHaving,
1216 bool bAddOrOnOneLine);
1217 SqlParseError GetORCriteria(OQueryDesignView* _pView,
1218 OSelectionBrowseBox* _pSelectionBrw,
1219 const ::connectivity::OSQLParseNode * pCondition,
1220 sal_uInt16& nLevel ,
1221 bool bHaving,
1222 bool bAddOrOnOneLine)
1223 {
1224 SqlParseError eErrorCode = eOk;
1225
1226 // round brackets around the printout
1227 if (pCondition->count() == 3 &&
1228 SQL_ISPUNCTUATION(pCondition->getChild(0),"(")((pCondition->getChild(0))->getNodeType() == SQLNodeType
::Punctuation && (pCondition->getChild(0))->getTokenValue
() == ("("))
&&
1229 SQL_ISPUNCTUATION(pCondition->getChild(2),")")((pCondition->getChild(2))->getNodeType() == SQLNodeType
::Punctuation && (pCondition->getChild(2))->getTokenValue
() == (")"))
)
1230 {
1231 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pCondition->getChild(1),nLevel,bHaving,bAddOrOnOneLine);
1232 }
1233 // OR condition
1234 // a searchcondition can only look like this: search_condition SQL_TOKEN_OR boolean_term
1235 else if (SQL_ISRULE(pCondition,search_condition)((pCondition)->isRule() && (pCondition)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::search_condition))
)
1236 {
1237 for (int i = 0; i < 3 && eErrorCode == eOk ; i+=2)
1238 {
1239 const ::connectivity::OSQLParseNode* pChild = pCondition->getChild(i);
1240 if ( SQL_ISRULE(pChild,search_condition)((pChild)->isRule() && (pChild)->getRuleID() ==
OSQLParser::RuleID(OSQLParseNode::search_condition))
)
1241 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pChild,nLevel,bHaving,bAddOrOnOneLine);
1242 else
1243 {
1244 eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pChild, nLevel,bHaving, i != 0 && bAddOrOnOneLine);
1245 if ( !bAddOrOnOneLine)
1246 nLevel++;
1247 }
1248 }
1249 }
1250 else
1251 eErrorCode = GetANDCriteria( _pView,_pSelectionBrw,pCondition, nLevel, bHaving,bAddOrOnOneLine );
1252
1253 return eErrorCode;
1254 }
1255 bool CheckOrCriteria(const ::connectivity::OSQLParseNode* _pCondition,::connectivity::OSQLParseNode* _pFirstColumnRef)
1256 {
1257 bool bRet = true;
1258 ::connectivity::OSQLParseNode* pFirstColumnRef = _pFirstColumnRef;
1259 for (size_t i = 0; bRet && i < _pCondition->count(); ++i)
1260 {
1261 const ::connectivity::OSQLParseNode* pChild = _pCondition->getChild(i);
1262 if ( pChild->isToken() )
1263 continue;
1264 else if ( SQL_ISRULE(pChild,search_condition)((pChild)->isRule() && (pChild)->getRuleID() ==
OSQLParser::RuleID(OSQLParseNode::search_condition))
)
1265 bRet = CheckOrCriteria(pChild,pFirstColumnRef);
1266 else
1267 {
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;
1274 }
1275 }
1276 return bRet;
1277 }
1278 SqlParseError GetANDCriteria( OQueryDesignView* _pView,
1279 OSelectionBrowseBox* _pSelectionBrw,
1280 const ::connectivity::OSQLParseNode * pCondition,
1281 sal_uInt16& nLevel,
1282 bool bHaving,
1283 bool bAddOrOnOneLine)
1284 {
1285 const css::lang::Locale aLocale = _pView->getLocale();
1286 const OUString sDecimal = _pView->getDecimalSeparator();
1287
1288 // I will need a cast pointer to my css::sdbcx::Container
1289 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1290 SqlParseError eErrorCode = eOk;
1291
1292 // round brackets
1293 if (SQL_ISRULE(pCondition,boolean_primary)((pCondition)->isRule() && (pCondition)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::boolean_primary))
)
1294 {
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)((pSearchCondition)->isRule() && (pSearchCondition
)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::search_condition
))
) // we have a or
1299 {
1300 _pSelectionBrw->DuplicateConditionLevel( nLevel);
1301 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(0), nLevel,bHaving,bMustAddOrOnOneLine );
1302 if ( eErrorCode == eOk )
1303 {
1304 ++nLevel;
1305 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(2), nLevel,bHaving,bMustAddOrOnOneLine );
1306 }
1307 }
1308 else
1309 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition, nLevel,bHaving,bMustAddOrOnOneLine );
1310 }
1311 // The first element is (again) an AND condition
1312 else if ( SQL_ISRULE(pCondition,boolean_term)((pCondition)->isRule() && (pCondition)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::boolean_term))
)
1313 {
1314 OSL_ENSURE(pCondition->count() == 3,"Illegal definition of boolean_term")do { if (true && (!(pCondition->count() == 3))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1314" ": "), "%s", "Illegal definition of boolean_term"
); } } while (false)
;
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 );
1318 }
1319 else if (SQL_ISRULE( pCondition, comparison_predicate)((pCondition)->isRule() && (pCondition)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::comparison_predicate)
)
)
1320 {
1321 eErrorCode = ComparisonPredicate(_pView,_pSelectionBrw,pCondition,nLevel,bHaving,bAddOrOnOneLine);
1322 }
1323 else if( SQL_ISRULE(pCondition,like_predicate)((pCondition)->isRule() && (pCondition)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::like_predicate))
)
1324 {
1325 const ::connectivity::OSQLParseNode* pValueExp = pCondition->getChild(0);
1326 if (SQL_ISRULE(pValueExp, column_ref )((pValueExp)->isRule() && (pValueExp)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::column_ref))
)
1327 {
1328 OUString aCondition;
1329 Reference< XConnection> xConnection = rController.getConnection();
1330 if ( xConnection.is() )
1331 {
1332 OUString aColumnName;
1333 // the international doesn't matter I have a string
1334 pCondition->parseNodeToPredicateStr(aCondition,
1335 xConnection,
1336 rController.getNumberFormatter(),
1337 aLocale,
1338 sDecimal,
1339 &rController.getParser().getContext());
1340
1341 pValueExp->parseNodeToPredicateStr( aColumnName,
1342 xConnection,
1343 rController.getNumberFormatter(),
1344 aLocale,
1345 sDecimal,
1346 &rController.getParser().getContext());
1347
1348 // don't display the column name
1349 aCondition = aCondition.copy(aColumnName.getLength());
1350 aCondition = aCondition.trim();
1351 }
1352
1353 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1354 if ( eOk == ( eErrorCode = FillDragInfo(_pView,pValueExp,aDragLeft) ))
1355 {
1356 if ( bHaving )
1357 aDragLeft->SetGroupBy(true);
1358 _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
1359 }
1360 }
1361 else if(SQL_ISRULEOR3(pValueExp, general_set_fct, set_fct_spec, position_exp)((pValueExp)->isRule() && ( (pValueExp)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::general_set_fct) || (
pValueExp)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::set_fct_spec) || (pValueExp)->getRuleID() == OSQLParser::
RuleID(OSQLParseNode::position_exp)))
||
1362 SQL_ISRULEOR3(pValueExp, extract_exp, fold, char_substring_fct)((pValueExp)->isRule() && ( (pValueExp)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::extract_exp) || (pValueExp
)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::fold) ||
(pValueExp)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::char_substring_fct)))
||
1363 SQL_ISRULEOR2(pValueExp, length_exp, char_value_fct)((pValueExp)->isRule() && ( (pValueExp)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::length_exp) || (pValueExp
)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::char_value_fct
)))
)
1364 {
1365 AddFunctionCondition( _pView,
1366 _pSelectionBrw,
1367 pCondition,
1368 nLevel,
1369 bHaving,
1370 bAddOrOnOneLine);
1371 }
1372 else
1373 {
1374 eErrorCode = eNoColumnInLike;
1375 OUString sError(DBA_RES(STR_QRY_LIKE_LEFT_NO_COLUMN)::dbaccess::ResourceManager::loadString( reinterpret_cast<
char const *>("STR_QRY_LIKE_LEFT_NO_COLUMN" "\004" u8"You must use a column name before 'LIKE'."
) )
);
1376 _pView->getController().appendError( sError );
1377 }
1378 }
1379 else if( SQL_ISRULEOR2(pCondition,test_for_null,in_predicate)((pCondition)->isRule() && ( (pCondition)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::test_for_null) || (pCondition
)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::in_predicate
)))
1380 || SQL_ISRULEOR2(pCondition,all_or_any_predicate,between_predicate)((pCondition)->isRule() && ( (pCondition)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::all_or_any_predicate)
|| (pCondition)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::between_predicate)))
)
1381 {
1382 if ( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , general_set_fct )((pCondition->getChild(0))->isRule() && ( (pCondition
->getChild(0))->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::set_fct_spec) || (pCondition->getChild(0))->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::general_set_fct)))
)
1383 {
1384 AddFunctionCondition( _pView,
1385 _pSelectionBrw,
1386 pCondition,
1387 nLevel,
1388 bHaving,
1389 bAddOrOnOneLine);
1390 }
1391 else if ( SQL_ISRULE(pCondition->getChild(0), column_ref )((pCondition->getChild(0))->isRule() && (pCondition
->getChild(0))->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::column_ref))
)
1392 {
1393 // parse condition
1394 OUString sCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,1);
1395 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1396 if ( eOk == ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(0),aDragLeft)) )
1397 {
1398 if ( bHaving )
1399 aDragLeft->SetGroupBy(true);
1400 _pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine);
1401 }
1402 }
1403 else
1404 {
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
1409 OUString sName;
1410 pCondition->getChild(0)->parseNodeToPredicateStr(sName,
1411 xConnection,
1412 rController.getNumberFormatter(),
1413 aLocale,
1414 sDecimal,
1415 &rController.getParser().getContext());
1416
1417 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1418 aDragLeft->SetField(sName);
1419 aDragLeft->SetFunctionType(FKT_OTHER);
1420
1421 if ( bHaving )
1422 aDragLeft->SetGroupBy(true);
1423 _pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine);
1424 }
1425 }
1426 else if( SQL_ISRULEOR2(pCondition,existence_test,unique_test)((pCondition)->isRule() && ( (pCondition)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::existence_test) || (pCondition
)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::unique_test
)))
)
1427 {
1428 // Parse the function condition
1429 OUString aCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,0);
1430
1431 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1432 aDragLeft->SetField(aCondition);
1433 aDragLeft->SetFunctionType(FKT_CONDITION);
1434
1435 eErrorCode = _pSelectionBrw->InsertField(aDragLeft,BROWSER_INVALIDID((sal_uInt16) 0xFFFF),false).is() ? eOk : eTooManyColumns;
1436 }
1437 else //! TODO not supported yet
1438 eErrorCode = eStatementTooComplex;
1439 // Pass on the error code
1440 return eErrorCode;
1441 }
1442 SqlParseError AddFunctionCondition(OQueryDesignView const * _pView,
1443 OSelectionBrowseBox* _pSelectionBrw,
1444 const ::connectivity::OSQLParseNode * pCondition,
1445 const sal_uInt16 nLevel,
1446 bool bHaving,
1447 bool bAddOrOnOneLine)
1448 {
1449 SqlParseError eErrorCode = eOk;
1450 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1451
1452 OSQLParseNode* pFunction = pCondition->getChild(0);
1453
1454 OSL_ENSURE(SQL_ISRULEOR3(pFunction, general_set_fct, set_fct_spec, position_exp) ||do { if (true && (!(((pFunction)->isRule() &&
( (pFunction)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::general_set_fct) || (pFunction)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::set_fct_spec) || (pFunction)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::position_exp))) || ((
pFunction)->isRule() && ( (pFunction)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::extract_exp) || (pFunction
)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::fold) ||
(pFunction)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::char_substring_fct))) || ((pFunction)->isRule() &&
( (pFunction)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::length_exp) || (pFunction)->getRuleID() == OSQLParser::RuleID
(OSQLParseNode::char_value_fct)))))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1457" ": "), "%s", "Illegal call!"); } } while (false)
1455 SQL_ISRULEOR3(pFunction, extract_exp, fold, char_substring_fct) ||do { if (true && (!(((pFunction)->isRule() &&
( (pFunction)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::general_set_fct) || (pFunction)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::set_fct_spec) || (pFunction)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::position_exp))) || ((
pFunction)->isRule() && ( (pFunction)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::extract_exp) || (pFunction
)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::fold) ||
(pFunction)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::char_substring_fct))) || ((pFunction)->isRule() &&
( (pFunction)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::length_exp) || (pFunction)->getRuleID() == OSQLParser::RuleID
(OSQLParseNode::char_value_fct)))))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1457" ": "), "%s", "Illegal call!"); } } while (false)
1456 SQL_ISRULEOR2(pFunction,length_exp,char_value_fct),do { if (true && (!(((pFunction)->isRule() &&
( (pFunction)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::general_set_fct) || (pFunction)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::set_fct_spec) || (pFunction)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::position_exp))) || ((
pFunction)->isRule() && ( (pFunction)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::extract_exp) || (pFunction
)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::fold) ||
(pFunction)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::char_substring_fct))) || ((pFunction)->isRule() &&
( (pFunction)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::length_exp) || (pFunction)->getRuleID() == OSQLParser::RuleID
(OSQLParseNode::char_value_fct)))))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1457" ": "), "%s", "Illegal call!"); } } while (false)
1457 "Illegal call!")do { if (true && (!(((pFunction)->isRule() &&
( (pFunction)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::general_set_fct) || (pFunction)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::set_fct_spec) || (pFunction)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::position_exp))) || ((
pFunction)->isRule() && ( (pFunction)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::extract_exp) || (pFunction
)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::fold) ||
(pFunction)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::char_substring_fct))) || ((pFunction)->isRule() &&
( (pFunction)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::length_exp) || (pFunction)->getRuleID() == OSQLParser::RuleID
(OSQLParseNode::char_value_fct)))))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1457" ": "), "%s", "Illegal call!"); } } while (false)
;
1458
1459 Reference< XConnection> xConnection = rController.getConnection();
1460 if(xConnection.is())
1461 {
1462 OUString aCondition;
1463 OUString aColumnName;
1464 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1465 pCondition->parseNodeToPredicateStr(aCondition,
1466 xConnection,
1467 rController.getNumberFormatter(),
1468 _pView->getLocale(),
1469 _pView->getDecimalSeparator(),
1470 &rController.getParser().getContext());
1471
1472 pFunction->parseNodeToStr( aColumnName,
1473 xConnection,
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);
1481
1482 if ( SQL_ISRULE(pFunction, general_set_fct )((pFunction)->isRule() && (pFunction)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::general_set_fct))
)
1483 {
1484 sal_Int32 nFunctionType = FKT_AGGREGATE;
1485 OSQLParseNode* pParamNode = pFunction->getChild(pFunction->count()-2);
1486 if ( pParamNode && pParamNode->getTokenValue().toChar() == '*' )
1487 {
1488 OJoinTableView::OTableWindowMap& rTabList = _pView->getTableView()->GetTabWinMap();
1489 for (auto const& table : rTabList)
1490 {
1491 OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get());
1492 if (pTabWin->ExistsField( "*", aDragLeft ))
1493 {
1494 aDragLeft->SetAlias(OUString());
1495 aDragLeft->SetTable(OUString());
1496 break;
1497 }
1498 }
1499 }
1500 else if (pParamNode)
1501 {
1502 eErrorCode = FillDragInfo(_pView,pParamNode,aDragLeft);
1503 if ( eOk != eErrorCode && SQL_ISRULE(pParamNode,num_value_exp)((pParamNode)->isRule() && (pParamNode)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::num_value_exp))
)
1504 {
1505 OUString sParameterValue;
1506 pParamNode->parseNodeToStr( sParameterValue,
1507 xConnection,
1508 &rController.getParser().getContext());
1509 nFunctionType |= FKT_NUMERIC;
1510 aDragLeft->SetField(sParameterValue);
1511 eErrorCode = eOk;
1512 }
1513 }
1514 aDragLeft->SetFunctionType(nFunctionType);
1515 if ( bHaving )
1516 aDragLeft->SetGroupBy(true);
1517 aDragLeft->SetFunction(aColumnName.getToken(0, '('));
1518 }
1519 else
1520 {
1521 // for an unknown function we write the whole text in the field
1522 aDragLeft->SetField(aColumnName);
1523 if(bHaving)
1524 aDragLeft->SetGroupBy(true);
1525 aDragLeft->SetFunctionType(FKT_OTHER|FKT_NUMERIC);
1526 }
1527 _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
1528 }
1529
1530 return eErrorCode;
1531 }
1532 SqlParseError ComparisonPredicate(OQueryDesignView const * _pView,
1533 OSelectionBrowseBox* _pSelectionBrw,
1534 const ::connectivity::OSQLParseNode * pCondition,
1535 const sal_uInt16 nLevel,
1536 bool bHaving
1537 ,bool bAddOrOnOneLine)
1538 {
1539 SqlParseError eErrorCode = eOk;
1540 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1541
1542 OSL_ENSURE(SQL_ISRULE( pCondition, comparison_predicate),"ComparisonPredicate: pCondition is not a Comparison Predicate")do { if (true && (!(((pCondition)->isRule() &&
(pCondition)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::comparison_predicate))))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1542" ": "), "%s", "ComparisonPredicate: pCondition is not a Comparison Predicate"
); } } while (false)
;
1543 if ( SQL_ISRULE(pCondition->getChild(0), column_ref )((pCondition->getChild(0))->isRule() && (pCondition
->getChild(0))->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::column_ref))
1544 || SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref)((pCondition->getChild(pCondition->count()-1))->isRule
() && (pCondition->getChild(pCondition->count()
-1))->getRuleID() == OSQLParser::RuleID(OSQLParseNode::column_ref
))
)
1545 {
1546 OUString aCondition;
1547 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1548
1549 if ( SQL_ISRULE(pCondition->getChild(0), column_ref )((pCondition->getChild(0))->isRule() && (pCondition
->getChild(0))->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::column_ref))
&& SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref )((pCondition->getChild(pCondition->count()-1))->isRule
() && (pCondition->getChild(pCondition->count()
-1))->getRuleID() == OSQLParser::RuleID(OSQLParseNode::column_ref
))
)
1550 {
1551 OTableFieldDescRef aDragRight = new OTableFieldDesc();
1552 eErrorCode = FillDragInfo(_pView,pCondition->getChild(0),aDragLeft);
1553 if (eOk != eErrorCode)
1554 return eErrorCode;
1555 eErrorCode = FillDragInfo(_pView,pCondition->getChild(2),aDragRight);
1556 if (eOk != eErrorCode)
1557 return eErrorCode;
1558
1559 OQueryTableConnection* pConn = static_cast<OQueryTableConnection*>(
1560 _pView->getTableView()->GetTabConn(static_cast<OQueryTableWindow*>(aDragLeft->GetTabWindow()),
1561 static_cast<OQueryTableWindow*>(aDragRight->GetTabWindow()),
1562 true));
1563 if ( pConn )
1564 {
1565 OConnectionLineDataVec& rLineDataList = pConn->GetData()->GetConnLineDataList();
1566 for (auto const& lineData : rLineDataList)
1567 {
1568 if(lineData->GetSourceFieldName() == aDragLeft->GetField() ||
1569 lineData->GetDestFieldName() == aDragLeft->GetField() )
1570 return eOk;
1571 }
1572 }
1573 }
1574
1575 sal_uInt32 nPos = 0;
1576 if(SQL_ISRULE(pCondition->getChild(0), column_ref )((pCondition->getChild(0))->isRule() && (pCondition
->getChild(0))->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::column_ref))
)
1577 {
1578 nPos = 0;
1579 sal_uInt32 i=1;
1580
1581 // don't display the equal
1582 if (pCondition->getChild(i)->getNodeType() == SQLNodeType::Equal)
1583 i++;
1584
1585 // parse the condition
1586 aCondition = ParseCondition(rController
1587 ,pCondition
1588 ,_pView->getDecimalSeparator()
1589 ,_pView->getLocale()
1590 ,i);
1591 }
1592 else if( SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref )((pCondition->getChild(pCondition->count()-1))->isRule
() && (pCondition->getChild(pCondition->count()
-1))->getRuleID() == OSQLParser::RuleID(OSQLParseNode::column_ref
))
)
1593 {
1594 nPos = pCondition->count()-1;
1595
1596 sal_Int32 i = static_cast<sal_Int32>(pCondition->count() - 2);
1597 switch (pCondition->getChild(i)->getNodeType())
1598 {
1599 case SQLNodeType::Equal:
1600 // don't display the equal
1601 i--;
1602 break;
1603 case SQLNodeType::Less:
1604 // take the opposite as we change the order
1605 i--;
1606 aCondition += ">";
1607 break;
1608 case SQLNodeType::LessEq:
1609 // take the opposite as we change the order
1610 i--;
1611 aCondition += ">=";
1612 break;
1613 case SQLNodeType::Great:
1614 // take the opposite as we change the order
1615 i--;
1616 aCondition += "<";
1617 break;
1618 case SQLNodeType::GreatEq:
1619 // take the opposite as we change the order
1620 i--;
1621 aCondition += "<=";
1622 break;
1623 default:
1624 break;
1625 }
1626
1627 // go backward
1628 Reference< XConnection> xConnection = rController.getConnection();
1629 if(xConnection.is())
1630 {
1631 for (; i >= 0; i--)
1632 pCondition->getChild(i)->parseNodeToPredicateStr(aCondition,
1633 xConnection,
1634 rController.getNumberFormatter(),
1635 _pView->getLocale(),
1636 _pView->getDecimalSeparator(),
1637 &rController.getParser().getContext());
1638 }
1639 }
1640 // else ???
1641
1642 if( eOk == ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(nPos),aDragLeft)))
1643 {
1644 if(bHaving)
1645 aDragLeft->SetGroupBy(true);
1646 _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
1647 }
1648 }
1649 else if( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , general_set_fct )((pCondition->getChild(0))->isRule() && ( (pCondition
->getChild(0))->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::set_fct_spec) || (pCondition->getChild(0))->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::general_set_fct)))
)
1650 {
1651 AddFunctionCondition( _pView,
1652 _pSelectionBrw,
1653 pCondition,
1654 nLevel,
1655 bHaving,
1656 bAddOrOnOneLine);
1657 }
1658 else // it can only be an Expr
1659 {
1660 OUString aName,aCondition;
1661
1662 // Field name
1663 Reference< XConnection> xConnection = rController.getConnection();
1664 if(xConnection.is())
1665 {
1666 ::connectivity::OSQLParseNode *pLhs = pCondition->getChild(0);
1667 ::connectivity::OSQLParseNode *pRhs = pCondition->getChild(2);
1668 pLhs->parseNodeToStr(aName,
1669 xConnection,
1670 &rController.getParser().getContext(),
1671 true);
1672 // Criteria
1673 aCondition = pCondition->getChild(1)->getTokenValue();
1674 pRhs->parseNodeToPredicateStr(aCondition,
1675 xConnection,
1676 rController.getNumberFormatter(),
1677 _pView->getLocale(),
1678 _pView->getDecimalSeparator(),
1679 &rController.getParser().getContext());
1680 }
1681
1682 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1683 aDragLeft->SetField(aName);
1684 aDragLeft->SetFunctionType(FKT_OTHER|FKT_NUMERIC);
1685 // and add it on
1686 _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
1687 }
1688 return eErrorCode;
1689 }
1690
1691 OQueryTableWindow* lcl_findColumnInTables( const OUString& _rColumName, const OJoinTableView::OTableWindowMap& _rTabList, OTableFieldDescRef const & _rInfo )
1692 {
1693 for (auto const& table : _rTabList)
1694 {
1695 OQueryTableWindow* pTabWin = static_cast< OQueryTableWindow* >( table.second.get() );
1696 if ( pTabWin && pTabWin->ExistsField( _rColumName, _rInfo ) )
1697 return pTabWin;
1698 }
1699 return nullptr;
1700 }
1701
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)
1709 {
1710
1711 // Put the table names together
1712 ::connectivity::OSQLParseTreeIterator& rParseIter = static_cast<OQueryController&>(_pView->getController()).getParseIterator();
1713 rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange );
1714
1715 bool bFound(false);
1716 OSL_ENSURE(!aColumnName.isEmpty(),"Column name must not be empty")do { if (true && (!(!aColumnName.isEmpty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1716" ": "), "%s", "Column name must not be empty"); } }
while (false)
;
1717 if (aTableRange.isEmpty())
1718 {
1719 // SELECT column, ...
1720 bFound = nullptr != lcl_findColumnInTables( aColumnName, *pTabList, _raInfo );
1721 if ( bFound && ( aColumnName.toChar() != '*' ) )
1722 _raInfo->SetFieldAlias(aColumnAlias);
1723 }
1724 else
1725 {
1726 // SELECT range.column, ...
1727 OQueryTableWindow* pTabWin = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable(aTableRange);
1728
1729 if (pTabWin && pTabWin->ExistsField(aColumnName, _raInfo))
1730 {
1731 if(aColumnName.toChar() != '*')
1732 _raInfo->SetFieldAlias(aColumnAlias);
1733 bFound = true;
1734 }
1735 }
1736 if (!bFound)
1737 {
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);
1743 }
1744 }
1745 bool checkJoinConditions( const OQueryDesignView* _pView,
1746 const ::connectivity::OSQLParseNode* _pNode )
1747 {
1748 const ::connectivity::OSQLParseNode* pJoinNode = nullptr;
1749 bool bRet = true;
1750 if (SQL_ISRULE(_pNode,qualified_join)((_pNode)->isRule() && (_pNode)->getRuleID() ==
OSQLParser::RuleID(OSQLParseNode::qualified_join))
)
1751 pJoinNode = _pNode;
1752 else if (SQL_ISRULE(_pNode,table_ref)((_pNode)->isRule() && (_pNode)->getRuleID() ==
OSQLParser::RuleID(OSQLParseNode::table_ref))
1753 && _pNode->count() == 3
1754 && SQL_ISPUNCTUATION(_pNode->getChild(0),"(")((_pNode->getChild(0))->getNodeType() == SQLNodeType::Punctuation
&& (_pNode->getChild(0))->getTokenValue() == (
"("))
1755 && SQL_ISPUNCTUATION(_pNode->getChild(2),")")((_pNode->getChild(2))->getNodeType() == SQLNodeType::Punctuation
&& (_pNode->getChild(2))->getTokenValue() == (
")"))
) // '(' joined_table ')'
1756 pJoinNode = _pNode->getChild(1);
1757 else if (! ( SQL_ISRULE(_pNode, table_ref)((_pNode)->isRule() && (_pNode)->getRuleID() ==
OSQLParser::RuleID(OSQLParseNode::table_ref))
&& _pNode->count() == 2) ) // table_node table_primary_as_range_column
1758 bRet = false;
1759
1760 if (pJoinNode && !InsertJoin(_pView,pJoinNode))
1761 bRet = false;
1762 return bRet;
1763 }
1764 bool InsertJoin(const OQueryDesignView* _pView,
1765 const ::connectivity::OSQLParseNode *pNode)
1766 {
1767 OSL_ENSURE( SQL_ISRULE( pNode, qualified_join ) || SQL_ISRULE( pNode, joined_table ) || SQL_ISRULE( pNode, cross_union ),do { if (true && (!(((pNode)->isRule() && (
pNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::qualified_join
)) || ((pNode)->isRule() && (pNode)->getRuleID(
) == OSQLParser::RuleID(OSQLParseNode::joined_table)) || ((pNode
)->isRule() && (pNode)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::cross_union))))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1768" ": "), "%s", "OQueryDesignView::InsertJoin: Error in the Parse Tree"
); } } while (false)
1768 "OQueryDesignView::InsertJoin: Error in the Parse Tree")do { if (true && (!(((pNode)->isRule() && (
pNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::qualified_join
)) || ((pNode)->isRule() && (pNode)->getRuleID(
) == OSQLParser::RuleID(OSQLParseNode::joined_table)) || ((pNode
)->isRule() && (pNode)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::cross_union))))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1768" ": "), "%s", "OQueryDesignView::InsertJoin: Error in the Parse Tree"
); } } while (false)
;
1769
1770 if (SQL_ISRULE(pNode,joined_table)((pNode)->isRule() && (pNode)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::joined_table))
)
1771 return InsertJoin(_pView,pNode->getChild(1));
1772
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)((pNode)->isRule() && (pNode)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::qualified_join))
&& SQL_ISTOKEN(pNode->getChild(1),NATURAL)((pNode->getChild(1))->isToken() && (pNode->
getChild(1))->getTokenID() == SQL_TOKEN_NATURAL)
)
1776 pRightTableRef = pNode->getChild(4); // table_ref
1777
1778 if ( !checkJoinConditions(_pView,pNode->getChild(0)) || !checkJoinConditions(_pView,pRightTableRef))
1779 return false;
1780
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)((pNode)->isRule() && (pNode)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::qualified_join))
)
1786 {
1787 ::connectivity::OSQLParseNode* pJoinType = pNode->getChild(1); // join_type
1788 if ( SQL_ISTOKEN(pJoinType,NATURAL)((pJoinType)->isToken() && (pJoinType)->getTokenID
() == SQL_TOKEN_NATURAL)
)
1789 {
1790 bNatural = true;
1791 pJoinType = pNode->getChild(2);
1792 }
1793
1794 if (SQL_ISRULE(pJoinType,join_type)((pJoinType)->isRule() && (pJoinType)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::join_type))
&& (!pJoinType->count() || SQL_ISTOKEN(pJoinType->getChild(0),INNER)((pJoinType->getChild(0))->isToken() && (pJoinType
->getChild(0))->getTokenID() == SQL_TOKEN_INNER)
))
1795 {
1796 eJoinType = INNER_JOIN;
1797 }
1798 else
1799 {
1800 if (SQL_ISRULE(pJoinType,join_type)((pJoinType)->isRule() && (pJoinType)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::join_type))
) // one level deeper
1801 pJoinType = pJoinType->getChild(0);
1802
1803 if (SQL_ISTOKEN(pJoinType->getChild(0),LEFT)((pJoinType->getChild(0))->isToken() && (pJoinType
->getChild(0))->getTokenID() == SQL_TOKEN_LEFT)
)
1804 eJoinType = LEFT_JOIN;
1805 else if(SQL_ISTOKEN(pJoinType->getChild(0),RIGHT)((pJoinType->getChild(0))->isToken() && (pJoinType
->getChild(0))->getTokenID() == SQL_TOKEN_RIGHT)
)
1806 eJoinType = RIGHT_JOIN;
1807 else
1808 eJoinType = FULL_JOIN;
1809 }
1810 if ( SQL_ISRULE(pNode->getChild(4),join_condition)((pNode->getChild(4))->isRule() && (pNode->getChild
(4))->getRuleID() == OSQLParser::RuleID(OSQLParseNode::join_condition
))
)
1811 {
1812 if ( InsertJoinConnection(_pView,pNode->getChild(4)->getChild(1), eJoinType,pNode->getChild(0),pRightTableRef) != eOk )
1813 return false;
1814 }
1815 }
1816 else if ( SQL_ISRULE(pNode, cross_union)((pNode)->isRule() && (pNode)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::cross_union))
)
1817 {
1818 eJoinType = CROSS_JOIN;
1819 pRightTableRef = pNode->getChild(pNode->count() - 1);
1820 }
1821 else
1822 return false;
1823
1824 if ( eJoinType == CROSS_JOIN || bNatural )
1825 {
1826
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!")do { if (true && (!(pLeftWindow && pRightWindow
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1829" ": "), "%s", "Table Windows could not be found!")
; } } while (false)
;
1830 if ( !pLeftWindow || !pRightWindow )
1831 return false;
1832
1833 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1834 aDragLeft->SetTabWindow(pLeftWindow);
1835 aDragLeft->SetTable(pLeftWindow->GetTableName());
1836 aDragLeft->SetAlias(pLeftWindow->GetAliasName());
1837
1838 OTableFieldDescRef aDragRight = new OTableFieldDesc();
1839 aDragRight->SetTabWindow(pRightWindow);
1840 aDragRight->SetTable(pRightWindow->GetTableName());
1841 aDragRight->SetAlias(pRightWindow->GetAliasName());
1842
1843 insertConnection(_pView,eJoinType,aDragLeft,aDragRight,bNatural);
1844 }
1845
1846 return true;
1847 }
1848 void insertUnUsedFields(OQueryDesignView const * _pView,OSelectionBrowseBox* _pSelectionBrw)
1849 {
1850 // now we have to insert the fields which aren't in the statement
1851 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1852 OTableFields& rUnUsedFields = rController.getUnUsedFields();
1853 for (auto & unusedField : rUnUsedFields)
1854 if(_pSelectionBrw->InsertField(unusedField,BROWSER_INVALIDID((sal_uInt16) 0xFFFF),false,false).is())
1855 unusedField = nullptr;
1856 OTableFields().swap( rUnUsedFields );
1857 }
1858
1859 SqlParseError InitFromParseNodeImpl(OQueryDesignView* _pView,OSelectionBrowseBox* _pSelectionBrw)
1860 {
1861 SqlParseError eErrorCode = eOk;
1862
1863 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1864
1865 _pSelectionBrw->PreFill();
1866 _pSelectionBrw->SetReadOnly(rController.isReadOnly());
1867 _pSelectionBrw->Fill();
1868
1869 ::connectivity::OSQLParseTreeIterator& aIterator = rController.getParseIterator();
1870 const ::connectivity::OSQLParseNode* pParseTree = aIterator.getParseTree();
1871
1872 do
1873 {
1874 if ( !pParseTree )
1875 {
1876 // now we have to insert the fields which aren't in the statement
1877 insertUnUsedFields(_pView,_pSelectionBrw);
1878 break;
1879 }
1880
1881 if ( !rController.isEscapeProcessing() ) // not allowed in this mode
1882 {
1883 eErrorCode = eNativeMode;
1884 break;
1885 }
1886
1887 if ( !( SQL_ISRULE( pParseTree, select_statement )((pParseTree)->isRule() && (pParseTree)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::select_statement))
) )
1888 {
1889 eErrorCode = eNoSelectStatement;
1890 break;
1891 }
1892
1893 const OSQLParseNode* pTableExp = pParseTree->getChild(3);
1894 if ( pTableExp->getChild(7)->count() > 0 || pTableExp->getChild(8)->count() > 0)
1895 {
1896 eErrorCode = eStatementTooComplex;
1897 break;
1898 }
1899
1900 Reference< XConnection> xConnection = rController.getConnection();
1901 if ( !xConnection.is() )
1902 {
1903 OSL_FAIL( "InitFromParseNodeImpl: no connection? no connection!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1903" ": "), "%s", "InitFromParseNodeImpl: no connection? no connection!"
); } } while (false)
;
1904 break;
1905 }
1906
1907 const OSQLTables& aMap = aIterator.getTables();
1908 ::comphelper::UStringMixLess aTmp(aMap.key_comp());
1909 ::comphelper::UStringMixEqual aKeyComp( aTmp.isCaseSensitive() );
1910
1911 Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
1912 try
1913 {
1914 sal_Int32 nMax = xMetaData->getMaxTablesInSelect();
1915 if ( nMax && nMax < static_cast<sal_Int32>(aMap.size()) )
1916 {
1917 eErrorCode = eTooManyTables;
1918 break;
1919 }
1920
1921 OUString sComposedName;
1922 OUString sAlias;
1923
1924 OQueryTableView* pTableView = static_cast<OQueryTableView*>(_pView->getTableView());
1925 pTableView->clearLayoutInformation();
1926 for (auto const& elem : aMap)
1927 {
1928 OSQLTable xTable = elem.second;
1929 Reference< XPropertySet > xTableProps( xTable, UNO_QUERY_THROW );
1930
1931 sAlias = elem.first;
1932
1933 // check whether this is a query
1934 Reference< XPropertySetInfo > xPSI = xTableProps->getPropertySetInfo();
1935 bool bIsQuery = xPSI.is() && xPSI->hasPropertyByName( PROPERTY_COMMAND"Command" );
1936
1937 if ( bIsQuery )
1938 OSL_VERIFY( xTableProps->getPropertyValue( PROPERTY_NAME ) >>= sComposedName )do { if (!(xTableProps->getPropertyValue( "Name" ) >>=
sComposedName)) do { if (true && (!(0))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "1938" ": "), "OSL_ASSERT: %s", "0"); } } while (false);
} while (0)
;
1939 else
1940 {
1941 sComposedName = ::dbtools::composeTableName( xMetaData, xTableProps, ::dbtools::EComposeRule::InDataManipulation, false );
1942
1943 // if the alias is the complete (composed) table, then shorten it
1944 if ( aKeyComp( sComposedName, elem.first ) )
1945 {
1946 OUString sCatalog, sSchema, sTable;
1947 ::dbtools::qualifiedNameComponents( xMetaData, sComposedName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
1948 sAlias = sTable;
1949 }
1950 }
1951
1952 // find the existent window for this alias
1953 OQueryTableWindow* pExistentWin = pTableView->FindTable( sAlias );
1954 if ( !pExistentWin )
1955 {
1956 pTableView->AddTabWin( sComposedName, sAlias ); // don't create data here
1957 }
1958 else
1959 {
1960 // there already exists a window for this alias...
1961 if ( !aKeyComp( pExistentWin->GetData()->GetComposedName(), sComposedName ) )
1962 // ... but for another complete table name -> new window
1963 pTableView->AddTabWin(sComposedName, sAlias);
1964 }
1965 }
1966
1967 // now delete the data for which we haven't any tablewindow
1968 OJoinTableView::OTableWindowMap aTableMap(pTableView->GetTabWinMap());
1969 for (auto const& table : aTableMap)
1970 {
1971 if(aMap.find(table.second->GetComposedName()) == aMap.end() &&
1972 aMap.find(table.first) == aMap.end())
1973 pTableView->RemoveTabWin(table.second);
1974 }
1975
1976 if ( eOk == (eErrorCode = FillOuterJoins(_pView,pTableExp->getChild(0)->getChild(1))) )
1977 {
1978 // check if we have a distinct statement
1979 if(SQL_ISTOKEN(pParseTree->getChild(1),DISTINCT)((pParseTree->getChild(1))->isToken() && (pParseTree
->getChild(1))->getTokenID() == SQL_TOKEN_DISTINCT)
)
1980 {
1981 rController.setDistinct(true);
1982 rController.InvalidateFeature(SID_QUERY_DISTINCT_VALUES( ((((((((10000 + 1499) + 1) + 499) + 1) + 100) + 1) + 149) +
1) + 49 )
);
1983 }
1984 else
1985 {
1986 rController.setDistinct(false);
1987 }
1988
1989 ///check if query has a limit
1990 if( pTableExp->getChild(6)->count() >= 2 && pTableExp->getChild(6)->getChild(1) )
1991 {
1992 rController.setLimit(
1993 pTableExp->getChild(6)->getChild(1)->getTokenValue().toInt64() );
1994 }
1995 else
1996 {
1997 rController.setLimit(-1);
1998 }
1999
2000 if ( (eErrorCode = InstallFields(_pView, pParseTree, &pTableView->GetTabWinMap())) == eOk )
2001 {
2002 // GetSelectionCriteria must be called before GetHavingCriteria
2003 sal_uInt16 nLevel=0;
2004
2005 if ( eOk == (eErrorCode = GetSelectionCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) )
2006 {
2007 if ( eOk == (eErrorCode = GetGroupCriteria(_pView,_pSelectionBrw,pParseTree)) )
2008 {
2009 if ( eOk == (eErrorCode = GetHavingCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) )
2010 {
2011 if ( eOk == (eErrorCode = GetOrderCriteria(_pView,_pSelectionBrw,pParseTree)) )
2012 insertUnUsedFields(_pView,_pSelectionBrw);
2013 }
2014 }
2015 }
2016 }
2017 }
2018 }
2019 catch(SQLException&)
2020 {
2021 OSL_FAIL("getMaxTablesInSelect!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "2021" ": "), "%s", "getMaxTablesInSelect!"); } } while (
false)
;
2022 }
2023 }
2024 while ( false );
2025
2026 // New Undo-Actions were created in the Manager by the regeneration
2027 rController.ClearUndoManager();
2028 _pSelectionBrw->Invalidate();
2029 return eErrorCode;
2030 }
2031 /** fillSelectSubList
2032 @return
2033 <TRUE/> when columns could be inserted otherwise <FALSE/>
2034 */
2035 SqlParseError fillSelectSubList( OQueryDesignView* _pView,
2036 OJoinTableView::OTableWindowMap* _pTabList)
2037 {
2038 SqlParseError eErrorCode = eOk;
2039 bool bFirstField = true;
2040 for (auto const& table : *_pTabList)
2041 {
2042 OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get());
2043 OTableFieldDescRef aInfo = new OTableFieldDesc();
2044 if (pTabWin->ExistsField( "*", aInfo ))
2045 {
2046 eErrorCode = _pView->InsertField(aInfo, bFirstField);
2047 bFirstField = false;
2048 if (eErrorCode != eOk)
2049 break;
2050 }
2051 }
2052 return eErrorCode;
2053 }
2054 SqlParseError InstallFields(OQueryDesignView* _pView,
2055 const ::connectivity::OSQLParseNode* pNode,
2056 OJoinTableView::OTableWindowMap* pTabList )
2057 {
2058 if( pNode==nullptr || !SQL_ISRULE(pNode,select_statement)((pNode)->isRule() && (pNode)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::select_statement))
)
2059 return eNoSelectStatement;
2060
2061 ::connectivity::OSQLParseNode* pParseTree = pNode->getChild(2); // selection
2062 bool bFirstField = true; // When initializing, the first field must be reactivated
2063
2064 SqlParseError eErrorCode = eOk;
2065
2066 if ( pParseTree->isRule() && SQL_ISPUNCTUATION(pParseTree->getChild(0),"*")((pParseTree->getChild(0))->getNodeType() == SQLNodeType
::Punctuation && (pParseTree->getChild(0))->getTokenValue
() == ("*"))
)
2067 {
2068 // SELECT * ...
2069 eErrorCode = fillSelectSubList(_pView,pTabList);
2070 }
2071 else if (SQL_ISRULE(pParseTree,scalar_exp_commalist)((pParseTree)->isRule() && (pParseTree)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::scalar_exp_commalist)
)
)
2072 {
2073 // SELECT column, ...
2074 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
2075 Reference< XConnection> xConnection = rController.getConnection();
2076
2077 OUString aColumnName,aTableRange;
2078 for (size_t i = 0; i < pParseTree->count() && eOk == eErrorCode ; ++i)
2079 {
2080 ::connectivity::OSQLParseNode * pColumnRef = pParseTree->getChild(i);
2081
2082 do {
2083
2084 if ( SQL_ISRULE(pColumnRef,select_sublist)((pColumnRef)->isRule() && (pColumnRef)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::select_sublist))
)
2085 {
2086 eErrorCode = fillSelectSubList(_pView,pTabList);
2087 break;
2088 }
2089
2090 if ( SQL_ISRULE(pColumnRef,derived_column)((pColumnRef)->isRule() && (pColumnRef)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::derived_column))
)
2091 {
2092 OUString aColumnAlias(connectivity::OSQLParseTreeIterator::getColumnAlias(pColumnRef)); // might be empty
2093 pColumnRef = pColumnRef->getChild(0);
2094 OTableFieldDescRef aInfo = new OTableFieldDesc();
2095
2096 if ( pColumnRef->getKnownRuleID() != OSQLParseNode::subquery &&
2097 pColumnRef->count() == 3 &&
2098 SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(")((pColumnRef->getChild(0))->getNodeType() == SQLNodeType
::Punctuation && (pColumnRef->getChild(0))->getTokenValue
() == ("("))
&&
2099 SQL_ISPUNCTUATION(pColumnRef->getChild(2),")")((pColumnRef->getChild(2))->getNodeType() == SQLNodeType
::Punctuation && (pColumnRef->getChild(2))->getTokenValue
() == (")"))
2100 )
2101 pColumnRef = pColumnRef->getChild(1);
2102
2103 if (SQL_ISRULE(pColumnRef,column_ref)((pColumnRef)->isRule() && (pColumnRef)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::column_ref))
)
2104 {
2105 InsertColumnRef(_pView,pColumnRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList);
2106 eErrorCode = _pView->InsertField(aInfo, bFirstField);
2107 bFirstField = false;
2108 }
2109 else if(SQL_ISRULEOR3(pColumnRef, general_set_fct, set_fct_spec, position_exp)((pColumnRef)->isRule() && ( (pColumnRef)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::general_set_fct) || (
pColumnRef)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::set_fct_spec) || (pColumnRef)->getRuleID() == OSQLParser
::RuleID(OSQLParseNode::position_exp)))
||
2110 SQL_ISRULEOR3(pColumnRef, extract_exp, fold, char_substring_fct)((pColumnRef)->isRule() && ( (pColumnRef)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::extract_exp) || (pColumnRef
)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::fold) ||
(pColumnRef)->getRuleID() == OSQLParser::RuleID(OSQLParseNode
::char_substring_fct)))
||
2111 SQL_ISRULEOR2(pColumnRef,length_exp,char_value_fct)((pColumnRef)->isRule() && ( (pColumnRef)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::length_exp) || (pColumnRef
)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::char_value_fct
)))
)
2112 {
2113 OUString aColumns;
2114 pColumnRef->parseNodeToPredicateStr(aColumns,
2115 xConnection,
2116 rController.getNumberFormatter(),
2117 _pView->getLocale(),
2118 _pView->getDecimalSeparator(),
2119 &rController.getParser().getContext());
2120
2121 sal_Int32 nFunctionType = FKT_NONE;
2122 ::connectivity::OSQLParseNode* pParamRef = nullptr;
2123 sal_Int32 nColumnRefPos = pColumnRef->count() - 2;
2124 if ( nColumnRefPos >= 0 && o3tl::make_unsigned(nColumnRefPos) < pColumnRef->count() )
2125 pParamRef = pColumnRef->getChild(nColumnRefPos);
2126
2127 if ( SQL_ISRULE(pColumnRef,general_set_fct)((pColumnRef)->isRule() && (pColumnRef)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::general_set_fct))
2128 && pParamRef && SQL_ISRULE(pParamRef,column_ref)((pParamRef)->isRule() && (pParamRef)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::column_ref))
)
2129 {
2130 // Check the parameters for Column references
2131 InsertColumnRef(_pView,pParamRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList);
2132 }
2133 else if ( SQL_ISRULE(pColumnRef,general_set_fct)((pColumnRef)->isRule() && (pColumnRef)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::general_set_fct))
)
2134 {
2135 if ( pParamRef && pParamRef->getTokenValue().toChar() == '*' )
2136 {
2137 for (auto const& table : *pTabList)
2138 {
2139 OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get());
2140 if (pTabWin->ExistsField( "*", aInfo ))
2141 {
2142 aInfo->SetAlias(OUString());
2143 aInfo->SetTable(OUString());
2144 break;
2145 }
2146 }
2147 }
2148 else
2149 {
2150 OUString sFieldName = aColumns;
2151 if ( pParamRef )
2152 { // we got an aggregate function but without column name inside
2153 // so we set the whole argument of the function as field name
2154 nFunctionType |= FKT_NUMERIC;
2155 sFieldName.clear();
2156 pParamRef->parseNodeToStr( sFieldName,
2157 xConnection,
2158 &rController.getParser().getContext(),
2159 true); // quote is to true because we need quoted elements inside the function
2160 }
2161 aInfo->SetDataType(DataType::DOUBLE);
2162 aInfo->SetFieldType(TAB_NORMAL_FIELD);
2163 aInfo->SetField(sFieldName);
2164 }
2165 aInfo->SetTabWindow(nullptr);
2166 aInfo->SetFieldAlias(aColumnAlias);
2167 }
2168 else
2169 {
2170 _pView->fillFunctionInfo(pColumnRef,aColumns,aInfo);
2171 aInfo->SetFieldAlias(aColumnAlias);
2172 }
2173
2174 if ( SQL_ISRULE(pColumnRef,general_set_fct)((pColumnRef)->isRule() && (pColumnRef)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::general_set_fct))
)
2175 {
2176 aInfo->SetFunctionType(nFunctionType|FKT_AGGREGATE);
2177 aInfo->SetFunction(comphelper::string::stripEnd(aColumns.getToken(0,'('), ' '));
2178 }
2179 else
2180 aInfo->SetFunctionType(nFunctionType|FKT_OTHER);
2181
2182 eErrorCode = _pView->InsertField(aInfo, bFirstField);
2183 bFirstField = false;
2184 }
2185 else
2186 {
2187 OUString aColumns;
2188 pColumnRef->parseNodeToStr( aColumns,
2189 xConnection,
2190 &rController.getParser().getContext(),
2191 true); // quote is to true because we need quoted elements inside the function
2192
2193 aInfo->SetTabWindow( nullptr );
2194
2195 // since we support queries in queries, the thingie might belong to an existing "table"
2196 OQueryTableWindow* pExistingTable = lcl_findColumnInTables( aColumns, *pTabList, aInfo );
2197 if ( pExistingTable )
2198 {
2199 aInfo->SetTabWindow( pExistingTable );
2200 aInfo->SetTable( pExistingTable->GetTableName() );
2201 aInfo->SetAlias( pExistingTable->GetAliasName() );
2202 }
2203
2204 aInfo->SetDataType(DataType::DOUBLE);
2205 aInfo->SetFieldType(TAB_NORMAL_FIELD);
2206 aInfo->SetField(aColumns);
2207 aInfo->SetFieldAlias(aColumnAlias);
2208 aInfo->SetFunctionType(FKT_NUMERIC | FKT_OTHER);
2209
2210 eErrorCode = _pView->InsertField(aInfo, bFirstField);
2211 bFirstField = false;
2212 }
2213
2214 break;
2215 }
2216
2217 OSL_FAIL( "InstallFields: don't know how to interpret this parse node!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "2217" ": "), "%s", "InstallFields: don't know how to interpret this parse node!"
); } } while (false)
;
2218
2219 } while ( false );
2220 }
2221 }
2222 else
2223 eErrorCode = eStatementTooComplex;
2224
2225 return eErrorCode;
2226 }
2227 SqlParseError GetOrderCriteria( OQueryDesignView* _pView,
2228 OSelectionBrowseBox* _pSelectionBrw,
2229 const ::connectivity::OSQLParseNode* pParseRoot )
2230 {
2231 SqlParseError eErrorCode = eOk;
2232 if (!pParseRoot->getChild(3)->getChild(ORDER_BY_CHILD_POS5)->isLeaf())
2233 {
2234 ::connectivity::OSQLParseNode* pNode = pParseRoot->getChild(3)->getChild(ORDER_BY_CHILD_POS5)->getChild(2);
2235 ::connectivity::OSQLParseNode* pParamRef = nullptr;
2236
2237 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
2238 EOrderDir eOrderDir;
2239 for( size_t i=0 ; i<pNode->count() ; i++ )
2240 {
2241 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
2242 eOrderDir = ORDER_ASC;
2243 ::connectivity::OSQLParseNode* pChild = pNode->getChild( i );
2244
2245 if (SQL_ISTOKEN( pChild->getChild(1), DESC )((pChild->getChild(1))->isToken() && (pChild->
getChild(1))->getTokenID() == SQL_TOKEN_DESC)
)
2246 eOrderDir = ORDER_DESC;
2247
2248 ::connectivity::OSQLParseNode* pArgument = pChild->getChild(0);
2249
2250 if(SQL_ISRULE(pArgument,column_ref)((pArgument)->isRule() && (pArgument)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::column_ref))
)
2251 {
2252 if( eOk == FillDragInfo(_pView,pArgument,aDragLeft))
2253 _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i);
2254 else // it could be an alias name for a field
2255 {
2256 OUString aTableRange,aColumnName;
2257 ::connectivity::OSQLParseTreeIterator& rParseIter = rController.getParseIterator();
2258 rParseIter.getColumnRange( pArgument, aColumnName, aTableRange );
2259
2260 OTableFields& aList = rController.getTableFieldDesc();
2261 for (auto const& elem : aList)
2262 {
2263 if(elem.is() && elem->GetFieldAlias() == aColumnName)
2264 elem->SetOrderDir( eOrderDir );
2265 }
2266 }
2267 }
2268 else if(SQL_ISRULE(pArgument, general_set_fct )((pArgument)->isRule() && (pArgument)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::general_set_fct))
&&
2269 SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref)((pParamRef = pArgument->getChild(pArgument->count()-2)
)->isRule() && (pParamRef = pArgument->getChild
(pArgument->count()-2))->getRuleID() == OSQLParser::RuleID
(OSQLParseNode::column_ref))
&&
2270 eOk == FillDragInfo(_pView,pParamRef,aDragLeft))
2271 _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i );
2272 else if( SQL_ISRULE(pArgument, set_fct_spec )((pArgument)->isRule() && (pArgument)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::set_fct_spec))
)
2273 {
2274
2275 Reference< XConnection> xConnection = rController.getConnection();
2276 if(xConnection.is())
2277 {
2278 OUString sCondition;
2279 pArgument->parseNodeToPredicateStr(sCondition,
2280 xConnection,
2281 rController.getNumberFormatter(),
2282 _pView->getLocale(),
2283 _pView->getDecimalSeparator(),
2284 &rController.getParser().getContext());
2285 _pView->fillFunctionInfo(pArgument,sCondition,aDragLeft);
2286 aDragLeft->SetFunctionType(FKT_OTHER);
2287 aDragLeft->SetOrderDir(eOrderDir);
2288 aDragLeft->SetVisible(false);
2289 _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i );
2290 }
2291 else
2292 eErrorCode = eColumnNotFound;
2293 }
2294 else
2295 eErrorCode = eColumnNotFound;
2296 }
2297 }
2298 return eErrorCode;
2299 }
2300 SqlParseError GetHavingCriteria( OQueryDesignView* _pView,
2301 OSelectionBrowseBox* _pSelectionBrw,
2302 const ::connectivity::OSQLParseNode* pSelectRoot,
2303 sal_uInt16& rLevel )
2304 {
2305 SqlParseError eErrorCode = eOk;
2306 if (!pSelectRoot->getChild(3)->getChild(3)->isLeaf())
2307 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSelectRoot->getChild(3)->getChild(3)->getChild(1),rLevel, true);
2308 return eErrorCode;
2309 }
2310 SqlParseError GetGroupCriteria( OQueryDesignView* _pView,
2311 OSelectionBrowseBox* _pSelectionBrw,
2312 const ::connectivity::OSQLParseNode* pSelectRoot )
2313 {
2314 SqlParseError eErrorCode = eOk;
2315 if (!pSelectRoot->getChild(3)->getChild(2)->isLeaf()) // opt_group_by_clause
2316 {
2317 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
2318 ::connectivity::OSQLParseNode* pGroupBy = pSelectRoot->getChild(3)->getChild(2)->getChild(2);
2319
2320 for( size_t i=0 ; i < pGroupBy->count() && eOk == eErrorCode; ++i )
2321 {
2322 OTableFieldDescRef aDragInfo = new OTableFieldDesc();
2323 ::connectivity::OSQLParseNode* pParamRef = nullptr;
2324 ::connectivity::OSQLParseNode* pArgument = pGroupBy->getChild( i );
2325 if(SQL_ISRULE(pArgument,column_ref)((pArgument)->isRule() && (pArgument)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::column_ref))
)
2326 {
2327 if ( eOk == (eErrorCode = FillDragInfo(_pView,pArgument,aDragInfo)) )
2328 {
2329 aDragInfo->SetGroupBy(true);
2330 _pSelectionBrw->AddGroupBy(aDragInfo);
2331 }
2332 }
2333 else if(SQL_ISRULE(pArgument, general_set_fct )((pArgument)->isRule() && (pArgument)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::general_set_fct))
&&
2334 SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref)((pParamRef = pArgument->getChild(pArgument->count()-2)
)->isRule() && (pParamRef = pArgument->getChild
(pArgument->count()-2))->getRuleID() == OSQLParser::RuleID
(OSQLParseNode::column_ref))
&&
2335 eOk == FillDragInfo(_pView,pParamRef,aDragInfo))
2336 {
2337 aDragInfo->SetGroupBy(true);
2338 _pSelectionBrw->AddGroupBy( aDragInfo );
2339 }
2340 else if( SQL_ISRULE(pArgument, set_fct_spec )((pArgument)->isRule() && (pArgument)->getRuleID
() == OSQLParser::RuleID(OSQLParseNode::set_fct_spec))
)
2341 {
2342 Reference< XConnection> xConnection = rController.getConnection();
2343 if(xConnection.is())
2344 {
2345 OUString sGroupByExpression;
2346 pArgument->parseNodeToStr( sGroupByExpression,
2347 xConnection,
2348 &rController.getParser().getContext(),
2349 true); // quote is to true because we need quoted elements inside the function
2350 _pView->fillFunctionInfo(pArgument,sGroupByExpression,aDragInfo);
2351 aDragInfo->SetFunctionType(FKT_OTHER);
2352 aDragInfo->SetGroupBy(true);
2353 aDragInfo->SetVisible(false);
2354 _pSelectionBrw->AddGroupBy( aDragInfo );
2355 }
2356 else
2357 eErrorCode = eColumnNotFound;
2358 }
2359 }
2360 }
2361 return eErrorCode;
2362 }
2363
2364 OUString getParseErrorMessage( SqlParseError _eErrorCode )
2365 {
2366 const char* pResId;
2367 switch (_eErrorCode)
2368 {
2369 case eIllegalJoin:
2370 pResId = STR_QRY_ILLEGAL_JOINreinterpret_cast<char const *>("STR_QRY_ILLEGAL_JOIN" "\004"
u8"Join could not be processed")
;
2371 break;
2372 case eStatementTooLong:
2373 pResId = STR_QRY_TOO_LONG_STATEMENTreinterpret_cast<char const *>("STR_QRY_TOO_LONG_STATEMENT"
"\004" u8"The SQL statement created is too long.")
;
2374 break;
2375 case eNoConnection:
2376 pResId = STR_QRY_SYNTAXreinterpret_cast<char const *>("STR_QRY_SYNTAX" "\004" u8"SQL syntax error"
)
;
2377 break;
2378 case eNoSelectStatement:
2379 pResId = STR_QRY_NOSELECTreinterpret_cast<char const *>("STR_QRY_NOSELECT" "\004"
u8"Nothing has been selected.")
;
2380 break;
2381 case eNoColumnInLike:
2382 pResId = STR_QRY_SYNTAXreinterpret_cast<char const *>("STR_QRY_SYNTAX" "\004" u8"SQL syntax error"
)
;
2383 break;
2384 case eColumnNotFound:
2385 pResId = STR_QRY_SYNTAXreinterpret_cast<char const *>("STR_QRY_SYNTAX" "\004" u8"SQL syntax error"
)
;
2386 break;
2387 case eNativeMode:
2388 pResId = STR_QRY_NATIVEreinterpret_cast<char const *>("STR_QRY_NATIVE" "\004" u8"The statement will not be applied when querying in the SQL dialect of the database."
)
;
2389 break;
2390 case eTooManyTables:
2391 pResId = STR_QRY_TOO_MANY_TABLESreinterpret_cast<char const *>("STR_QRY_TOO_MANY_TABLES"
"\004" u8"There are too many tables.")
;
2392 break;
2393 case eTooManyColumns:
2394 pResId = STR_QRY_TOO_MANY_COLUMNSreinterpret_cast<char const *>("STR_QRY_TOO_MANY_COLUMNS"
"\004" u8"There are too many columns.")
;
2395 break;
2396 case eStatementTooComplex:
2397 pResId = STR_QRY_TOOCOMPLEXreinterpret_cast<char const *>("STR_QRY_TOOCOMPLEX" "\004"
u8"Query is too complex")
;
2398 break;
2399 default:
2400 pResId = STR_QRY_SYNTAXreinterpret_cast<char const *>("STR_QRY_SYNTAX" "\004" u8"SQL syntax error"
)
;
2401 break;
2402 }
2403 return DBA_RES(pResId)::dbaccess::ResourceManager::loadString( pResId );
2404 }
2405}
2406
2407// end of anonymous namespace
2408
2409OQueryDesignView::OQueryDesignView( OQueryContainerWindow* _pParent,
2410 OQueryController& _rController,
2411 const Reference< XComponentContext >& _rxContext)
2412 :OJoinDesignView( _pParent, _rController, _rxContext )
2413 ,m_aSplitter( VclPtr<Splitter>::Create(this) )
2414 ,m_eChildFocus(NONE)
2415 ,m_bInSplitHandler( false )
2416{
2417
2418 try
2419 {
2420 SvtSysLocale aSysLocale;
2421 m_aLocale = aSysLocale.GetLanguageTag().getLocale();
2422 m_sDecimalSep = aSysLocale.GetLocaleData().getNumDecimalSep();
2423 }
2424 catch(Exception&)
2425 {
2426 }
2427
2428 m_pSelectionBox = VclPtr<OSelectionBrowseBox>::Create(this);
2429
2430 setNoneVisibleRow(static_cast<OQueryController&>(getController()).getVisibleRows());
2431 m_pSelectionBox->Show();
2432 // setup Splitter
2433 m_aSplitter->SetSplitHdl(LINK(this, OQueryDesignView,SplitHdl)::tools::detail::makeLink( ::tools::detail::castTo<OQueryDesignView
*>(this), &OQueryDesignView::LinkStubSplitHdl)
);
2434 m_aSplitter->Show();
2435
2436}
2437
2438OQueryDesignView::~OQueryDesignView()
2439{
2440 disposeOnce();
2441}
2442
2443void OQueryDesignView::dispose()
2444{
2445 if ( m_pTableView )
2446 ::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::RemoveWindow));
2447 m_pSelectionBox.disposeAndClear();
2448 m_aSplitter.disposeAndClear();
2449 OJoinDesignView::dispose();
2450}
2451
2452IMPL_LINK_NOARG( OQueryDesignView, SplitHdl, Splitter*, void )void OQueryDesignView::LinkStubSplitHdl(void * instance, Splitter
* data) { return static_cast<OQueryDesignView *>(instance
)->SplitHdl(data); } void OQueryDesignView::SplitHdl(__attribute__
((unused)) Splitter*)
2453{
2454 if (!getController().isReadOnly())
2455 {
2456 m_bInSplitHandler = true;
2457 m_aSplitter->SetPosPixel( Point( m_aSplitter->GetPosPixel().X(),m_aSplitter->GetSplitPosPixel() ) );
2458 static_cast<OQueryController&>(getController()).setSplitPos(m_aSplitter->GetSplitPosPixel());
2459 static_cast<OQueryController&>(getController()).setModified( true );
2460 Resize();
2461 m_bInSplitHandler = true;
2462 }
2463}
2464
2465void OQueryDesignView::Construct()
2466{
2467 m_pTableView = VclPtr<OQueryTableView>::Create(m_pScrollWindow,this);
1
Calling 'VclPtr::Create'
3
Returned allocated memory
4
Calling implicit destructor for 'VclPtr<dbaui::OQueryTableView>'
5
Calling '~Reference'
12
Returning from '~Reference'
13
Returning from destructor for 'VclPtr<dbaui::OQueryTableView>'
2468 ::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::AddWindow));
14
Calling 'VclPtr::operator dbaui::OJoinTableView *'
2469 OJoinDesignView::Construct();
2470}
2471
2472void OQueryDesignView::initialize()
2473{
2474 if(static_cast<OQueryController&>(getController()).getSplitPos() != -1)
2475 {
2476 m_aSplitter->SetPosPixel( Point( m_aSplitter->GetPosPixel().X(),static_cast<OQueryController&>(getController()).getSplitPos() ) );
2477 m_aSplitter->SetSplitPosPixel(static_cast<OQueryController&>(getController()).getSplitPos());
2478 }
2479 m_pSelectionBox->initialize();
2480 reset();
2481}
2482
2483void OQueryDesignView::resizeDocumentView(tools::Rectangle& _rPlayground)
2484{
2485 Point aPlaygroundPos( _rPlayground.TopLeft() );
2486 Size aPlaygroundSize( _rPlayground.GetSize() );
2487
2488 // calc the split pos, and forward it to the controller
2489 sal_Int32 nSplitPos = static_cast<OQueryController&>(getController()).getSplitPos();
2490 if ( 0 != aPlaygroundSize.Height() )
2491 {
2492 if ( ( -1 == nSplitPos )
2493 || ( nSplitPos >= aPlaygroundSize.Height() )
2494 )
2495 {
2496 // let the selection browse box determine an optimal size
2497 Size aSelectionBoxSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize );
2498 nSplitPos = aPlaygroundSize.Height() - aSelectionBoxSize.Height() - m_aSplitter->GetSizePixel().Height();
2499 // still an invalid size?
2500 if ( nSplitPos == -1 || nSplitPos >= aPlaygroundSize.Height() )
2501 nSplitPos = sal_Int32(aPlaygroundSize.Height()*0.6);
2502
2503 static_cast<OQueryController&>(getController()).setSplitPos(nSplitPos);
2504 }
2505
2506 if ( !m_bInSplitHandler )
2507 { // the resize is triggered by something else than the split handler
2508 // our main focus is to try to preserve the size of the selectionbrowse box
2509 Size aSelBoxSize = m_pSelectionBox->GetSizePixel();
2510 if ( aSelBoxSize.Height() )
2511 {
2512 // keep the size of the sel box constant
2513 nSplitPos = aPlaygroundSize.Height() - m_aSplitter->GetSizePixel().Height() - aSelBoxSize.Height();
2514
2515 // and if the box is smaller than the optimal size, try to do something about it
2516 Size aSelBoxOptSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize );
2517 if ( aSelBoxOptSize.Height() > aSelBoxSize.Height() )
2518 {
2519 nSplitPos = aPlaygroundSize.Height() - m_aSplitter->GetSizePixel().Height() - aSelBoxOptSize.Height();
2520 }
2521
2522 static_cast< OQueryController& >(getController()).setSplitPos( nSplitPos );
2523 }
2524 }
2525 }
2526
2527 // normalize the split pos
2528 Point aSplitPos( _rPlayground.Left(), nSplitPos );
2529 Size aSplitSize( _rPlayground.GetSize().Width(), m_aSplitter->GetSizePixel().Height() );
2530
2531 if( ( aSplitPos.Y() + aSplitSize.Height() ) > ( aPlaygroundSize.Height() ))
2532 aSplitPos.setY( aPlaygroundSize.Height() - aSplitSize.Height() );
2533
2534 if( aSplitPos.Y() <= aPlaygroundPos.Y() )
2535 aSplitPos.setY( aPlaygroundPos.Y() + sal_Int32(aPlaygroundSize.Height() * 0.2) );
2536
2537 // position the table
2538 Size aTableViewSize(aPlaygroundSize.Width(), aSplitPos.Y() - aPlaygroundPos.Y());
2539 m_pScrollWindow->SetPosSizePixel(aPlaygroundPos, aTableViewSize);
2540
2541 // position the selection browse box
2542 Point aPos( aPlaygroundPos.X(), aSplitPos.Y() + aSplitSize.Height() );
2543 m_pSelectionBox->SetPosSizePixel( aPos, Size( aPlaygroundSize.Width(), aPlaygroundSize.Height() - aSplitSize.Height() - aTableViewSize.Height() ));
2544
2545 // set the size of the splitter
2546 m_aSplitter->SetPosSizePixel( aSplitPos, aSplitSize );
2547 m_aSplitter->SetDragRectPixel( _rPlayground );
2548
2549 // just for completeness: there is no space left, we occupied it all ...
2550 _rPlayground.SetPos( _rPlayground.BottomRight() );
2551 _rPlayground.SetSize( Size( 0, 0 ) );
2552}
2553
2554void OQueryDesignView::setReadOnly(bool _bReadOnly)
2555{
2556 m_pSelectionBox->SetReadOnly(_bReadOnly);
2557}
2558
2559void OQueryDesignView::clear()
2560{
2561 m_pSelectionBox->ClearAll(); // clear the whole selection
2562 m_pTableView->ClearAll();
2563}
2564
2565void OQueryDesignView::copy()
2566{
2567 if( m_eChildFocus == SELECTION)
2568 m_pSelectionBox->copy();
2569}
2570
2571bool OQueryDesignView::isCutAllowed() const
2572{
2573 bool bAllowed = false;
2574 if ( SELECTION == m_eChildFocus )
2575 bAllowed = m_pSelectionBox->isCutAllowed();
2576 return bAllowed;
2577}
2578
2579bool OQueryDesignView::isPasteAllowed() const
2580{
2581 bool bAllowed = false;
2582 if ( SELECTION == m_eChildFocus )
2583 bAllowed = m_pSelectionBox->isPasteAllowed();
2584 return bAllowed;
2585}
2586
2587bool OQueryDesignView::isCopyAllowed() const
2588{
2589 bool bAllowed = false;
2590 if ( SELECTION == m_eChildFocus )
2591 bAllowed = m_pSelectionBox->isCopyAllowed();
2592 return bAllowed;
2593}
2594
2595void OQueryDesignView::stopTimer()
2596{
2597 m_pSelectionBox->stopTimer();
2598}
2599
2600void OQueryDesignView::startTimer()
2601{
2602 m_pSelectionBox->startTimer();
2603}
2604
2605void OQueryDesignView::cut()
2606{
2607 if( m_eChildFocus == SELECTION)
2608 {
2609 m_pSelectionBox->cut();
2610 static_cast<OQueryController&>(getController()).setModified(true);
2611 }
2612}
2613
2614void OQueryDesignView::paste()
2615{
2616 if( m_eChildFocus == SELECTION)
2617 {
2618 m_pSelectionBox->paste();
2619 static_cast<OQueryController&>(getController()).setModified(true);
2620 }
2621}
2622
2623void OQueryDesignView::TableDeleted(const OUString& rAliasName)
2624{
2625 // message that the table was removed from the window
2626 m_pSelectionBox->DeleteFields( rAliasName );
2627 static_cast<OQueryController&>(getController()).InvalidateFeature(ID_BROWSER_ADDTABLE( 10000 + 722 )); // inform the view again
2628}
2629
2630bool OQueryDesignView::HasFieldByAliasName(const OUString& rFieldName, OTableFieldDescRef const & rInfo) const
2631{
2632 return m_pSelectionBox->HasFieldByAliasName( rFieldName, rInfo);
2633}
2634
2635SqlParseError OQueryDesignView::InsertField( const OTableFieldDescRef& rInfo, bool bActivate)
2636{
2637 return m_pSelectionBox->InsertField( rInfo, BROWSER_INVALIDID((sal_uInt16) 0xFFFF), true/*bVis*/, bActivate ).is() ? eOk : eTooManyColumns;
2638}
2639
2640sal_Int32 OQueryDesignView::getColWidth(sal_uInt16 _nColPos) const
2641{
2642 static sal_Int32 s_nDefaultWidth = GetTextWidth("0") * 15;
2643 sal_Int32 nWidth = static_cast<OQueryController&>(getController()).getColWidth(_nColPos);
2644 if ( !nWidth )
2645 nWidth = s_nDefaultWidth;
2646 return nWidth;
2647}
2648
2649void OQueryDesignView::fillValidFields(const OUString& sAliasName, weld::ComboBox& rFieldList)
2650{
2651 rFieldList.clear();
2652
2653 bool bAllTables = sAliasName.isEmpty();
2654
2655 OJoinTableView::OTableWindowMap& rTabWins = m_pTableView->GetTabWinMap();
2656 OUString strCurrentPrefix;
2657 std::vector< OUString> aFields;
2658 for (auto const& tabWin : rTabWins)
2659 {
2660 OQueryTableWindow* pCurrentWin = static_cast<OQueryTableWindow*>(tabWin.second.get());
2661 if (bAllTables || (pCurrentWin->GetAliasName() == sAliasName))
2662 {
2663 strCurrentPrefix = pCurrentWin->GetAliasName() + ".";
2664
2665 pCurrentWin->EnumValidFields(aFields);
2666
2667 for (auto const& field : aFields)
2668 {
2669 if (bAllTables || field.toChar() == '*')
2670 rFieldList.append_text(strCurrentPrefix + field);
2671 else
2672 rFieldList.append_text(field);
2673 }
2674
2675 if (!bAllTables)
2676 // this means that I came into this block because the table name was exactly what I was looking for so I can end here
2677 // (and I prevent that fields get added more than once, if a table is repeated in TabWin)
2678 break;
2679 }
2680 }
2681}
2682
2683bool OQueryDesignView::PreNotify(NotifyEvent& rNEvt)
2684{
2685 if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS)
2686 {
2687 if ( m_pSelectionBox && m_pSelectionBox->HasChildPathFocus() )
2688 m_eChildFocus = SELECTION;
2689 else
2690 m_eChildFocus = TABLEVIEW;
2691 }
2692
2693 return OJoinDesignView::PreNotify(rNEvt);
2694}
2695
2696// check if the statement is correct when not returning false
2697bool OQueryDesignView::checkStatement()
2698{
2699 bool bRet = true;
2700 if ( m_pSelectionBox )
2701 bRet = m_pSelectionBox->Save(); // an error occurred so we return no
2702 return bRet;
2703}
2704
2705OUString OQueryDesignView::getStatement()
2706{
2707 OQueryController& rController = static_cast<OQueryController&>(getController());
2708 m_rController.clearError();
2709 // used for fields which aren't any longer in the statement
2710 OTableFields& rUnUsedFields = rController.getUnUsedFields();
2711 OTableFields().swap( rUnUsedFields );
2712
2713 // create the select columns
2714 sal_uInt32 nFieldcount = 0;
2715 OTableFields& rFieldList = rController.getTableFieldDesc();
2716 for (auto const& field : rFieldList)
2717 {
2718 if (!field->GetField().isEmpty() && field->IsVisible() )
2719 ++nFieldcount;
2720 else if (!field->GetField().isEmpty() &&
2721 !field->HasCriteria() &&
2722 field->isNoneFunction() &&
2723 field->GetOrderDir() == ORDER_NONE &&
2724 !field->IsGroupBy() &&
2725 field->GetFunction().isEmpty() )
2726 rUnUsedFields.push_back(field);
2727 }
2728 if ( !nFieldcount ) // no visible fields so return
2729 {
2730 rUnUsedFields = rFieldList;
2731 return OUString();
2732 }
2733
2734 OQueryTableView::OTableWindowMap& rTabList = m_pTableView->GetTabWinMap();
2735 sal_uInt32 nTabcount = rTabList.size();
2736
2737 OUString aFieldListStr(GenerateSelectList(this,rFieldList,nTabcount>1));
2738 if( aFieldListStr.isEmpty() )
2739 return OUString();
2740
2741 // Exception handling, if no fields have been passed we should not
2742 // change the tab page
2743 // TabBarSelectHdl will query the SQL-OUString for STATEMENT_NOFIELDS
2744 // and trigger an error message
2745 // ----------------- Build table list ----------------------
2746
2747 const auto& rConnList = m_pTableView->getTableConnections();
2748 Reference< XConnection> xConnection = rController.getConnection();
2749 OUString aTableListStr(GenerateFromClause(xConnection,&rTabList,rConnList));
2750 OSL_ENSURE(!aTableListStr.isEmpty(), "OQueryDesignView::getStatement() : unexpected : have Fields, but no Tables !")do { if (true && (!(!aTableListStr.isEmpty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "2750" ": "), "%s", "OQueryDesignView::getStatement() : unexpected : have Fields, but no Tables !"
); } } while (false)
;
2751 // if fields exist now, these only can be created by inserting from an already existing table; if on the other hand
2752 // a table is deleted, also the belonging fields will be deleted -> therefore it CANNOT occur that fields
2753 // exist but no tables exist (and aFieldListStr has its length, I secure this above)
2754 OUStringBuffer aHavingStr,aCriteriaListStr;
2755
2756 // ----------------- build the criteria ----------------------
2757 if (!GenerateCriterias(this,aCriteriaListStr,aHavingStr,rFieldList, nTabcount > 1))
2758 return OUString();
2759
2760 OUString aJoinCrit;
2761 GenerateInnerJoinCriterias(xConnection,aJoinCrit,rConnList);
2762 if(!aJoinCrit.isEmpty())
2763 {
2764 OUString aTmp = "( " + aJoinCrit + " )";
2765 if(!aCriteriaListStr.isEmpty())
2766 {
2767 aTmp += C_AND + aCriteriaListStr.makeStringAndClear();
2768 }
2769 aCriteriaListStr = aTmp;
2770 }
2771 // ----------------- construct statement ----------------------
2772 OUStringBuffer aSqlCmd("SELECT ");
2773 if(rController.isDistinct())
2774 aSqlCmd.append(" DISTINCT ");
2775 aSqlCmd.append(aFieldListStr);
2776 aSqlCmd.append(" FROM ");
2777 aSqlCmd.append(aTableListStr);
2778
2779 if (!aCriteriaListStr.isEmpty())
2780 {
2781 aSqlCmd.append(" WHERE ");
2782 aSqlCmd.append(aCriteriaListStr.makeStringAndClear());
2783 }
2784 Reference<XDatabaseMetaData> xMeta;
2785 if ( xConnection.is() )
2786 xMeta = xConnection->getMetaData();
2787 bool bUseAlias = nTabcount > 1;
2788 if ( xMeta.is() )
2789 bUseAlias = bUseAlias || !xMeta->supportsGroupByUnrelated();
2790
2791 aSqlCmd.append(GenerateGroupBy(this,rFieldList,bUseAlias));
2792 // ----------------- construct GroupBy and attach ------------
2793 if(!aHavingStr.isEmpty())
2794 {
2795 aSqlCmd.append(" HAVING ");
2796 aSqlCmd.append(aHavingStr.makeStringAndClear());
2797 }
2798 // ----------------- construct sorting and attach ------------
2799 OUString sOrder;
2800 SqlParseError eErrorCode = eOk;
2801 if ( (eErrorCode = GenerateOrder(this,rFieldList,nTabcount > 1,sOrder)) == eOk)
2802 aSqlCmd.append(sOrder);
2803 else
2804 {
2805 if ( !m_rController.hasError() )
2806 m_rController.appendError( getParseErrorMessage( eErrorCode ) );
2807
2808 m_rController.displayError();
2809 }
2810 // --------------------- Limit Clause -------------------
2811 {
2812 const sal_Int64 nLimit = rController.getLimit();
2813 if( nLimit != -1 )
2814 {
2815 aSqlCmd.append( " LIMIT " ).append( OUString::number(nLimit) );
2816 }
2817 }
2818
2819 OUString sSQL = aSqlCmd.makeStringAndClear();
2820 if ( xConnection.is() )
2821 {
2822 ::connectivity::OSQLParser& rParser( rController.getParser() );
2823 OUString sErrorMessage;
2824 std::unique_ptr<OSQLParseNode> pParseNode( rParser.parseTree( sErrorMessage, sSQL, true ) );
2825 if (pParseNode)
2826 {
2827 OSQLParseNode* pNode = pParseNode->getChild(3)->getChild(1);
2828 if ( pNode->count() > 1 )
2829 {
2830 ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1);
2831 if ( pCondition ) // no where clause
2832 {
2833 OSQLParseNode::compress(pCondition);
2834 OUString sTemp;
2835 pParseNode->parseNodeToStr(sTemp,xConnection);
2836 sSQL = sTemp;
2837 }
2838 }
2839 }
2840 }
2841 return sSQL;
2842}
2843
2844void OQueryDesignView::setSlotEnabled(sal_Int32 _nSlotId, bool _bEnable)
2845{
2846 sal_uInt16 nRow;
2847 switch (_nSlotId)
2848 {
2849 case SID_QUERY_VIEW_FUNCTIONS( ((((((((10000 + 1499) + 1) + 499) + 1) + 100) + 1) + 149) +
1) + 46 )
:
2850 nRow = BROW_FUNCTION_ROW5;
2851 break;
2852 case SID_QUERY_VIEW_TABLES( ((((((((10000 + 1499) + 1) + 499) + 1) + 100) + 1) + 149) +
1) + 47 )
:
2853 nRow = BROW_TABLE_ROW2;
2854 break;
2855 case SID_QUERY_VIEW_ALIASES( ((((((((10000 + 1499) + 1) + 499) + 1) + 100) + 1) + 149) +
1) + 48 )
:
2856 nRow = BROW_COLUMNALIAS_ROW1;
2857 break;
2858 default:
2859 // ????????????
2860 nRow = 0;
2861 break;
2862 }
2863 m_pSelectionBox->SetRowVisible(nRow,_bEnable);
2864 m_pSelectionBox->Invalidate();
2865}
2866
2867bool OQueryDesignView::isSlotEnabled(sal_Int32 _nSlotId)
2868{
2869 sal_uInt16 nRow;
2870 switch (_nSlotId)
2871 {
2872 case SID_QUERY_VIEW_FUNCTIONS( ((((((((10000 + 1499) + 1) + 499) + 1) + 100) + 1) + 149) +
1) + 46 )
:
2873 nRow = BROW_FUNCTION_ROW5;
2874 break;
2875 case SID_QUERY_VIEW_TABLES( ((((((((10000 + 1499) + 1) + 499) + 1) + 100) + 1) + 149) +
1) + 47 )
:
2876 nRow = BROW_TABLE_ROW2;
2877 break;
2878 case SID_QUERY_VIEW_ALIASES( ((((((((10000 + 1499) + 1) + 499) + 1) + 100) + 1) + 149) +
1) + 48 )
:
2879 nRow = BROW_COLUMNALIAS_ROW1;
2880 break;
2881 default:
2882 // ?????????
2883 nRow = 0;
2884 break;
2885 }
2886 return m_pSelectionBox->IsRowVisible(nRow);
2887}
2888
2889void OQueryDesignView::SaveUIConfig()
2890{
2891 OQueryController& rCtrl = static_cast<OQueryController&>(getController());
2892 rCtrl.SaveTabWinsPosSize( &m_pTableView->GetTabWinMap(), m_pScrollWindow->GetHScrollBar().GetThumbPos(), m_pScrollWindow->GetVScrollBar().GetThumbPos() );
2893 rCtrl.setVisibleRows( m_pSelectionBox->GetNoneVisibleRows() );
2894 if ( m_aSplitter->GetSplitPosPixel() != 0 )
2895 rCtrl.setSplitPos( m_aSplitter->GetSplitPosPixel() );
2896}
2897
2898std::unique_ptr<OSQLParseNode> OQueryDesignView::getPredicateTreeFromEntry(const OTableFieldDescRef& pEntry,
2899 const OUString& _sCriteria,
2900 OUString& _rsErrorMessage,
2901 Reference<XPropertySet>& _rxColumn) const
2902{
2903 OSL_ENSURE(pEntry.is(),"Entry is null!")do { if (true && (!(pEntry.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "2903" ": "), "%s", "Entry is null!"); } } while (false)
;
2904 if(!pEntry.is())
2905 return nullptr;
2906 Reference< XConnection> xConnection = static_cast<OQueryController&>(getController()).getConnection();
2907 if(!xConnection.is())
2908 return nullptr;
2909
2910 ::connectivity::OSQLParser& rParser( static_cast<OQueryController&>(getController()).getParser() );
2911 OQueryTableWindow* pWin = static_cast<OQueryTableWindow*>(pEntry->GetTabWindow());
2912
2913 // special handling for functions
2914 if ( pEntry->GetFunctionType() & (FKT_OTHER | FKT_AGGREGATE | FKT_NUMERIC) )
2915 {
2916 // we have a function here so we have to distinguish the type of return value
2917 OUString sFunction;
2918 if ( pEntry->isNumericOrAggregateFunction() )
2919 sFunction = pEntry->GetFunction().getToken(0, '(');
2920
2921 if ( sFunction.isEmpty() )
2922 sFunction = pEntry->GetField().getToken(0, '(');
2923
2924 sal_Int32 nType = ::connectivity::OSQLParser::getFunctionReturnType(sFunction,&rParser.getContext());
2925 if ( nType == DataType::OTHER || (sFunction.isEmpty() && pEntry->isNumericOrAggregateFunction()) )
2926 {
2927 // first try the international version
2928 OUString sSql = "SELECT * FROM x WHERE " + pEntry->GetField() + _sCriteria;
2929 std::unique_ptr<OSQLParseNode> pParseNode( rParser.parseTree( _rsErrorMessage, sSql, true ) );
2930 nType = DataType::DOUBLE;
2931 if (pParseNode)
2932 {
2933 OSQLParseNode* pColumnRef = pParseNode->getByRule(OSQLParseNode::column_ref);
2934 if ( pColumnRef )
2935 {
2936 OTableFieldDescRef aField = new OTableFieldDesc();
2937 if ( eOk == FillDragInfo(this,pColumnRef,aField) )
2938 {
2939 nType = aField->GetDataType();
2940 }
2941 }
2942 }
2943 }
2944
2945 Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
2946 parse::OParseColumn* pColumn = new parse::OParseColumn( pEntry->GetField(),
2947 OUString(),
2948 OUString(),
2949 OUString(),
2950 ColumnValue::NULLABLE_UNKNOWN,
2951 0,
2952 0,
2953 nType,
2954 false,
2955 false,
2956 xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),
2957 OUString(),
2958 OUString(),
2959 OUString());
2960 _rxColumn = pColumn;
2961 pColumn->setFunction(true);
2962 pColumn->setRealName(pEntry->GetField());
2963 }
2964 else
2965 {
2966 if (pWin)
2967 {
2968 Reference<XNameAccess> xColumns = pWin->GetOriginalColumns();
2969 if (xColumns.is() && xColumns->hasByName(pEntry->GetField()))
2970 xColumns->getByName(pEntry->GetField()) >>= _rxColumn;
2971 }
2972 }
2973
2974 // _rxColumn, if it is a "lookup" column, not a computed column,
2975 // is guaranteed to be the column taken from the *source* of the column,
2976 // that is either a table or another query.
2977 // _rxColumn is *not* taken from the columns of the query we are constructing
2978 // (and rightfully so, since it may not be part of these columns; SELECT A FROM t WHERE B = foo)
2979 // If it is a computed column, we just constructed it above, with same Name and RealName.
2980 // In all cases, we should use the "external" name of the column, not the "RealName";
2981 // the latter is the name that the column had in the source of the source query.
2982 // An example: we are designing "SELECT A, B FROM q WHERE C='foo'"
2983 // q itself is query "SELECT aye AS A, bee as B, cee as C FROM t"
2984 // We are currently treating the entry "C='foo'"
2985 // Then _rxColumn has Name "C" and RealName "cee". We should *obviously* use "C", not "cee".
2986 std::unique_ptr<OSQLParseNode> pParseNode = rParser.predicateTree( _rsErrorMessage,
2987 _sCriteria,
2988 static_cast<OQueryController&>(getController()).getNumberFormatter(),
2989 _rxColumn,
2990 false);
2991 return pParseNode;
2992}
2993
2994void OQueryDesignView::GetFocus()
2995{
2996 OJoinDesignView::GetFocus();
2997 if ( m_pSelectionBox && !m_pSelectionBox->HasChildPathFocus() )
2998 {
2999 // first we have to deactivate the current cell to refill when necessary
3000 m_pSelectionBox->DeactivateCell();
3001 m_pSelectionBox->ActivateCell(m_pSelectionBox->GetCurRow(), m_pSelectionBox->GetCurColumnId());
3002 m_pSelectionBox->GrabFocus();
3003 }
3004}
3005
3006void OQueryDesignView::reset()
3007{
3008 m_pTableView->ClearAll();
3009 m_pTableView->ReSync();
3010}
3011
3012void OQueryDesignView::setNoneVisibleRow(sal_Int32 _nRows)
3013{
3014 m_pSelectionBox->SetNoneVisibleRow(_nRows);
3015}
3016
3017void OQueryDesignView::initByFieldDescriptions( const Sequence< PropertyValue >& i_rFieldDescriptions )
3018{
3019 OQueryController& rController = static_cast< OQueryController& >( getController() );
3020
3021 m_pSelectionBox->PreFill();
3022 m_pSelectionBox->SetReadOnly( rController.isReadOnly() );
3023 m_pSelectionBox->Fill();
3024
3025 for ( auto const & field : i_rFieldDescriptions )
3026 {
3027 ::rtl::Reference< OTableFieldDesc > pField( new OTableFieldDesc() );
3028 pField->Load( field, true );
3029 InsertField( pField, false );
3030 }
3031
3032 rController.ClearUndoManager();
3033 m_pSelectionBox->Invalidate();
3034}
3035
3036bool OQueryDesignView::initByParseIterator( ::dbtools::SQLExceptionInfo* _pErrorInfo )
3037{
3038 SqlParseError eErrorCode = eNativeMode;
3039 m_rController.clearError();
3040
3041 try
3042 {
3043 eErrorCode = InitFromParseNodeImpl( this, m_pSelectionBox );
3044
3045 if ( eErrorCode != eOk )
3046 {
3047 if ( !m_rController.hasError() )
3048 m_rController.appendError( getParseErrorMessage( eErrorCode ) );
3049
3050 if ( _pErrorInfo )
3051 {
3052 *_pErrorInfo = m_rController.getError();
3053 }
3054 else
3055 {
3056 m_rController.displayError();
3057 }
3058 }
3059 }
3060 catch ( const Exception& )
3061 {
3062 DBG_UNHANDLED_EXCEPTION("dbaccess")DbgUnhandledException( DbgGetCaughtException(), __func__, "/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3062" ": ", "dbaccess" );
;
3063 }
3064 return eErrorCode == eOk;
3065}
3066
3067// Utility function for fillFunctionInfo
3068namespace {
3069 sal_Int32 char_datatype(const::connectivity::OSQLParseNode* pDataType, const unsigned int offset) {
3070 int cnt = pDataType->count() - offset;
3071 if ( cnt < 0 )
3072 {
3073 OSL_FAIL("internal error in decoding character datatype specification")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3073" ": "), "%s", "internal error in decoding character datatype specification"
); } } while (false)
;
3074 return DataType::VARCHAR;
3075 }
3076 else if ( cnt == 0 )
3077 {
3078 if ( offset == 0 )
3079 {
3080 // The datatype is the node itself
3081 if ( SQL_ISTOKENOR2 (pDataType, CHARACTER, CHAR)((pDataType)->isToken() && ( (pDataType)->getTokenID
() == SQL_TOKEN_CHARACTER || (pDataType)->getTokenID() == SQL_TOKEN_CHAR
))
)
3082 return DataType::CHAR;
3083 else if ( SQL_ISTOKEN (pDataType, VARCHAR)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_VARCHAR)
)
3084 return DataType::VARCHAR;
3085 else if ( SQL_ISTOKEN (pDataType, CLOB)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_CLOB)
)
3086 return DataType::CLOB;
3087 else
3088 {
3089 OSL_FAIL("unknown/unexpected token in decoding character datatype specification")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3089" ": "), "%s", "unknown/unexpected token in decoding character datatype specification"
); } } while (false)
;
3090 return DataType::VARCHAR;
3091 }
3092 }
3093 else
3094 {
3095 // No child left to read!
3096 OSL_FAIL("incomplete datatype in decoding character datatype specification")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3096" ": "), "%s", "incomplete datatype in decoding character datatype specification"
); } } while (false)
;
3097 return DataType::VARCHAR;
3098 }
3099 }
3100
3101 if ( SQL_ISTOKEN(pDataType->getChild(offset), NATIONAL)((pDataType->getChild(offset))->isToken() && (pDataType
->getChild(offset))->getTokenID() == SQL_TOKEN_NATIONAL
)
)
3102 return char_datatype(pDataType, offset+1);
3103 else if ( SQL_ISTOKENOR3(pDataType->getChild(offset), CHARACTER, CHAR, NCHAR)((pDataType->getChild(offset))->isToken() && ( (
pDataType->getChild(offset))->getTokenID() == SQL_TOKEN_CHARACTER
|| (pDataType->getChild(offset))->getTokenID() == SQL_TOKEN_CHAR
|| (pDataType->getChild(offset))->getTokenID() == SQL_TOKEN_NCHAR
))
)
3104 {
3105 if ( cnt > 2 && SQL_ISTOKEN(pDataType->getChild(offset+1), LARGE)((pDataType->getChild(offset+1))->isToken() && (
pDataType->getChild(offset+1))->getTokenID() == SQL_TOKEN_LARGE
)
&& SQL_ISTOKEN(pDataType->getChild(offset+2), OBJECT)((pDataType->getChild(offset+2))->isToken() && (
pDataType->getChild(offset+2))->getTokenID() == SQL_TOKEN_OBJECT
)
)
3106 return DataType::CLOB;
3107 else if ( cnt > 1 && SQL_ISTOKEN(pDataType->getChild(offset+1), VARYING)((pDataType->getChild(offset+1))->isToken() && (
pDataType->getChild(offset+1))->getTokenID() == SQL_TOKEN_VARYING
)
)
3108 return DataType::VARCHAR;
3109 else
3110 return DataType::CHAR;
3111 }
3112 else if ( SQL_ISTOKEN (pDataType->getChild(offset), VARCHAR)((pDataType->getChild(offset))->isToken() && (pDataType
->getChild(offset))->getTokenID() == SQL_TOKEN_VARCHAR)
)
3113 return DataType::VARCHAR;
3114 else if ( SQL_ISTOKENOR2 (pDataType->getChild(offset), CLOB, NCLOB)((pDataType->getChild(offset))->isToken() && ( (
pDataType->getChild(offset))->getTokenID() == SQL_TOKEN_CLOB
|| (pDataType->getChild(offset))->getTokenID() == SQL_TOKEN_NCLOB
))
)
3115 return DataType::CLOB;
3116
3117 OSL_FAIL("unrecognised character datatype")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3117" ": "), "%s", "unrecognised character datatype"); }
} while (false)
;
3118 return DataType::VARCHAR;
3119 }
3120}
3121
3122// Try to guess the type of an expression in simple cases.
3123// Originally meant to be called only on a function call (hence the misnomer),
3124// but now tries to do the best it can also in other cases.
3125// Don't completely rely on fillFunctionInfo,
3126// it won't look at the function's arguments to find the return type
3127// (in particular, in the case of general_set_fct,
3128// the return type is the type of the argument;
3129// if that is (as is typical) a column reference,
3130// it is the type of the column).
3131// TODO: There is similar "guess the expression's type" code in several places:
3132// SelectionBrowseBox.cxx: OSelectionBrowseBox::saveField
3133// QueryDesignView.cxx: InstallFields, GetOrderCriteria, GetGroupCriteria
3134// If possible, they should be factorised into this function
3135// (which should then be renamed...)
3136
3137void OQueryDesignView::fillFunctionInfo( const ::connectivity::OSQLParseNode* pNode
3138 ,const OUString& sFunctionTerm
3139 ,OTableFieldDescRef& aInfo)
3140{
3141 // get the type of the expression, as far as easily possible
3142 OQueryController& rController = static_cast<OQueryController&>(getController());
3143 sal_Int32 nDataType = DataType::DOUBLE;
3144 switch(pNode->getNodeType())
3145 {
3146 case SQLNodeType::Concat:
3147 case SQLNodeType::String:
3148 nDataType = DataType::VARCHAR;
3149 break;
3150 case SQLNodeType::IntNum:
3151 nDataType = DataType::INTEGER;
3152 break;
3153 case SQLNodeType::ApproxNum:
3154 nDataType = DataType::DOUBLE;
3155 break;
3156 case SQLNodeType::AccessDate:
3157 nDataType = DataType::TIMESTAMP;
3158 break;
3159 case SQLNodeType::Equal:
3160 case SQLNodeType::Less:
3161 case SQLNodeType::Great:
3162 case SQLNodeType::LessEq:
3163 case SQLNodeType::GreatEq:
3164 case SQLNodeType::NotEqual:
3165 nDataType = DataType::BOOLEAN;
3166 break;
3167 case SQLNodeType::Name:
3168 case SQLNodeType::ListRule:
3169 case SQLNodeType::CommaListRule:
3170 case SQLNodeType::Keyword:
3171 case SQLNodeType::Punctuation:
3172 OSL_FAIL("Unexpected SQL Node Type")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3172" ": "), "%s", "Unexpected SQL Node Type"); } } while
(false)
;
3173 break;
3174 case SQLNodeType::Rule:
3175 switch(pNode->getKnownRuleID())
3176 {
3177 case OSQLParseNode::select_statement:
3178 case OSQLParseNode::table_exp:
3179 case OSQLParseNode::table_ref_commalist:
3180 case OSQLParseNode::table_ref:
3181 case OSQLParseNode::catalog_name:
3182 case OSQLParseNode::schema_name:
3183 case OSQLParseNode::table_name:
3184 case OSQLParseNode::opt_column_commalist:
3185 case OSQLParseNode::column_commalist:
3186 case OSQLParseNode::column_ref_commalist:
3187 case OSQLParseNode::column_ref:
3188 case OSQLParseNode::opt_order_by_clause:
3189 case OSQLParseNode::ordering_spec_commalist:
3190 case OSQLParseNode::ordering_spec:
3191 case OSQLParseNode::opt_asc_desc:
3192 case OSQLParseNode::where_clause:
3193 case OSQLParseNode::opt_where_clause:
3194 case OSQLParseNode::opt_escape:
3195 case OSQLParseNode::scalar_exp_commalist:
3196 case OSQLParseNode::scalar_exp: // Seems to never be generated?
3197 case OSQLParseNode::parameter_ref:
3198 case OSQLParseNode::parameter:
3199 case OSQLParseNode::range_variable:
3200 case OSQLParseNode::delete_statement_positioned:
3201 case OSQLParseNode::delete_statement_searched:
3202 case OSQLParseNode::update_statement_positioned:
3203 case OSQLParseNode::update_statement_searched:
3204 case OSQLParseNode::assignment_commalist:
3205 case OSQLParseNode::assignment:
3206 case OSQLParseNode::insert_statement:
3207 case OSQLParseNode::insert_atom_commalist:
3208 case OSQLParseNode::insert_atom:
3209 case OSQLParseNode::from_clause:
3210 case OSQLParseNode::qualified_join:
3211 case OSQLParseNode::cross_union:
3212 case OSQLParseNode::select_sublist:
3213 case OSQLParseNode::join_type:
3214 case OSQLParseNode::named_columns_join:
3215 case OSQLParseNode::joined_table:
3216 case OSQLParseNode::sql_not:
3217 case OSQLParseNode::manipulative_statement:
3218 case OSQLParseNode::value_exp_commalist:
3219 case OSQLParseNode::union_statement:
3220 case OSQLParseNode::outer_join_type:
3221 case OSQLParseNode::selection:
3222 case OSQLParseNode::base_table_def:
3223 case OSQLParseNode::base_table_element_commalist:
3224 case OSQLParseNode::data_type:
3225 case OSQLParseNode::column_def:
3226 case OSQLParseNode::table_node:
3227 case OSQLParseNode::as_clause:
3228 case OSQLParseNode::opt_as:
3229 case OSQLParseNode::op_column_commalist:
3230 case OSQLParseNode::table_primary_as_range_column:
3231 case OSQLParseNode::character_string_type:
3232 case OSQLParseNode::comparison:
3233 OSL_FAIL("Unexpected SQL RuleID")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3233" ": "), "%s", "Unexpected SQL RuleID"); } } while (
false)
;
3234 break;
3235 case OSQLParseNode::column:
3236 case OSQLParseNode::column_val:
3237 OSL_FAIL("Cannot guess column type")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3237" ": "), "%s", "Cannot guess column type"); } } while
(false)
;
3238 break;
3239 case OSQLParseNode::values_or_query_spec:
3240 OSL_FAIL("Cannot guess VALUES type")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3240" ": "), "%s", "Cannot guess VALUES type"); } } while
(false)
;
3241 break;
3242 case OSQLParseNode::derived_column:
3243 OSL_FAIL("Cannot guess computed column type")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3243" ": "), "%s", "Cannot guess computed column type")
; } } while (false)
;
3244 break;
3245 case OSQLParseNode::subquery:
3246 OSL_FAIL("Cannot guess subquery return type")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3246" ": "), "%s", "Cannot guess subquery return type")
; } } while (false)
;
3247 break;
3248 case OSQLParseNode::search_condition:
3249 case OSQLParseNode::comparison_predicate:
3250 case OSQLParseNode::between_predicate:
3251 case OSQLParseNode::like_predicate:
3252 case OSQLParseNode::test_for_null:
3253 case OSQLParseNode::boolean_term:
3254 case OSQLParseNode::boolean_primary:
3255 case OSQLParseNode::in_predicate:
3256 case OSQLParseNode::existence_test:
3257 case OSQLParseNode::unique_test:
3258 case OSQLParseNode::all_or_any_predicate:
3259 case OSQLParseNode::join_condition:
3260 case OSQLParseNode::boolean_factor:
3261 case OSQLParseNode::comparison_predicate_part_2:
3262 case OSQLParseNode::parenthesized_boolean_value_expression:
3263 case OSQLParseNode::other_like_predicate_part_2:
3264 case OSQLParseNode::between_predicate_part_2:
3265 nDataType = DataType::BOOLEAN;
3266 break;
3267 case OSQLParseNode::num_value_exp:
3268 case OSQLParseNode::extract_exp:
3269 case OSQLParseNode::term:
3270 case OSQLParseNode::factor:
3271 // Might by an integer or a float; take the most generic
3272 nDataType = DataType::DOUBLE;
3273 break;
3274 case OSQLParseNode::value_exp_primary:
3275 case OSQLParseNode::value_exp:
3276 case OSQLParseNode::odbc_call_spec:
3277 // Really, we don't know. Let the default.
3278 break;
3279 case OSQLParseNode::position_exp:
3280 case OSQLParseNode::length_exp:
3281 nDataType = DataType::INTEGER;
3282 break;
3283 case OSQLParseNode::char_value_exp:
3284 case OSQLParseNode::char_value_fct:
3285 case OSQLParseNode::fold:
3286 case OSQLParseNode::char_substring_fct:
3287 case OSQLParseNode::char_factor:
3288 case OSQLParseNode::concatenation:
3289 nDataType = DataType::VARCHAR;
3290 break;
3291 case OSQLParseNode::datetime_primary:
3292 nDataType = DataType::TIMESTAMP;
3293 break;
3294 case OSQLParseNode::bit_value_fct:
3295 nDataType = DataType::BINARY;
3296 break;
3297 case OSQLParseNode::general_set_fct: // May depend on argument; ignore that for now
3298 case OSQLParseNode::set_fct_spec:
3299 {
3300 if (pNode->count() == 0)
3301 {
3302 // This is not a function call, no sense to continue with a function return type lookup
3303 OSL_FAIL("Got leaf SQL node where non-leaf expected")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3303" ": "), "%s", "Got leaf SQL node where non-leaf expected"
); } } while (false)
;
3304 break;
3305 }
3306 const OSQLParseNode* pFunctionName = pNode->getChild(0);
3307 if ( SQL_ISPUNCTUATION(pFunctionName,"{")((pFunctionName)->getNodeType() == SQLNodeType::Punctuation
&& (pFunctionName)->getTokenValue() == ("{"))
)
3308 {
3309 if ( pNode->count() == 3 )
3310 return fillFunctionInfo( pNode->getChild(1), sFunctionTerm, aInfo );
3311 else
3312 OSL_FAIL("ODBC escape not in recognised form")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3312" ": "), "%s", "ODBC escape not in recognised form"
); } } while (false)
;
3313 break;
3314 }
3315 else
3316 {
3317 if ( SQL_ISRULEOR2(pNode,length_exp,char_value_fct)((pNode)->isRule() && ( (pNode)->getRuleID() ==
OSQLParser::RuleID(OSQLParseNode::length_exp) || (pNode)->
getRuleID() == OSQLParser::RuleID(OSQLParseNode::char_value_fct
)))
)
3318 pFunctionName = pFunctionName->getChild(0);
3319
3320 OUString sFunctionName = pFunctionName->getTokenValue();
3321 if ( sFunctionName.isEmpty() )
3322 sFunctionName = OStringToOUString(OSQLParser::TokenIDToStr(pFunctionName->getTokenID()),RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
3323
3324 nDataType = OSQLParser::getFunctionReturnType(
3325 sFunctionName
3326 ,&rController.getParser().getContext());
3327 }
3328 break;
3329 }
3330 case OSQLParseNode::odbc_fct_spec:
3331 {
3332 if (pNode->count() != 2)
3333 {
3334 OSL_FAIL("interior of ODBC escape not in recognised shape")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3334" ": "), "%s", "interior of ODBC escape not in recognised shape"
); } } while (false)
;
3335 break;
3336 }
3337
3338 const OSQLParseNode* const pEscapeType = pNode->getChild(0);
3339 if (SQL_ISTOKEN(pEscapeType, TS)((pEscapeType)->isToken() && (pEscapeType)->getTokenID
() == SQL_TOKEN_TS)
)
3340 nDataType = DataType::TIMESTAMP;
3341 else if (SQL_ISTOKEN(pEscapeType, D)((pEscapeType)->isToken() && (pEscapeType)->getTokenID
() == SQL_TOKEN_D)
)
3342 nDataType = DataType::DATE;
3343 else if (SQL_ISTOKEN(pEscapeType, T)((pEscapeType)->isToken() && (pEscapeType)->getTokenID
() == SQL_TOKEN_T)
)
3344 nDataType = DataType::TIME;
3345 else if (SQL_ISTOKEN(pEscapeType, FN)((pEscapeType)->isToken() && (pEscapeType)->getTokenID
() == SQL_TOKEN_FN)
)
3346 return fillFunctionInfo( pNode->getChild(1), sFunctionTerm, aInfo );
3347 else
3348 OSL_FAIL("Unknown ODBC escape")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3348" ": "), "%s", "Unknown ODBC escape"); } } while (false
)
;
3349 break;
3350 }
3351 case OSQLParseNode::cast_spec:
3352 {
3353 if ( pNode->count() != 6 || !SQL_ISTOKEN(pNode->getChild(3), AS)((pNode->getChild(3))->isToken() && (pNode->
getChild(3))->getTokenID() == SQL_TOKEN_AS)
)
3354 {
3355 OSL_FAIL("CAST not in recognised shape")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3355" ": "), "%s", "CAST not in recognised shape"); } }
while (false)
;
3356 break;
3357 }
3358 const OSQLParseNode *pCastTarget = pNode->getChild(4);
3359 if ( SQL_ISTOKENOR2(pCastTarget, INTEGER, INT)((pCastTarget)->isToken() && ( (pCastTarget)->getTokenID
() == SQL_TOKEN_INTEGER || (pCastTarget)->getTokenID() == SQL_TOKEN_INT
))
)
3360 nDataType = DataType::INTEGER;
3361 else if ( SQL_ISTOKEN(pCastTarget, SMALLINT)((pCastTarget)->isToken() && (pCastTarget)->getTokenID
() == SQL_TOKEN_SMALLINT)
)
3362 nDataType = DataType::SMALLINT;
3363 else if ( SQL_ISTOKEN(pCastTarget, BIGINT)((pCastTarget)->isToken() && (pCastTarget)->getTokenID
() == SQL_TOKEN_BIGINT)
)
3364 nDataType = DataType::BIGINT;
3365 else if ( SQL_ISTOKEN(pCastTarget, FLOAT)((pCastTarget)->isToken() && (pCastTarget)->getTokenID
() == SQL_TOKEN_FLOAT)
)
3366 nDataType = DataType::FLOAT;
3367 else if ( SQL_ISTOKEN(pCastTarget, REAL)((pCastTarget)->isToken() && (pCastTarget)->getTokenID
() == SQL_TOKEN_REAL)
)
3368 nDataType = DataType::REAL;
3369 else if ( SQL_ISTOKEN(pCastTarget, DOUBLE)((pCastTarget)->isToken() && (pCastTarget)->getTokenID
() == SQL_TOKEN_DOUBLE)
)
3370 nDataType = DataType::DOUBLE;
3371 else if ( SQL_ISTOKEN(pCastTarget, BOOLEAN)((pCastTarget)->isToken() && (pCastTarget)->getTokenID
() == SQL_TOKEN_BOOLEAN)
)
3372 nDataType = DataType::BOOLEAN;
3373 else if ( SQL_ISTOKEN(pCastTarget, DATE)((pCastTarget)->isToken() && (pCastTarget)->getTokenID
() == SQL_TOKEN_DATE)
)
3374 nDataType = DataType::DATE;
3375 else if ( pCastTarget->count() > 0 )
3376 {
3377 const OSQLParseNode *pDataType = pCastTarget->getChild(0);
3378 while (pDataType->count() > 0)
3379 {
3380 pCastTarget = pDataType;
3381 pDataType = pDataType->getChild(0);
3382 }
3383 if ( SQL_ISTOKEN (pDataType, TIME)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_TIME)
)
3384 nDataType = DataType::TIME;
3385 else if ( SQL_ISTOKEN (pDataType, TIMESTAMP)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_TIMESTAMP)
)
3386 nDataType = DataType::TIMESTAMP;
3387 else if ( SQL_ISTOKENOR3 (pDataType, CHARACTER, CHAR, NCHAR)((pDataType)->isToken() && ( (pDataType)->getTokenID
() == SQL_TOKEN_CHARACTER || (pDataType)->getTokenID() == SQL_TOKEN_CHAR
|| (pDataType)->getTokenID() == SQL_TOKEN_NCHAR ))
)
3388 nDataType = char_datatype(pCastTarget, 0);
3389 else if ( SQL_ISTOKEN (pDataType, VARCHAR)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_VARCHAR)
)
3390 nDataType = DataType::VARCHAR;
3391 else if ( SQL_ISTOKEN (pDataType, CLOB)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_CLOB)
)
3392 nDataType = DataType::CLOB;
3393 else if ( SQL_ISTOKEN (pDataType, NATIONAL)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_NATIONAL)
)
3394 nDataType = char_datatype(pCastTarget, 1);
3395 else if ( SQL_ISTOKEN (pDataType, BINARY)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_BINARY)
)
3396 {
3397 if ( pCastTarget->count() > 2 && SQL_ISTOKEN(pCastTarget->getChild(1), LARGE)((pCastTarget->getChild(1))->isToken() && (pCastTarget
->getChild(1))->getTokenID() == SQL_TOKEN_LARGE)
&& SQL_ISTOKEN(pCastTarget->getChild(2), OBJECT)((pCastTarget->getChild(2))->isToken() && (pCastTarget
->getChild(2))->getTokenID() == SQL_TOKEN_OBJECT)
)
3398 nDataType = DataType::BLOB;
3399 else if ( pCastTarget->count() > 1 && SQL_ISTOKEN(pCastTarget->getChild(1), VARYING)((pCastTarget->getChild(1))->isToken() && (pCastTarget
->getChild(1))->getTokenID() == SQL_TOKEN_VARYING)
)
3400 nDataType = DataType::VARBINARY;
3401 else
3402 nDataType = DataType::BINARY;
3403 }
3404 else if ( SQL_ISTOKEN (pDataType, VARBINARY)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_VARBINARY)
)
3405 nDataType = DataType::VARBINARY;
3406 else if ( SQL_ISTOKEN (pDataType, BLOB)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_BLOB)
)
3407 nDataType = DataType::BLOB;
3408 else if ( SQL_ISTOKEN (pDataType, NUMERIC)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_NUMERIC)
)
3409 nDataType = DataType::NUMERIC;
3410 else if ( SQL_ISTOKENOR2 (pDataType, DECIMAL, DEC)((pDataType)->isToken() && ( (pDataType)->getTokenID
() == SQL_TOKEN_DECIMAL || (pDataType)->getTokenID() == SQL_TOKEN_DEC
))
)
3411 nDataType = DataType::DECIMAL;
3412 else if ( SQL_ISTOKEN (pDataType, FLOAT)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_FLOAT)
)
3413 nDataType = DataType::FLOAT;
3414 else if ( SQL_ISTOKEN (pDataType, DOUBLE)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_DOUBLE)
)
3415 nDataType = DataType::DOUBLE;
3416 else if ( SQL_ISTOKEN (pDataType, INTERVAL)((pDataType)->isToken() && (pDataType)->getTokenID
() == SQL_TOKEN_INTERVAL)
)
3417 // Not in DataType published constant (because not in JDBC...)
3418 nDataType = DataType::VARCHAR;
3419 else
3420 OSL_FAIL("Failed to decode CAST target")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3420" ": "), "%s", "Failed to decode CAST target"); } }
while (false)
;
3421 }
3422 else
3423 OSL_FAIL("Could not decipher CAST target")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3423" ": "), "%s", "Could not decipher CAST target"); }
} while (false)
;
3424 break;
3425 }
3426 default:
3427 OSL_FAIL("Unknown SQL RuleID")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3427" ": "), "%s", "Unknown SQL RuleID"); } } while (false
)
;
3428 break;
3429 }
3430 break;
3431 default:
3432 OSL_FAIL("Unknown SQL Node Type")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/dbaccess/source/ui/querydesign/QueryDesignView.cxx"
":" "3432" ": "), "%s", "Unknown SQL Node Type"); } } while (
false)
;
3433 break;
3434 }
3435
3436 aInfo->SetDataType(nDataType);
3437 aInfo->SetFieldType(TAB_NORMAL_FIELD);
3438 aInfo->SetField(sFunctionTerm);
3439 aInfo->SetTabWindow(nullptr);
3440}
3441
3442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
2
Memory is allocated
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
15
Calling 'Reference::get'
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
205 if (aTmp.get()) {
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody
5.1
Field 'm_pBody' is non-null
5.1
Field 'm_pBody' is non-null
5.1
Field 'm_pBody' is non-null
5.1
Field 'm_pBody' is non-null
)
6
Taking true branch
113 m_pBody->release();
7
Calling 'VclReferenceBase::release'
11
Returning; memory was released
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody)
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
16
Use of memory after it is freed
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
8
Assuming the condition is true
9
Taking true branch
40 delete this;
10
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif