File: | home/maarten/src/libreoffice/core/include/rtl/ref.hxx |
Warning: | line 192, column 9 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
53 | using namespace ::dbaui; | |||
54 | using namespace ::utl; | |||
55 | using namespace ::connectivity; | |||
56 | using namespace ::dbtools; | |||
57 | using namespace ::com::sun::star::uno; | |||
58 | using namespace ::com::sun::star::lang; | |||
59 | using namespace ::com::sun::star::i18n; | |||
60 | using namespace ::com::sun::star::sdbc; | |||
61 | using namespace ::com::sun::star::beans; | |||
62 | using 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 | |||
66 | namespace | |||
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 | ||||
2409 | OQueryDesignView::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 | ||||
2438 | OQueryDesignView::~OQueryDesignView() | |||
2439 | { | |||
2440 | disposeOnce(); | |||
2441 | } | |||
2442 | ||||
2443 | void 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 | ||||
2452 | IMPL_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 | ||||
2465 | void OQueryDesignView::Construct() | |||
2466 | { | |||
2467 | m_pTableView = VclPtr<OQueryTableView>::Create(m_pScrollWindow,this); | |||
| ||||
2468 | ::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::AddWindow)); | |||
2469 | OJoinDesignView::Construct(); | |||
2470 | } | |||
2471 | ||||
2472 | void 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 | ||||
2483 | void 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 | ||||
2554 | void OQueryDesignView::setReadOnly(bool _bReadOnly) | |||
2555 | { | |||
2556 | m_pSelectionBox->SetReadOnly(_bReadOnly); | |||
2557 | } | |||
2558 | ||||
2559 | void OQueryDesignView::clear() | |||
2560 | { | |||
2561 | m_pSelectionBox->ClearAll(); // clear the whole selection | |||
2562 | m_pTableView->ClearAll(); | |||
2563 | } | |||
2564 | ||||
2565 | void OQueryDesignView::copy() | |||
2566 | { | |||
2567 | if( m_eChildFocus == SELECTION) | |||
2568 | m_pSelectionBox->copy(); | |||
2569 | } | |||
2570 | ||||
2571 | bool OQueryDesignView::isCutAllowed() const | |||
2572 | { | |||
2573 | bool bAllowed = false; | |||
2574 | if ( SELECTION == m_eChildFocus ) | |||
2575 | bAllowed = m_pSelectionBox->isCutAllowed(); | |||
2576 | return bAllowed; | |||
2577 | } | |||
2578 | ||||
2579 | bool OQueryDesignView::isPasteAllowed() const | |||
2580 | { | |||
2581 | bool bAllowed = false; | |||
2582 | if ( SELECTION == m_eChildFocus ) | |||
2583 | bAllowed = m_pSelectionBox->isPasteAllowed(); | |||
2584 | return bAllowed; | |||
2585 | } | |||
2586 | ||||
2587 | bool OQueryDesignView::isCopyAllowed() const | |||
2588 | { | |||
2589 | bool bAllowed = false; | |||
2590 | if ( SELECTION == m_eChildFocus ) | |||
2591 | bAllowed = m_pSelectionBox->isCopyAllowed(); | |||
2592 | return bAllowed; | |||
2593 | } | |||
2594 | ||||
2595 | void OQueryDesignView::stopTimer() | |||
2596 | { | |||
2597 | m_pSelectionBox->stopTimer(); | |||
2598 | } | |||
2599 | ||||
2600 | void OQueryDesignView::startTimer() | |||
2601 | { | |||
2602 | m_pSelectionBox->startTimer(); | |||
2603 | } | |||
2604 | ||||
2605 | void OQueryDesignView::cut() | |||
2606 | { | |||
2607 | if( m_eChildFocus == SELECTION) | |||
2608 | { | |||
2609 | m_pSelectionBox->cut(); | |||
2610 | static_cast<OQueryController&>(getController()).setModified(true); | |||
2611 | } | |||
2612 | } | |||
2613 | ||||
2614 | void OQueryDesignView::paste() | |||
2615 | { | |||
2616 | if( m_eChildFocus == SELECTION) | |||
2617 | { | |||
2618 | m_pSelectionBox->paste(); | |||
2619 | static_cast<OQueryController&>(getController()).setModified(true); | |||
2620 | } | |||
2621 | } | |||
2622 | ||||
2623 | void 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 | ||||
2630 | bool OQueryDesignView::HasFieldByAliasName(const OUString& rFieldName, OTableFieldDescRef const & rInfo) const | |||
2631 | { | |||
2632 | return m_pSelectionBox->HasFieldByAliasName( rFieldName, rInfo); | |||
2633 | } | |||
2634 | ||||
2635 | SqlParseError 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 | ||||
2640 | sal_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 | ||||
2649 | void 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 | ||||
2683 | bool 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 | |||
2697 | bool 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 | ||||
2705 | OUString 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 | ||||
2844 | void 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 | ||||
2867 | bool 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 | ||||
2889 | void 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 | ||||
2898 | std::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 | ||||
2994 | void 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 | ||||
3006 | void OQueryDesignView::reset() | |||
3007 | { | |||
3008 | m_pTableView->ClearAll(); | |||
3009 | m_pTableView->ReSync(); | |||
3010 | } | |||
3011 | ||||
3012 | void OQueryDesignView::setNoneVisibleRow(sal_Int32 _nRows) | |||
3013 | { | |||
3014 | m_pSelectionBox->SetNoneVisibleRow(_nRows); | |||
3015 | } | |||
3016 | ||||
3017 | void 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 | ||||
3036 | bool 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 | |||
3068 | namespace { | |||
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 | ||||
3137 | void 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: */ |
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 | |
36 | class VclReferenceBase; |
37 | |
38 | namespace vcl::detail { |
39 | |
40 | template<typename> |
41 | constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; } |
42 | |
43 | template<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 | */ |
56 | template <class reference_type> |
57 | class 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 | |
66 | public: |
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 ); |
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(); |
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 | |
218 | template<typename T1, typename T2> |
219 | inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) { |
220 | return p1.get() == p2.get(); |
221 | } |
222 | |
223 | template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2) |
224 | { |
225 | return p1.get() == p2; |
226 | } |
227 | |
228 | template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) { |
229 | return p1.get() == p2; |
230 | } |
231 | |
232 | template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2) |
233 | { |
234 | return p1 == p2.get(); |
235 | } |
236 | |
237 | template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) { |
238 | return p1 == p2.get(); |
239 | } |
240 | |
241 | template<typename T1, typename T2> |
242 | inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) { |
243 | return !(p1 == p2); |
244 | } |
245 | |
246 | template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2) |
247 | { |
248 | return !(p1 == p2); |
249 | } |
250 | |
251 | template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) { |
252 | return !(p1 == p2); |
253 | } |
254 | |
255 | template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2) |
256 | { |
257 | return !(p1 == p2); |
258 | } |
259 | |
260 | template<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 | */ |
274 | template <class reference_type> |
275 | class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type> |
276 | { |
277 | public: |
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 | |
290 | template <class reference_type> |
291 | class ScopedVclPtr : public VclPtr<reference_type> |
292 | { |
293 | public: |
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 | |
378 | private: |
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 | |
387 | protected: |
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 |
406 | template <class reference_type> |
407 | class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type> |
408 | { |
409 | public: |
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 | |
421 | private: |
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: */ |
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 | |||||||||
34 | namespace rtl | ||||||||
35 | { | ||||||||
36 | |||||||||
37 | /** Template reference class for reference type. | ||||||||
38 | */ | ||||||||
39 | template <class reference_type> | ||||||||
40 | class Reference | ||||||||
41 | { | ||||||||
42 | /** The <b>reference_type</b> body pointer. | ||||||||
43 | */ | ||||||||
44 | reference_type * m_pBody; | ||||||||
45 | |||||||||
46 | |||||||||
47 | public: | ||||||||
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
| ||||||||
113 | m_pBody->release(); | ||||||||
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; | ||||||||
| |||||||||
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 | ||||||||
277 | namespace 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 | */ | ||||||||
286 | template<typename T> | ||||||||
287 | struct 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: */ |
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 | |
25 | class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase |
26 | { |
27 | mutable oslInterlockedCount mnRefCnt; |
28 | |
29 | template<typename T> friend class VclPtr; |
30 | |
31 | public: |
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) |
40 | delete this; |
41 | } |
42 | #ifdef DBG_UTIL |
43 | #ifndef _WIN32 |
44 | sal_Int32 getRefCount() const { return mnRefCnt; } |
45 | #endif |
46 | #endif |
47 | |
48 | |
49 | private: |
50 | VclReferenceBase(const VclReferenceBase&) = delete; |
51 | VclReferenceBase& operator=(const VclReferenceBase&) = delete; |
52 | |
53 | bool mbDisposed : 1; |
54 | |
55 | protected: |
56 | VclReferenceBase(); |
57 | protected: |
58 | virtual ~VclReferenceBase(); |
59 | |
60 | protected: |
61 | virtual void dispose(); |
62 | |
63 | public: |
64 | void disposeOnce(); |
65 | bool isDisposed() const { return mbDisposed; } |
66 | |
67 | }; |
68 | #endif |