LibreOffice Module dbaccess (master) 1
QueryDesignView.cxx
Go to the documentation of this file.
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>
27#include <o3tl/safeint.hxx>
28#include <o3tl/string_view.hxx>
29#include <osl/diagnose.h>
30#include <vcl/svapp.hxx>
31#include <vcl/weld.hxx>
32#include <browserids.hxx>
34#include <strings.hrc>
35#include <strings.hxx>
36#include <comphelper/string.hxx>
39#include <com/sun/star/sdbc/DataType.hpp>
40#include <com/sun/star/container/XNameAccess.hpp>
41#include <com/sun/star/sdbc/ColumnValue.hpp>
43#include "QTableConnection.hxx"
46#include <core_resource.hxx>
47#include <UITools.hxx>
51#include <memory>
52#include <set>
53#include <string_view>
54
55using namespace ::dbaui;
56using namespace ::utl;
57using namespace ::connectivity;
58using namespace ::dbtools;
59using namespace ::com::sun::star::uno;
60using namespace ::com::sun::star::lang;
61using namespace ::com::sun::star::i18n;
62using namespace ::com::sun::star::sdbc;
63using namespace ::com::sun::star::beans;
64using namespace ::com::sun::star::container;
65
66// here we define our functions used in the anonymous namespace to get our header file smaller
67// please look at the book LargeScale C++ to know why
68namespace
69{
70 const char C_AND[] = " AND ";
71 const char C_OR[] = " OR ";
72
73 bool InsertJoin( const OQueryDesignView* _pView,
74 const ::connectivity::OSQLParseNode *pNode);
75
76 SqlParseError InstallFields(OQueryDesignView* _pView,
77 const ::connectivity::OSQLParseNode* pNode,
78 OJoinTableView::OTableWindowMap* pTabList );
79
80 SqlParseError GetGroupCriteria( OQueryDesignView* _pView,
81 OSelectionBrowseBox* _pSelectionBrw,
82 const ::connectivity::OSQLParseNode* pSelectRoot );
83
84 SqlParseError GetHavingCriteria(OQueryDesignView* _pView,
85 OSelectionBrowseBox* _pSelectionBrw,
86 const ::connectivity::OSQLParseNode* pSelectRoot,
87 sal_uInt16& rLevel );
88
89 SqlParseError GetOrderCriteria( OQueryDesignView* _pView,
90 OSelectionBrowseBox* _pSelectionBrw,
91 const ::connectivity::OSQLParseNode* pParseRoot );
92
93 SqlParseError AddFunctionCondition(OQueryDesignView const * _pView,
94 OSelectionBrowseBox* _pSelectionBrw,
95 const ::connectivity::OSQLParseNode * pCondition,
96 const sal_uInt16 nLevel,
97 bool bHaving,
98 bool _bAddOrOnOneLine);
99
100 OUString quoteTableAlias(bool _bQuote, const OUString& _sAliasName, std::u16string_view _sQuote)
101 {
102 OUString sRet;
103 if ( _bQuote && !_sAliasName.isEmpty() )
104 {
105 sRet = ::dbtools::quoteName(_sQuote,_sAliasName) + ".";
106 }
107 return sRet;
108 }
109 OUString getTableRange(const OQueryDesignView* _pView,const ::connectivity::OSQLParseNode* _pTableRef)
110 {
111 Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
112 OUString sTableRange;
113 if ( _pTableRef )
114 {
115 sTableRange = ::connectivity::OSQLParseNode::getTableRange(_pTableRef);
116 if ( sTableRange.isEmpty() )
117 _pTableRef->parseNodeToStr(sTableRange,xConnection,nullptr,false,false);
118 }
119 return sTableRange;
120 }
121 void insertConnection(const OQueryDesignView* _pView,const EJoinType& _eJoinType, const OTableFieldDescRef& _aDragLeft, const OTableFieldDescRef& _aDragRight, bool _bNatural = false)
122 {
123 OQueryTableView* pTableView = static_cast<OQueryTableView*>(_pView->getTableView());
124 OQueryTableConnection* pConn = static_cast<OQueryTableConnection*>( pTableView->GetTabConn(static_cast<OTableWindow*>(_aDragLeft->GetTabWindow()),static_cast<OTableWindow*>(_aDragRight->GetTabWindow()),true));
125
126 if ( !pConn )
127 {
128 auto xInfoData = std::make_shared<OQueryTableConnectionData>();
129 xInfoData->InitFromDrag(_aDragLeft, _aDragRight);
130 xInfoData->SetJoinType(_eJoinType);
131
132 if ( _bNatural )
133 {
134 xInfoData->ResetConnLines();
135 xInfoData->setNatural(_bNatural);
136 try
137 {
138 Reference<XNameAccess> xReferencedTableColumns(xInfoData->getReferencedTable()->getColumns());
139 Sequence< OUString> aSeq = xInfoData->getReferencingTable()->getColumns()->getElementNames();
140 const OUString* pIter = aSeq.getConstArray();
141 const OUString* pEnd = pIter + aSeq.getLength();
142 for(;pIter != pEnd;++pIter)
143 {
144 if ( xReferencedTableColumns->hasByName(*pIter) )
145 xInfoData->AppendConnLine(*pIter,*pIter);
146 }
147 }
148 catch( const Exception& )
149 {
150 DBG_UNHANDLED_EXCEPTION("dbaccess");
151 }
152 }
153
154 ScopedVclPtrInstance< OQueryTableConnection > aInfo(pTableView, xInfoData);
155 // Because OQueryTableConnection never takes ownership of the data passed to it, but only remembers the pointer,
156 // this pointer to a local variable is not critical, as xInfoData and aInfo have the same lifetime
157 pTableView->NotifyTabConnection( *aInfo );
158 }
159 else
160 {
161 OUString aSourceFieldName(_aDragLeft->GetField());
162 OUString aDestFieldName(_aDragRight->GetField());
163 // the connection could point on the other side
164 if(pConn->GetSourceWin() == _aDragRight->GetTabWindow())
165 {
166 OUString aTmp(aSourceFieldName);
167 aSourceFieldName = aDestFieldName;
168 aDestFieldName = aTmp;
169 }
170 pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName);
171 pConn->UpdateLineList();
172 // Modified-Flag
173 // SetModified();
174 // and redraw
175 pConn->RecalcLines();
176 // for the following Invalidate, the new Connection must first be able
177 // to determine its BoundingRect
178 pConn->InvalidateConnection();
179 }
180 }
181 OUString ParseCondition( OQueryController& rController
182 ,const ::connectivity::OSQLParseNode* pCondition
183 ,const OUString& _sDecimal
184 ,const css::lang::Locale& _rLocale
185 ,sal_uInt32 _nStartIndex)
186 {
187 OUString aCondition;
188 Reference< XConnection> xConnection = rController.getConnection();
189 if ( xConnection.is() )
190 {
191 sal_uInt32 nCount = pCondition->count();
192 for(sal_uInt32 i = _nStartIndex ; i < nCount ; ++i)
193 pCondition->getChild(i)->parseNodeToPredicateStr(aCondition,
194 xConnection,
195 rController.getNumberFormatter(),
196 _rLocale,
197 _sDecimal,
198 &rController.getParser().getContext());
199 }
200 return aCondition;
201 }
202 SqlParseError FillOuterJoins(OQueryDesignView const * _pView,
203 const ::connectivity::OSQLParseNode* pTableRefList)
204 {
205 SqlParseError eErrorCode = eOk;
206 sal_uInt32 nCount = pTableRefList->count();
207 bool bError = false;
208 for (sal_uInt32 i=0; !bError && i < nCount; ++i)
209 {
210 const ::connectivity::OSQLParseNode* pParseNode = pTableRefList->getChild(i);
211 const ::connectivity::OSQLParseNode* pJoinNode = nullptr;
212
213 if ( SQL_ISRULE( pParseNode, qualified_join ) || SQL_ISRULE( pParseNode, joined_table ) || SQL_ISRULE( pParseNode, cross_union ) )
214 pJoinNode = pParseNode;
215 else if( SQL_ISRULE(pParseNode,table_ref)
216 && pParseNode->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
217 pJoinNode = pParseNode->getChild(2);
218
219 if ( pJoinNode )
220 {
221 if ( !InsertJoin(_pView,pJoinNode) )
222 bError = true;
223 }
224 }
225 // check if error occurred
226 if ( bError )
227 eErrorCode = eIllegalJoin;
228
229 return eErrorCode;
230 }
231
234 SqlParseError FillDragInfo( const OQueryDesignView* _pView,
235 const ::connectivity::OSQLParseNode* pColumnRef,
236 OTableFieldDescRef const & _rDragInfo)
237 {
238 SqlParseError eErrorCode = eOk;
239
240 bool bErg = false;
241
242 OUString aTableRange,aColumnName;
243 ::connectivity::OSQLParseTreeIterator& rParseIter = static_cast<OQueryController&>(_pView->getController()).getParseIterator();
244 rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange );
245
246 if ( !aTableRange.isEmpty() )
247 {
248 OQueryTableWindow* pSTW = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( aTableRange );
249 bErg = (pSTW && pSTW->ExistsField( aColumnName, _rDragInfo ) );
250 }
251 if ( !bErg )
252 {
253 sal_uInt16 nCntAccount;
254 bErg = static_cast<OQueryTableView*>(_pView->getTableView())->FindTableFromField(aColumnName, _rDragInfo, nCntAccount);
255 if ( !bErg )
256 bErg = _pView->HasFieldByAliasName(aColumnName, _rDragInfo);
257 }
258 if ( !bErg )
259 {
260 eErrorCode = eColumnNotFound;
261 OUString sError(DBA_RES(STR_QRY_COLUMN_NOT_FOUND));
262 sError = sError.replaceFirst("$name$",aColumnName);
263 _pView->getController().appendError( sError );
264
265 try
266 {
267 Reference<XDatabaseMetaData> xMeta = _pView->getController().getConnection()->getMetaData();
268 if ( xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() )
269 _pView->getController().appendError(DBA_RES(STR_QRY_CHECK_CASESENSITIVE));
270 }
271 catch(Exception&)
272 {
273 }
274 }
275
276 return eErrorCode;
277 }
278 OUString BuildJoinCriteria( const Reference< XConnection>& _xConnection,
279 const OConnectionLineDataVec* pLineDataList,
280 const OQueryTableConnectionData* pData)
281 {
282 OUStringBuffer aCondition;
283 if ( _xConnection.is() )
284 {
285 try
286 {
287 const Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData();
288 const OUString aQuote = xMetaData->getIdentifierQuoteString();
289
290 for (auto const& lineData : *pLineDataList)
291 {
292 if(!aCondition.isEmpty())
293 aCondition.append(C_AND);
294 aCondition.append(
295 quoteTableAlias(true,pData->GetAliasName(JTCS_FROM),aQuote)
296 + ::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_FROM) )
297 + " = "
298 + quoteTableAlias(true,pData->GetAliasName(JTCS_TO),aQuote)
299 + ::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_TO) ));
300 }
301 }
302 catch(SQLException&)
303 {
304 OSL_FAIL("Failure while building Join criteria!");
305 }
306 }
307
308 return aCondition.makeStringAndClear();
309 }
316 void JoinCycle( const Reference< XConnection>& _xConnection,
317 OQueryTableConnection* _pEntryConn,
318 const OQueryTableWindow* _pEntryTabTo,
319 OUString& _rJoin )
320 {
321 OSL_ENSURE(_pEntryConn,"TableConnection can not be null!");
322
323 OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pEntryConn->GetData().get());
324 if ( !(pData->GetJoinType() != INNER_JOIN && _pEntryTabTo->ExistsAVisitedConn()) )
325 return;
326
327 bool bBrace = false;
328 if(_rJoin.endsWith(")"))
329 {
330 bBrace = true;
331 _rJoin = _rJoin.replaceAt(_rJoin.getLength()-1,1, u" ");
332 }
333 _rJoin += C_AND + BuildJoinCriteria(_xConnection,&pData->GetConnLineDataList(),pData);
334 if(bBrace)
335 _rJoin += ")";
336 _pEntryConn->SetVisited(true);
337 }
338 OUString BuildTable( const Reference< XConnection>& _xConnection,
339 const OQueryTableWindow* pEntryTab,
340 bool _bForce = false
341 )
342 {
343 OUString aDBName(pEntryTab->GetComposedName());
344
345 if( _xConnection.is() )
346 {
347 try
348 {
349 Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData();
350
351 OUString sCatalog, sSchema, sTable;
352 ::dbtools::qualifiedNameComponents( xMetaData, aDBName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
353 OUString aTableListStr = ::dbtools::composeTableNameForSelect( _xConnection, sCatalog, sSchema, sTable );
354
355 OUString aQuote = xMetaData->getIdentifierQuoteString();
356 if ( _bForce || isAppendTableAliasEnabled( _xConnection ) || pEntryTab->GetAliasName() != aDBName )
357 {
358 aTableListStr += " ";
359 if ( generateAsBeforeTableAlias( _xConnection ) )
360 aTableListStr += "AS ";
361 aTableListStr += ::dbtools::quoteName( aQuote, pEntryTab->GetAliasName() );
362 }
363 aDBName = aTableListStr;
364 }
365 catch(const SQLException&)
366 {
367 DBG_UNHANDLED_EXCEPTION("dbaccess");
368 }
369 }
370 return aDBName;
371 }
372 OUString BuildJoin( const Reference< XConnection>& _xConnection,
373 const OUString& rLh,
374 std::u16string_view rRh,
375 const OQueryTableConnectionData* pData)
376 {
377
378 OUString aErg(rLh);
379 if ( pData->isNatural() && pData->GetJoinType() != CROSS_JOIN )
380 aErg += " NATURAL ";
381 switch(pData->GetJoinType())
382 {
383 case LEFT_JOIN:
384 aErg += " LEFT OUTER ";
385 break;
386 case RIGHT_JOIN:
387 aErg += " RIGHT OUTER ";
388 break;
389 case CROSS_JOIN:
390 OSL_ENSURE(!pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!");
391 aErg += " CROSS ";
392 break;
393 case INNER_JOIN:
394 OSL_ENSURE(pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!");
395 aErg += " INNER ";
396 break;
397 default:
398 aErg += " FULL OUTER ";
399 break;
400 }
401 aErg += OUString::Concat("JOIN ") + rRh;
402 if ( CROSS_JOIN != pData->GetJoinType() && !pData->isNatural() )
403 {
404 aErg += " ON " + BuildJoinCriteria(_xConnection,&pData->GetConnLineDataList(),pData);
405 }
406
407 return aErg;
408 }
409 OUString BuildJoin( const Reference< XConnection>& _xConnection,
410 const OQueryTableWindow* pLh,
411 const OQueryTableWindow* pRh,
412 const OQueryTableConnectionData* pData
413 )
414 {
415 bool bForce = pData->GetJoinType() == CROSS_JOIN || pData->isNatural();
416 return BuildJoin(_xConnection,BuildTable(_xConnection,pLh,bForce),BuildTable(_xConnection,pRh,bForce),pData);
417 }
418 OUString BuildJoin( const Reference< XConnection>& _xConnection,
419 const OUString &rLh,
420 const OQueryTableWindow* pRh,
421 const OQueryTableConnectionData* pData
422 )
423 {
424 return BuildJoin(_xConnection,rLh,BuildTable(_xConnection,pRh),pData);
425 }
426 OUString BuildJoin( const Reference< XConnection>& _xConnection,
427 const OQueryTableWindow* pLh,
428 const OUString &rRh,
429 const OQueryTableConnectionData* pData
430 )
431 {
432 // strict ANSI SQL:
433 // - does not support any bracketing of JOINS
434 // - supports nested joins only in the LEFT HAND SIDE
435 // In this case, we are trying to build a join with a nested join
436 // in the right hand side.
437 // So switch the direction of the join and both hand sides.
438 OQueryTableConnectionData data(*pData);
439 switch (data.GetJoinType())
440 {
441 case LEFT_JOIN:
442 data.SetJoinType(RIGHT_JOIN);
443 break;
444 case RIGHT_JOIN:
445 data.SetJoinType(LEFT_JOIN);
446 break;
447 default:
448 // the other join types are symmetric, so nothing to change
449 break;
450 }
451 return BuildJoin(_xConnection, rRh, BuildTable(_xConnection,pLh), &data);
452 }
453 void addConnectionTableNames( const Reference< XConnection>& _xConnection,
454 const OQueryTableConnection* const pEntryConn,
455 std::set<OUString> &_rTableNames )
456 {
457 // insert tables into table list to avoid double entries
458 const OQueryTableWindow* const pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
459 const OQueryTableWindow* const pEntryTabTo = static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin());
460 _rTableNames.insert(BuildTable(_xConnection,pEntryTabFrom));
461 _rTableNames.insert(BuildTable(_xConnection,pEntryTabTo));
462 }
463 void GetNextJoin( const Reference< XConnection>& _xConnection,
464 OQueryTableConnection* pEntryConn,
465 OQueryTableWindow const * pEntryTabTo,
466 OUString &aJoin,
467 std::set<OUString> &_rTableNames)
468 {
469 OQueryTableConnectionData* pEntryConnData = static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get());
470 if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() )
471 return;
472
473 if(aJoin.isEmpty())
474 {
475 addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
476 OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
477 aJoin = BuildJoin(_xConnection,pEntryTabFrom,pEntryTabTo,pEntryConnData);
478 }
479 else if(pEntryTabTo == pEntryConn->GetDestWin())
480 {
481 addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
482 aJoin = BuildJoin(_xConnection,aJoin,pEntryTabTo,pEntryConnData);
483 }
484 else if(pEntryTabTo == pEntryConn->GetSourceWin())
485 {
486 addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
487 aJoin = BuildJoin(_xConnection,pEntryTabTo,aJoin,pEntryConnData);
488 }
489
490 pEntryConn->SetVisited(true);
491
492 // first search for the "to" window
493 const auto& rConnections = pEntryConn->GetParent()->getTableConnections();
494 bool bFound = false;
495 for (auto const& connection : rConnections)
496 {
497 OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(connection.get());
498 if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabTo || pNext->GetDestWin() == pEntryTabTo))
499 {
500 OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabTo ? static_cast<OQueryTableWindow*>(pNext->GetDestWin()) : static_cast<OQueryTableWindow*>(pNext->GetSourceWin());
501 // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
502 JoinCycle(_xConnection,pNext,pEntryTab,aJoin);
503 if(!pNext->IsVisited())
504 GetNextJoin(_xConnection, pNext, pEntryTab, aJoin, _rTableNames);
505 bFound = true;
506 }
507 }
508
509 // when nothing found look for the "from" window
510 if(bFound)
511 return;
512
513 OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
514 for (auto const& connection : rConnections)
515 {
516 OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(connection.get());
517 if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabFrom || pNext->GetDestWin() == pEntryTabFrom))
518 {
519 OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabFrom ? static_cast<OQueryTableWindow*>(pNext->GetDestWin()) : static_cast<OQueryTableWindow*>(pNext->GetSourceWin());
520 // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
521 JoinCycle(_xConnection,pNext,pEntryTab,aJoin);
522 if(!pNext->IsVisited())
523 GetNextJoin(_xConnection, pNext, pEntryTab, aJoin, _rTableNames);
524 }
525 }
526 }
527 SqlParseError InsertJoinConnection( const OQueryDesignView* _pView,
528 const ::connectivity::OSQLParseNode *pNode,
529 const EJoinType& _eJoinType,
530 const ::connectivity::OSQLParseNode *pLeftTable,
531 const ::connectivity::OSQLParseNode *pRightTable)
532 {
533 SqlParseError eErrorCode = eOk;
534 if (pNode->count() == 3 && // statement between brackets
535 SQL_ISPUNCTUATION(pNode->getChild(0),"(") &&
536 SQL_ISPUNCTUATION(pNode->getChild(2),")"))
537 {
538 eErrorCode = InsertJoinConnection(_pView,pNode->getChild(1), _eJoinType,pLeftTable,pRightTable);
539 }
540 else if (SQL_ISRULEOR2(pNode,search_condition,boolean_term) && // AND/OR-joints:
541 pNode->count() == 3)
542 {
543 // only allow AND joints
544 if (!SQL_ISTOKEN(pNode->getChild(1),AND))
545 eErrorCode = eIllegalJoinCondition;
546 else if ( eOk == (eErrorCode = InsertJoinConnection(_pView,pNode->getChild(0), _eJoinType,pLeftTable,pRightTable)) )
547 eErrorCode = InsertJoinConnection(_pView,pNode->getChild(2), _eJoinType,pLeftTable,pRightTable);
548 }
549 else if (SQL_ISRULE(pNode,comparison_predicate))
550 {
551 // only the comparison of columns is allowed
552 OSL_ENSURE(pNode->count() == 3,"OQueryDesignView::InsertJoinConnection: Error in Parse Tree");
553 if (!(SQL_ISRULE(pNode->getChild(0),column_ref) &&
554 SQL_ISRULE(pNode->getChild(2),column_ref) &&
555 pNode->getChild(1)->getNodeType() == SQLNodeType::Equal))
556 {
557 OUString sError(DBA_RES(STR_QRY_JOIN_COLUMN_COMPARE));
558 _pView->getController().appendError( sError );
559 return eIllegalJoin;
560 }
561
562 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
563 OTableFieldDescRef aDragRight = new OTableFieldDesc();
564 eErrorCode = FillDragInfo(_pView,pNode->getChild(0),aDragLeft);
565 if ( eOk != eErrorCode )
566 return eErrorCode;
567 eErrorCode = FillDragInfo(_pView,pNode->getChild(2),aDragRight);
568 if ( eOk != eErrorCode )
569 return eErrorCode;
570
571 if ( pLeftTable )
572 {
573 OQueryTableWindow* pLeftWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pLeftTable->getByRule(OSQLParseNode::table_ref) ));
574 if ( pLeftWindow == aDragLeft->GetTabWindow() )
575 insertConnection(_pView,_eJoinType,aDragLeft,aDragRight);
576 else
577 insertConnection(_pView,_eJoinType,aDragRight,aDragLeft);
578 }
579 else
580 insertConnection(_pView,_eJoinType,aDragLeft,aDragRight);
581 }
582 else
583 eErrorCode = eIllegalJoin;
584 return eErrorCode;
585 }
586 bool GetInnerJoinCriteria( const OQueryDesignView* _pView,
587 const ::connectivity::OSQLParseNode *pCondition)
588 {
589 return InsertJoinConnection(_pView,pCondition, INNER_JOIN,nullptr,nullptr) != eOk;
590 }
591 OUString GenerateSelectList( const OQueryDesignView* _pView,
592 OTableFields& _rFieldList,
593 bool bAlias)
594 {
595 Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
596 if ( !xConnection.is() )
597 return OUString();
598
599 OUStringBuffer aTmpStr,aFieldListStr;
600
601 bool bAsterisk = false;
602 int nVis = 0;
603 for (auto const& field : _rFieldList)
604 {
605 if ( field->IsVisible() )
606 {
607 if ( field->GetField().toChar() == '*' )
608 bAsterisk = true;
609 ++nVis;
610 }
611 }
612 if(nVis == 1)
613 bAsterisk = false;
614
615 try
616 {
617 const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
618 const OUString aQuote = xMetaData->getIdentifierQuoteString();
619
620 OJoinTableView::OTableWindowMap& rTabList = _pView->getTableView()->GetTabWinMap();
621
622 for (auto const& field : _rFieldList)
623 {
624 OUString rFieldName = field->GetField();
625 if ( !rFieldName.isEmpty() && field->IsVisible() )
626 {
627 aTmpStr = "";
628 const OUString rAlias = field->GetAlias();
629 const OUString rFieldAlias = field->GetFieldAlias();
630
631 aTmpStr.append(quoteTableAlias((bAlias || bAsterisk),rAlias,aQuote));
632
633 // if we have a none numeric field, the table alias could be in the name
634 // otherwise we are not allowed to do this (e.g. 0.1 * PRICE )
635 if ( !field->isOtherFunction() )
636 {
637 // we have to look if we have alias.* here but before we have to check if the column doesn't already exist
638 OTableFieldDescRef aInfo = new OTableFieldDesc();
639 for (auto const& table : rTabList)
640 {
641 OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get());
642
643 if ( pTabWin->ExistsField( rFieldName, aInfo ) )
644 {
645 rFieldName = aInfo->GetField();
646 break;
647 }
648 }
649 if ( ( rFieldName.toChar() != '*' ) && ( rFieldName.indexOf( aQuote ) == -1 ) )
650 {
651 OSL_ENSURE(!field->GetTable().isEmpty(),"No table field name!");
652 aTmpStr.append(::dbtools::quoteName(aQuote, rFieldName));
653 }
654 else
655 aTmpStr.append(rFieldName);
656 }
657 else
658 aTmpStr.append(rFieldName);
659
660 if ( field->isAggregateFunction() )
661 {
662 OSL_ENSURE(!field->GetFunction().isEmpty(),"Function name must not be empty! ;-(");
663 OUStringBuffer aTmpStr2( field->GetFunction() + "(" + aTmpStr + ")");
664 aTmpStr = aTmpStr2;
665 }
666
667 if (!rFieldAlias.isEmpty() &&
668 (rFieldName.toChar() != '*' ||
669 field->isNumericOrAggregateFunction() ||
670 field->isOtherFunction()))
671 {
672 aTmpStr.append(" AS " + ::dbtools::quoteName(aQuote, rFieldAlias));
673 }
674 aFieldListStr.append(aTmpStr);
675 aTmpStr.setLength(0);
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!");
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)));
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!");
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!");
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)));
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! ;-(");
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::Concat(" ") + o3tl::getToken( u";ASC;DESC", 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!");
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 );
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, u"" );
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!;-(");
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, u" " );
1146 OUString aGroupByStr2 = " GROUP BY " + aGroupByStr;
1147 aGroupByStr = aGroupByStr2;
1148 }
1149 }
1150 catch(SQLException&)
1151 {
1152 OSL_FAIL("Failure while building group by!");
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))
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
1184 ::connectivity::OSQLParseNode *pNodeTmp = pNode->getChild(1);
1185
1187 pNodeTmp = pNode->getChild(1);
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
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),"(") &&
1229 SQL_ISPUNCTUATION(pCondition->getChild(2),")"))
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))
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) )
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) )
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. :-)
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))
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) ) // 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) )
1313 {
1314 OSL_ENSURE(pCondition->count() == 3,"Illegal definition of boolean_term");
1315 eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pCondition->getChild(0), nLevel,bHaving,bAddOrOnOneLine );
1316 if ( eErrorCode == eOk )
1317 eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pCondition->getChild(2), nLevel,bHaving,bAddOrOnOneLine );
1318 }
1319 else if (SQL_ISRULE( pCondition, comparison_predicate))
1320 {
1321 eErrorCode = ComparisonPredicate(_pView,_pSelectionBrw,pCondition,nLevel,bHaving,bAddOrOnOneLine);
1322 }
1323 else if( SQL_ISRULE(pCondition,like_predicate) )
1324 {
1325 const ::connectivity::OSQLParseNode* pValueExp = pCondition->getChild(0);
1326 if (SQL_ISRULE(pValueExp, 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) ||
1362 SQL_ISRULEOR3(pValueExp, extract_exp, fold, char_substring_fct) ||
1363 SQL_ISRULEOR2(pValueExp, length_exp, 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));
1376 _pView->getController().appendError( sError );
1377 }
1378 }
1379 else if( SQL_ISRULEOR2(pCondition,test_for_null,in_predicate)
1380 || SQL_ISRULEOR2(pCondition,all_or_any_predicate,between_predicate))
1381 {
1382 if ( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , 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 ) )
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) )
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,false).is() ? eOk : eTooManyColumns;
1436 }
1437 else
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) ||
1455 SQL_ISRULEOR3(pFunction, extract_exp, fold, char_substring_fct) ||
1456 SQL_ISRULEOR2(pFunction,length_exp,char_value_fct),
1457 "Illegal call!");
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 ) )
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))
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");
1543 if ( SQL_ISRULE(pCondition->getChild(0), column_ref )
1544 || SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref) )
1545 {
1546 OUString aCondition;
1547 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1548
1549 if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) && SQL_ISRULE(pCondition->getChild(pCondition->count()-1), 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 ))
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 ) )
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 ) )
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");
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))
1751 pJoinNode = _pNode;
1752 else if (SQL_ISRULE(_pNode,table_ref)
1753 && _pNode->count() == 3
1754 && SQL_ISPUNCTUATION(_pNode->getChild(0),"(")
1755 && SQL_ISPUNCTUATION(_pNode->getChild(2),")") ) // '(' joined_table ')'
1756 pJoinNode = _pNode->getChild(1);
1757 else if (! ( SQL_ISRULE(_pNode, table_ref) && _pNode->count() == 2) ) // table_node table_primary_as_range_column
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 ),
1768 "OQueryDesignView::InsertJoin: Error in the Parse Tree");
1769
1770 if (SQL_ISRULE(pNode,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) && SQL_ISTOKEN(pNode->getChild(1),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) )
1786 {
1787 ::connectivity::OSQLParseNode* pJoinType = pNode->getChild(1); // join_type
1788 if ( SQL_ISTOKEN(pJoinType,NATURAL) )
1789 {
1790 bNatural = true;
1791 pJoinType = pNode->getChild(2);
1792 }
1793
1794 if (SQL_ISRULE(pJoinType,join_type) && (!pJoinType->count() || SQL_ISTOKEN(pJoinType->getChild(0),INNER)))
1795 {
1796 eJoinType = INNER_JOIN;
1797 }
1798 else
1799 {
1800 if (SQL_ISRULE(pJoinType,join_type)) // one level deeper
1801 pJoinType = pJoinType->getChild(0);
1802
1803 if (SQL_ISTOKEN(pJoinType->getChild(0),LEFT))
1804 eJoinType = LEFT_JOIN;
1805 else if(SQL_ISTOKEN(pJoinType->getChild(0),RIGHT))
1806 eJoinType = RIGHT_JOIN;
1807 else
1808 eJoinType = FULL_JOIN;
1809 }
1810 if ( SQL_ISRULE(pNode->getChild(4),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) )
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 return true;
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!");
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 return true;
1846 }
1847 void insertUnUsedFields(OQueryDesignView const * _pView,OSelectionBrowseBox* _pSelectionBrw)
1848 {
1849 // now we have to insert the fields which aren't in the statement
1850 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1851 OTableFields& rUnUsedFields = rController.getUnUsedFields();
1852 for (auto & unusedField : rUnUsedFields)
1853 if(_pSelectionBrw->InsertField(unusedField,BROWSER_INVALIDID,false,false).is())
1854 unusedField = nullptr;
1855 OTableFields().swap( rUnUsedFields );
1856 }
1857
1858 SqlParseError InitFromParseNodeImpl(OQueryDesignView* _pView,OSelectionBrowseBox* _pSelectionBrw)
1859 {
1860 SqlParseError eErrorCode = eOk;
1861
1862 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1863
1864 _pSelectionBrw->PreFill();
1865 _pSelectionBrw->SetReadOnly(rController.isReadOnly());
1866 _pSelectionBrw->Fill();
1867
1868 ::connectivity::OSQLParseTreeIterator& aIterator = rController.getParseIterator();
1869 const ::connectivity::OSQLParseNode* pParseTree = aIterator.getParseTree();
1870
1871 do
1872 {
1873 if ( !pParseTree )
1874 {
1875 // now we have to insert the fields which aren't in the statement
1876 insertUnUsedFields(_pView,_pSelectionBrw);
1877 break;
1878 }
1879
1880 if ( !rController.isEscapeProcessing() ) // not allowed in this mode
1881 {
1882 eErrorCode = eNativeMode;
1883 break;
1884 }
1885
1886 if ( !( SQL_ISRULE( pParseTree, select_statement ) ) )
1887 {
1888 eErrorCode = eNoSelectStatement;
1889 break;
1890 }
1891
1892 const OSQLParseNode* pTableExp = pParseTree->getChild(3);
1893 if ( pTableExp->getChild(7)->count() > 0 || pTableExp->getChild(8)->count() > 0)
1894 {
1895 eErrorCode = eStatementTooComplex;
1896 break;
1897 }
1898
1899 Reference< XConnection> xConnection = rController.getConnection();
1900 if ( !xConnection.is() )
1901 {
1902 OSL_FAIL( "InitFromParseNodeImpl: no connection? no connection!" );
1903 break;
1904 }
1905
1906 const OSQLTables& aMap = aIterator.getTables();
1907 ::comphelper::UStringMixLess aTmp(aMap.key_comp());
1908 ::comphelper::UStringMixEqual aKeyComp( aTmp.isCaseSensitive() );
1909
1910 Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
1911 try
1912 {
1913 sal_Int32 nMax = xMetaData->getMaxTablesInSelect();
1914 if ( nMax && nMax < static_cast<sal_Int32>(aMap.size()) )
1915 {
1916 eErrorCode = eTooManyTables;
1917 break;
1918 }
1919
1920 OUString sComposedName;
1921 OUString sAlias;
1922
1923 OQueryTableView* pTableView = static_cast<OQueryTableView*>(_pView->getTableView());
1924 pTableView->clearLayoutInformation();
1925 for (auto const& elem : aMap)
1926 {
1927 OSQLTable xTable = elem.second;
1928 Reference< XPropertySet > xTableProps( xTable, UNO_QUERY_THROW );
1929
1930 sAlias = elem.first;
1931
1932 // check whether this is a query
1933 Reference< XPropertySetInfo > xPSI = xTableProps->getPropertySetInfo();
1934 bool bIsQuery = xPSI.is() && xPSI->hasPropertyByName( PROPERTY_COMMAND );
1935
1936 if ( bIsQuery )
1937 OSL_VERIFY( xTableProps->getPropertyValue( PROPERTY_NAME ) >>= sComposedName );
1938 else
1939 {
1940 sComposedName = ::dbtools::composeTableName( xMetaData, xTableProps, ::dbtools::EComposeRule::InDataManipulation, false );
1941
1942 // if the alias is the complete (composed) table, then shorten it
1943 if ( aKeyComp( sComposedName, elem.first ) )
1944 {
1945 OUString sCatalog, sSchema, sTable;
1946 ::dbtools::qualifiedNameComponents( xMetaData, sComposedName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
1947 sAlias = sTable;
1948 }
1949 }
1950
1951 // find the existent window for this alias
1952 OQueryTableWindow* pExistentWin = pTableView->FindTable( sAlias );
1953 if ( !pExistentWin )
1954 {
1955 pTableView->AddTabWin( sComposedName, sAlias ); // don't create data here
1956 }
1957 else
1958 {
1959 // there already exists a window for this alias...
1960 if ( !aKeyComp( pExistentWin->GetData()->GetComposedName(), sComposedName ) )
1961 // ... but for another complete table name -> new window
1962 pTableView->AddTabWin(sComposedName, sAlias);
1963 }
1964 }
1965
1966 // now delete the data for which we haven't any tablewindow
1967 OJoinTableView::OTableWindowMap aTableMap(pTableView->GetTabWinMap());
1968 for (auto const& table : aTableMap)
1969 {
1970 if(aMap.find(table.second->GetComposedName()) == aMap.end() &&
1971 aMap.find(table.first) == aMap.end())
1972 pTableView->RemoveTabWin(table.second);
1973 }
1974
1975 if ( eOk == (eErrorCode = FillOuterJoins(_pView,pTableExp->getChild(0)->getChild(1))) )
1976 {
1977 // check if we have a distinct statement
1978 if(SQL_ISTOKEN(pParseTree->getChild(1),DISTINCT))
1979 {
1980 rController.setDistinct(true);
1981 rController.InvalidateFeature(SID_QUERY_DISTINCT_VALUES);
1982 }
1983 else
1984 {
1985 rController.setDistinct(false);
1986 }
1987
1989 if( pTableExp->getChild(6)->count() >= 2 && pTableExp->getChild(6)->getChild(1) )
1990 {
1991 rController.setLimit(
1992 pTableExp->getChild(6)->getChild(1)->getTokenValue().toInt64() );
1993 }
1994 else
1995 {
1996 rController.setLimit(-1);
1997 }
1998
1999 if ( (eErrorCode = InstallFields(_pView, pParseTree, &pTableView->GetTabWinMap())) == eOk )
2000 {
2001 // GetSelectionCriteria must be called before GetHavingCriteria
2002 sal_uInt16 nLevel=0;
2003
2004 if ( eOk == (eErrorCode = GetSelectionCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) )
2005 {
2006 if ( eOk == (eErrorCode = GetGroupCriteria(_pView,_pSelectionBrw,pParseTree)) )
2007 {
2008 if ( eOk == (eErrorCode = GetHavingCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) )
2009 {
2010 if ( eOk == (eErrorCode = GetOrderCriteria(_pView,_pSelectionBrw,pParseTree)) )
2011 insertUnUsedFields(_pView,_pSelectionBrw);
2012 }
2013 }
2014 }
2015 }
2016 }
2017 }
2018 catch(SQLException&)
2019 {
2020 OSL_FAIL("getMaxTablesInSelect!");
2021 }
2022 }
2023 while ( false );
2024
2025 // New Undo-Actions were created in the Manager by the regeneration
2026 rController.ClearUndoManager();
2027 _pSelectionBrw->Invalidate();
2028 return eErrorCode;
2029 }
2034 SqlParseError fillSelectSubList( OQueryDesignView* _pView,
2035 OJoinTableView::OTableWindowMap* _pTabList)
2036 {
2037 SqlParseError eErrorCode = eOk;
2038 bool bFirstField = true;
2039 for (auto const& table : *_pTabList)
2040 {
2041 OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get());
2042 OTableFieldDescRef aInfo = new OTableFieldDesc();
2043 if (pTabWin->ExistsField( "*", aInfo ))
2044 {
2045 eErrorCode = _pView->InsertField(aInfo, bFirstField);
2046 bFirstField = false;
2047 if (eErrorCode != eOk)
2048 break;
2049 }
2050 }
2051 return eErrorCode;
2052 }
2053 SqlParseError InstallFields(OQueryDesignView* _pView,
2054 const ::connectivity::OSQLParseNode* pNode,
2055 OJoinTableView::OTableWindowMap* pTabList )
2056 {
2057 if( pNode==nullptr || !SQL_ISRULE(pNode,select_statement))
2058 return eNoSelectStatement;
2059
2060 ::connectivity::OSQLParseNode* pParseTree = pNode->getChild(2); // selection
2061 bool bFirstField = true; // When initializing, the first field must be reactivated
2062
2063 SqlParseError eErrorCode = eOk;
2064
2065 if ( pParseTree->isRule() && SQL_ISPUNCTUATION(pParseTree->getChild(0),"*") )
2066 {
2067 // SELECT * ...
2068 eErrorCode = fillSelectSubList(_pView,pTabList);
2069 }
2070 else if (SQL_ISRULE(pParseTree,scalar_exp_commalist) )
2071 {
2072 // SELECT column, ...
2073 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
2074 Reference< XConnection> xConnection = rController.getConnection();
2075
2076 OUString aColumnName,aTableRange;
2077 for (size_t i = 0; i < pParseTree->count() && eOk == eErrorCode ; ++i)
2078 {
2079 ::connectivity::OSQLParseNode * pColumnRef = pParseTree->getChild(i);
2080
2081 do {
2082
2083 if ( SQL_ISRULE(pColumnRef,select_sublist) )
2084 {
2085 eErrorCode = fillSelectSubList(_pView,pTabList);
2086 break;
2087 }
2088
2089 if ( SQL_ISRULE(pColumnRef,derived_column) )
2090 {
2091 OUString aColumnAlias(connectivity::OSQLParseTreeIterator::getColumnAlias(pColumnRef)); // might be empty
2092 pColumnRef = pColumnRef->getChild(0);
2093 OTableFieldDescRef aInfo = new OTableFieldDesc();
2094
2095 if ( pColumnRef->getKnownRuleID() != OSQLParseNode::subquery &&
2096 pColumnRef->count() == 3 &&
2097 SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") &&
2098 SQL_ISPUNCTUATION(pColumnRef->getChild(2),")")
2099 )
2100 pColumnRef = pColumnRef->getChild(1);
2101
2102 if (SQL_ISRULE(pColumnRef,column_ref))
2103 {
2104 InsertColumnRef(_pView,pColumnRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList);
2105 eErrorCode = _pView->InsertField(aInfo, bFirstField);
2106 bFirstField = false;
2107 }
2108 else if(SQL_ISRULEOR3(pColumnRef, general_set_fct, set_fct_spec, position_exp) ||
2109 SQL_ISRULEOR3(pColumnRef, extract_exp, fold, char_substring_fct) ||
2110 SQL_ISRULEOR2(pColumnRef,length_exp,char_value_fct))
2111 {
2112 OUString aColumns;
2113 pColumnRef->parseNodeToPredicateStr(aColumns,
2114 xConnection,
2115 rController.getNumberFormatter(),
2116 _pView->getLocale(),
2117 _pView->getDecimalSeparator(),
2118 &rController.getParser().getContext());
2119
2120 sal_Int32 nFunctionType = FKT_NONE;
2121 ::connectivity::OSQLParseNode* pParamRef = nullptr;
2122 sal_Int32 nColumnRefPos = pColumnRef->count() - 2;
2123 if ( nColumnRefPos >= 0 && o3tl::make_unsigned(nColumnRefPos) < pColumnRef->count() )
2124 pParamRef = pColumnRef->getChild(nColumnRefPos);
2125
2126 if ( SQL_ISRULE(pColumnRef,general_set_fct)
2127 && pParamRef && SQL_ISRULE(pParamRef,column_ref) )
2128 {
2129 // Check the parameters for Column references
2130 InsertColumnRef(_pView,pParamRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList);
2131 }
2132 else if ( SQL_ISRULE(pColumnRef,general_set_fct) )
2133 {
2134 if ( pParamRef && pParamRef->getTokenValue().toChar() == '*' )
2135 {
2136 for (auto const& table : *pTabList)
2137 {
2138 OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get());
2139 if (pTabWin->ExistsField( "*", aInfo ))
2140 {
2141 aInfo->SetAlias(OUString());
2142 aInfo->SetTable(OUString());
2143 break;
2144 }
2145 }
2146 }
2147 else
2148 {
2149 OUString sFieldName = aColumns;
2150 if ( pParamRef )
2151 { // we got an aggregate function but without column name inside
2152 // so we set the whole argument of the function as field name
2153 nFunctionType |= FKT_NUMERIC;
2154 sFieldName.clear();
2155 pParamRef->parseNodeToStr( sFieldName,
2156 xConnection,
2157 &rController.getParser().getContext(),
2158 true); // quote is to true because we need quoted elements inside the function
2159 }
2160 aInfo->SetDataType(DataType::DOUBLE);
2161 aInfo->SetFieldType(TAB_NORMAL_FIELD);
2162 aInfo->SetField(sFieldName);
2163 }
2164 aInfo->SetTabWindow(nullptr);
2165 aInfo->SetFieldAlias(aColumnAlias);
2166 }
2167 else
2168 {
2169 _pView->fillFunctionInfo(pColumnRef,aColumns,aInfo);
2170 aInfo->SetFieldAlias(aColumnAlias);
2171 }
2172
2173 if ( SQL_ISRULE(pColumnRef,general_set_fct) )
2174 {
2175 aInfo->SetFunctionType(nFunctionType|FKT_AGGREGATE);
2176 aInfo->SetFunction(OUString(comphelper::string::stripEnd(o3tl::getToken(aColumns,0,'('), ' ')));
2177 }
2178 else
2179 aInfo->SetFunctionType(nFunctionType|FKT_OTHER);
2180
2181 eErrorCode = _pView->InsertField(aInfo, bFirstField);
2182 bFirstField = false;
2183 }
2184 else
2185 {
2186 OUString aColumns;
2187 pColumnRef->parseNodeToStr( aColumns,
2188 xConnection,
2189 &rController.getParser().getContext(),
2190 true); // quote is to true because we need quoted elements inside the function
2191
2192 aInfo->SetTabWindow( nullptr );
2193
2194 // since we support queries in queries, the thingie might belong to an existing "table"
2195 OQueryTableWindow* pExistingTable = lcl_findColumnInTables( aColumns, *pTabList, aInfo );
2196 if ( pExistingTable )
2197 {
2198 aInfo->SetTabWindow( pExistingTable );
2199 aInfo->SetTable( pExistingTable->GetTableName() );
2200 aInfo->SetAlias( pExistingTable->GetAliasName() );
2201 }
2202
2203 aInfo->SetDataType(DataType::DOUBLE);
2204 aInfo->SetFieldType(TAB_NORMAL_FIELD);
2205 aInfo->SetField(aColumns);
2206 aInfo->SetFieldAlias(aColumnAlias);
2207 aInfo->SetFunctionType(FKT_NUMERIC | FKT_OTHER);
2208
2209 eErrorCode = _pView->InsertField(aInfo, bFirstField);
2210 bFirstField = false;
2211 }
2212
2213 break;
2214 }
2215
2216 OSL_FAIL( "InstallFields: don't know how to interpret this parse node!" );
2217
2218 } while ( false );
2219 }
2220 }
2221 else
2222 eErrorCode = eStatementTooComplex;
2223
2224 return eErrorCode;
2225 }
2226 SqlParseError GetOrderCriteria( OQueryDesignView* _pView,
2227 OSelectionBrowseBox* _pSelectionBrw,
2228 const ::connectivity::OSQLParseNode* pParseRoot )
2229 {
2230 SqlParseError eErrorCode = eOk;
2231 if (!pParseRoot->getChild(3)->getChild(ORDER_BY_CHILD_POS)->isLeaf())
2232 {
2233 ::connectivity::OSQLParseNode* pNode = pParseRoot->getChild(3)->getChild(ORDER_BY_CHILD_POS)->getChild(2);
2234 ::connectivity::OSQLParseNode* pParamRef = nullptr;
2235
2236 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
2237 EOrderDir eOrderDir;
2238 for( size_t i=0 ; i<pNode->count() ; i++ )
2239 {
2240 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
2241 eOrderDir = ORDER_ASC;
2242 ::connectivity::OSQLParseNode* pChild = pNode->getChild( i );
2243
2244 if (SQL_ISTOKEN( pChild->getChild(1), DESC ) )
2245 eOrderDir = ORDER_DESC;
2246
2247 ::connectivity::OSQLParseNode* pArgument = pChild->getChild(0);
2248
2249 if(SQL_ISRULE(pArgument,column_ref))
2250 {
2251 if( eOk == FillDragInfo(_pView,pArgument,aDragLeft))
2252 _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i);
2253 else // it could be an alias name for a field
2254 {
2255 OUString aTableRange,aColumnName;
2256 ::connectivity::OSQLParseTreeIterator& rParseIter = rController.getParseIterator();
2257 rParseIter.getColumnRange( pArgument, aColumnName, aTableRange );
2258
2259 OTableFields& aList = rController.getTableFieldDesc();
2260 for (auto const& elem : aList)
2261 {
2262 if(elem.is() && elem->GetFieldAlias() == aColumnName)
2263 elem->SetOrderDir( eOrderDir );
2264 }
2265 }
2266 }
2267 else if(SQL_ISRULE(pArgument, general_set_fct ) &&
2268 SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref) &&
2269 eOk == FillDragInfo(_pView,pParamRef,aDragLeft))
2270 _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i );
2271 else if( SQL_ISRULE(pArgument, set_fct_spec ) )
2272 {
2273
2274 Reference< XConnection> xConnection = rController.getConnection();
2275 if(xConnection.is())
2276 {
2277 OUString sCondition;
2278 pArgument->parseNodeToPredicateStr(sCondition,
2279 xConnection,
2280 rController.getNumberFormatter(),
2281 _pView->getLocale(),
2282 _pView->getDecimalSeparator(),
2283 &rController.getParser().getContext());
2284 _pView->fillFunctionInfo(pArgument,sCondition,aDragLeft);
2285 aDragLeft->SetFunctionType(FKT_OTHER);
2286 aDragLeft->SetOrderDir(eOrderDir);
2287 aDragLeft->SetVisible(false);
2288 _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i );
2289 }
2290 else
2291 eErrorCode = eColumnNotFound;
2292 }
2293 else
2294 eErrorCode = eColumnNotFound;
2295 }
2296 }
2297 return eErrorCode;
2298 }
2299 SqlParseError GetHavingCriteria( OQueryDesignView* _pView,
2300 OSelectionBrowseBox* _pSelectionBrw,
2301 const ::connectivity::OSQLParseNode* pSelectRoot,
2302 sal_uInt16& rLevel )
2303 {
2304 SqlParseError eErrorCode = eOk;
2305 if (!pSelectRoot->getChild(3)->getChild(3)->isLeaf())
2306 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSelectRoot->getChild(3)->getChild(3)->getChild(1),rLevel, true);
2307 return eErrorCode;
2308 }
2309 SqlParseError GetGroupCriteria( OQueryDesignView* _pView,
2310 OSelectionBrowseBox* _pSelectionBrw,
2311 const ::connectivity::OSQLParseNode* pSelectRoot )
2312 {
2313 SqlParseError eErrorCode = eOk;
2314 if (!pSelectRoot->getChild(3)->getChild(2)->isLeaf()) // opt_group_by_clause
2315 {
2316 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
2317 ::connectivity::OSQLParseNode* pGroupBy = pSelectRoot->getChild(3)->getChild(2)->getChild(2);
2318
2319 for( size_t i=0 ; i < pGroupBy->count() && eOk == eErrorCode; ++i )
2320 {
2321 OTableFieldDescRef aDragInfo = new OTableFieldDesc();
2322 ::connectivity::OSQLParseNode* pParamRef = nullptr;
2323 ::connectivity::OSQLParseNode* pArgument = pGroupBy->getChild( i );
2324 if(SQL_ISRULE(pArgument,column_ref))
2325 {
2326 if ( eOk == (eErrorCode = FillDragInfo(_pView,pArgument,aDragInfo)) )
2327 {
2328 aDragInfo->SetGroupBy(true);
2329 _pSelectionBrw->AddGroupBy(aDragInfo);
2330 }
2331 }
2332 else if(SQL_ISRULE(pArgument, general_set_fct ) &&
2333 SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref) &&
2334 eOk == FillDragInfo(_pView,pParamRef,aDragInfo))
2335 {
2336 aDragInfo->SetGroupBy(true);
2337 _pSelectionBrw->AddGroupBy( aDragInfo );
2338 }
2339 else if( SQL_ISRULE(pArgument, set_fct_spec ) )
2340 {
2341 Reference< XConnection> xConnection = rController.getConnection();
2342 if(xConnection.is())
2343 {
2344 OUString sGroupByExpression;
2345 pArgument->parseNodeToStr( sGroupByExpression,
2346 xConnection,
2347 &rController.getParser().getContext(),
2348 true); // quote is to true because we need quoted elements inside the function
2349 _pView->fillFunctionInfo(pArgument,sGroupByExpression,aDragInfo);
2350 aDragInfo->SetFunctionType(FKT_OTHER);
2351 aDragInfo->SetGroupBy(true);
2352 aDragInfo->SetVisible(false);
2353 _pSelectionBrw->AddGroupBy( aDragInfo );
2354 }
2355 else
2356 eErrorCode = eColumnNotFound;
2357 }
2358 }
2359 }
2360 return eErrorCode;
2361 }
2362
2363 OUString getParseErrorMessage( SqlParseError _eErrorCode )
2364 {
2365 TranslateId pResId;
2366 switch (_eErrorCode)
2367 {
2368 case eIllegalJoin:
2369 pResId = STR_QRY_ILLEGAL_JOIN;
2370 break;
2371 case eStatementTooLong:
2372 pResId = STR_QRY_TOO_LONG_STATEMENT;
2373 break;
2374 case eNoConnection:
2375 pResId = STR_QRY_SYNTAX;
2376 break;
2377 case eNoSelectStatement:
2378 pResId = STR_QRY_NOSELECT;
2379 break;
2380 case eNoColumnInLike:
2381 pResId = STR_QRY_SYNTAX;
2382 break;
2383 case eColumnNotFound:
2384 pResId = STR_QRY_SYNTAX;
2385 break;
2386 case eNativeMode:
2387 pResId = STR_QRY_NATIVE;
2388 break;
2389 case eTooManyTables:
2390 pResId = STR_QRY_TOO_MANY_TABLES;
2391 break;
2392 case eTooManyColumns:
2393 pResId = STR_QRY_TOO_MANY_COLUMNS;
2394 break;
2396 pResId = STR_QRY_TOOCOMPLEX;
2397 break;
2398 default:
2399 pResId = STR_QRY_SYNTAX;
2400 break;
2401 }
2402 return DBA_RES(pResId);
2403 }
2404}
2405
2406// end of anonymous namespace
2407
2408OQueryDesignView::OQueryDesignView( OQueryContainerWindow* _pParent,
2409 OQueryController& _rController,
2410 const Reference< XComponentContext >& _rxContext)
2411 :OJoinDesignView( _pParent, _rController, _rxContext )
2412 ,m_aSplitter( VclPtr<Splitter>::Create(this) )
2413 ,m_eChildFocus(NONE)
2414 ,m_bInSplitHandler( false )
2415{
2416
2417 try
2418 {
2419 SvtSysLocale aSysLocale;
2420 m_aLocale = aSysLocale.GetLanguageTag().getLocale();
2422 }
2423 catch(Exception&)
2424 {
2425 }
2426
2428
2429 setNoneVisibleRow(static_cast<OQueryController&>(getController()).getVisibleRows());
2430 m_pSelectionBox->Show();
2431 // setup Splitter
2432 m_aSplitter->SetSplitHdl(LINK(this, OQueryDesignView,SplitHdl));
2433 m_aSplitter->Show();
2434
2435}
2436
2438{
2439 disposeOnce();
2440}
2441
2443{
2444 if ( m_pTableView )
2446 m_pSelectionBox.disposeAndClear();
2449}
2450
2451IMPL_LINK_NOARG( OQueryDesignView, SplitHdl, Splitter*, void )
2452{
2453 if (!getController().isReadOnly())
2454 {
2455 m_bInSplitHandler = true;
2456 m_aSplitter->SetPosPixel( Point( m_aSplitter->GetPosPixel().X(),m_aSplitter->GetSplitPosPixel() ) );
2457 static_cast<OQueryController&>(getController()).setSplitPos(m_aSplitter->GetSplitPosPixel());
2458 static_cast<OQueryController&>(getController()).setModified( true );
2459 Resize();
2460 m_bInSplitHandler = true;
2461 }
2462}
2463
2465{
2469}
2470
2472{
2473 if(static_cast<OQueryController&>(getController()).getSplitPos() != -1)
2474 {
2475 m_aSplitter->SetPosPixel( Point( m_aSplitter->GetPosPixel().X(),static_cast<OQueryController&>(getController()).getSplitPos() ) );
2476 m_aSplitter->SetSplitPosPixel(static_cast<OQueryController&>(getController()).getSplitPos());
2477 }
2478 m_pSelectionBox->initialize();
2479 reset();
2480}
2481
2483{
2484 Point aPlaygroundPos( _rPlayground.TopLeft() );
2485 Size aPlaygroundSize( _rPlayground.GetSize() );
2486
2487 // calc the split pos, and forward it to the controller
2488 sal_Int32 nSplitPos = static_cast<OQueryController&>(getController()).getSplitPos();
2489 if ( 0 != aPlaygroundSize.Height() )
2490 {
2491 if ( ( -1 == nSplitPos )
2492 || ( nSplitPos >= aPlaygroundSize.Height() )
2493 )
2494 {
2495 // let the selection browse box determine an optimal size
2496 Size aSelectionBoxSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize );
2497 nSplitPos = aPlaygroundSize.Height() - aSelectionBoxSize.Height() - m_aSplitter->GetSizePixel().Height();
2498 // still an invalid size?
2499 if ( nSplitPos == -1 || nSplitPos >= aPlaygroundSize.Height() )
2500 nSplitPos = sal_Int32(aPlaygroundSize.Height()*0.6);
2501
2502 static_cast<OQueryController&>(getController()).setSplitPos(nSplitPos);
2503 }
2504
2505 if ( !m_bInSplitHandler )
2506 { // the resize is triggered by something else than the split handler
2507 // our main focus is to try to preserve the size of the selectionbrowse box
2508 Size aSelBoxSize = m_pSelectionBox->GetSizePixel();
2509 if ( aSelBoxSize.Height() )
2510 {
2511 // keep the size of the sel box constant
2512 nSplitPos = aPlaygroundSize.Height() - m_aSplitter->GetSizePixel().Height() - aSelBoxSize.Height();
2513
2514 // and if the box is smaller than the optimal size, try to do something about it
2515 Size aSelBoxOptSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize );
2516 if ( aSelBoxOptSize.Height() > aSelBoxSize.Height() )
2517 {
2518 nSplitPos = aPlaygroundSize.Height() - m_aSplitter->GetSizePixel().Height() - aSelBoxOptSize.Height();
2519 }
2520
2521 static_cast< OQueryController& >(getController()).setSplitPos( nSplitPos );
2522 }
2523 }
2524 }
2525
2526 // normalize the split pos
2527 Point aSplitPos( _rPlayground.Left(), nSplitPos );
2528 Size aSplitSize( _rPlayground.GetSize().Width(), m_aSplitter->GetSizePixel().Height() );
2529
2530 if( ( aSplitPos.Y() + aSplitSize.Height() ) > ( aPlaygroundSize.Height() ))
2531 aSplitPos.setY( aPlaygroundSize.Height() - aSplitSize.Height() );
2532
2533 if( aSplitPos.Y() <= aPlaygroundPos.Y() )
2534 aSplitPos.setY( aPlaygroundPos.Y() + sal_Int32(aPlaygroundSize.Height() * 0.2) );
2535
2536 // position the table
2537 Size aTableViewSize(aPlaygroundSize.Width(), aSplitPos.Y() - aPlaygroundPos.Y());
2538 m_pScrollWindow->SetPosSizePixel(aPlaygroundPos, aTableViewSize);
2539
2540 // position the selection browse box
2541 Point aPos( aPlaygroundPos.X(), aSplitPos.Y() + aSplitSize.Height() );
2542 m_pSelectionBox->SetPosSizePixel( aPos, Size( aPlaygroundSize.Width(), aPlaygroundSize.Height() - aSplitSize.Height() - aTableViewSize.Height() ));
2543
2544 // set the size of the splitter
2545 m_aSplitter->SetPosSizePixel( aSplitPos, aSplitSize );
2546 m_aSplitter->SetDragRectPixel( _rPlayground );
2547
2548 // just for completeness: there is no space left, we occupied it all ...
2549 _rPlayground.SetPos( _rPlayground.BottomRight() );
2550 _rPlayground.SetSize( Size( 0, 0 ) );
2551}
2552
2554{
2555 m_pSelectionBox->SetReadOnly(_bReadOnly);
2556}
2557
2559{
2560 m_pSelectionBox->ClearAll(); // clear the whole selection
2561 m_pTableView->ClearAll();
2562}
2563
2565{
2566 if( m_eChildFocus == SELECTION)
2567 m_pSelectionBox->copy();
2568}
2569
2571{
2572 bool bAllowed = false;
2573 if ( SELECTION == m_eChildFocus )
2574 bAllowed = m_pSelectionBox->isCutAllowed();
2575 return bAllowed;
2576}
2577
2579{
2580 bool bAllowed = false;
2581 if ( SELECTION == m_eChildFocus )
2582 bAllowed = m_pSelectionBox->isPasteAllowed();
2583 return bAllowed;
2584}
2585
2587{
2588 bool bAllowed = false;
2589 if ( SELECTION == m_eChildFocus )
2590 bAllowed = m_pSelectionBox->isCopyAllowed();
2591 return bAllowed;
2592}
2593
2595{
2596 m_pSelectionBox->stopTimer();
2597}
2598
2600{
2601 m_pSelectionBox->startTimer();
2602}
2603
2605{
2606 if( m_eChildFocus == SELECTION)
2607 {
2608 m_pSelectionBox->cut();
2609 static_cast<OQueryController&>(getController()).setModified(true);
2610 }
2611}
2612
2614{
2615 if( m_eChildFocus == SELECTION)
2616 {
2617 m_pSelectionBox->paste();
2618 static_cast<OQueryController&>(getController()).setModified(true);
2619 }
2620}
2621
2622void OQueryDesignView::TableDeleted(const OUString& rAliasName)
2623{
2624 // message that the table was removed from the window
2625 m_pSelectionBox->DeleteFields( rAliasName );
2626 static_cast<OQueryController&>(getController()).InvalidateFeature(ID_BROWSER_ADDTABLE); // inform the view again
2627}
2628
2629bool OQueryDesignView::HasFieldByAliasName(std::u16string_view rFieldName, OTableFieldDescRef const & rInfo) const
2630{
2631 return m_pSelectionBox->HasFieldByAliasName( rFieldName, rInfo);
2632}
2633
2635{
2636 return m_pSelectionBox->InsertField( rInfo, BROWSER_INVALIDID, true/*bVis*/, bActivate ).is() ? eOk : eTooManyColumns;
2637}
2638
2639sal_Int32 OQueryDesignView::getColWidth(sal_uInt16 _nColPos) const
2640{
2641 static sal_Int32 s_nDefaultWidth = GetTextWidth("0") * 15;
2642 sal_Int32 nWidth = static_cast<OQueryController&>(getController()).getColWidth(_nColPos);
2643 if ( !nWidth )
2644 nWidth = s_nDefaultWidth;
2645 return nWidth;
2646}
2647
2648void OQueryDesignView::fillValidFields(std::u16string_view sAliasName, weld::ComboBox& rFieldList)
2649{
2650 rFieldList.clear();
2651
2652 bool bAllTables = sAliasName.empty();
2653
2654 OJoinTableView::OTableWindowMap& rTabWins = m_pTableView->GetTabWinMap();
2655 OUString strCurrentPrefix;
2656 std::vector< OUString> aFields;
2657 for (auto const& tabWin : rTabWins)
2658 {
2659 OQueryTableWindow* pCurrentWin = static_cast<OQueryTableWindow*>(tabWin.second.get());
2660 if (bAllTables || (pCurrentWin->GetAliasName() == sAliasName))
2661 {
2662 strCurrentPrefix = pCurrentWin->GetAliasName() + ".";
2663
2664 pCurrentWin->EnumValidFields(aFields);
2665
2666 for (auto const& field : aFields)
2667 {
2668 if (bAllTables || field.toChar() == '*')
2669 rFieldList.append_text(strCurrentPrefix + field);
2670 else
2671 rFieldList.append_text(field);
2672 }
2673
2674 if (!bAllTables)
2675 // this means that I came into this block because the table name was exactly what I was looking for so I can end here
2676 // (and I prevent that fields get added more than once, if a table is repeated in TabWin)
2677 break;
2678 }
2679 }
2680}
2681
2683{
2684 if (rNEvt.GetType() == NotifyEventType::GETFOCUS)
2685 {
2686 if ( m_pSelectionBox && m_pSelectionBox->HasChildPathFocus() )
2688 else
2690 }
2691
2692 return OJoinDesignView::PreNotify(rNEvt);
2693}
2694
2695// check if the statement is correct when not returning false
2697{
2698 bool bRet = true;
2699 if ( m_pSelectionBox )
2700 bRet = m_pSelectionBox->Save(); // an error occurred so we return no
2701 return bRet;
2702}
2703
2705{
2706 OQueryController& rController = static_cast<OQueryController&>(getController());
2707 m_rController.clearError();
2708 // used for fields which aren't any longer in the statement
2709 OTableFields& rUnUsedFields = rController.getUnUsedFields();
2710 OTableFields().swap( rUnUsedFields );
2711
2712 // create the select columns
2713 sal_uInt32 nFieldcount = 0;
2714 OTableFields& rFieldList = rController.getTableFieldDesc();
2715 for (auto const& field : rFieldList)
2716 {
2717 if (!field->GetField().isEmpty() && field->IsVisible() )
2718 ++nFieldcount;
2719 else if (!field->GetField().isEmpty() &&
2720 !field->HasCriteria() &&
2721 field->isNoneFunction() &&
2722 field->GetOrderDir() == ORDER_NONE &&
2723 !field->IsGroupBy() &&
2724 field->GetFunction().isEmpty() )
2725 rUnUsedFields.push_back(field);
2726 }
2727 if ( !nFieldcount ) // no visible fields so return
2728 {
2729 rUnUsedFields = rFieldList;
2730 return OUString();
2731 }
2732
2733 OQueryTableView::OTableWindowMap& rTabList = m_pTableView->GetTabWinMap();
2734 sal_uInt32 nTabcount = rTabList.size();
2735
2736 OUString aFieldListStr(GenerateSelectList(this,rFieldList,nTabcount>1));
2737 if( aFieldListStr.isEmpty() )
2738 return OUString();
2739
2740 // Exception handling, if no fields have been passed we should not
2741 // change the tab page
2742 // TabBarSelectHdl will query the SQL-OUString for STATEMENT_NOFIELDS
2743 // and trigger an error message
2744 // ----------------- Build table list ----------------------
2745
2746 const auto& rConnList = m_pTableView->getTableConnections();
2747 Reference< XConnection> xConnection = rController.getConnection();
2748 OUString aTableListStr(GenerateFromClause(xConnection,&rTabList,rConnList));
2749 OSL_ENSURE(!aTableListStr.isEmpty(), "OQueryDesignView::getStatement() : unexpected : have Fields, but no Tables !");
2750 // if fields exist now, these only can be created by inserting from an already existing table; if on the other hand
2751 // a table is deleted, also the belonging fields will be deleted -> therefore it CANNOT occur that fields
2752 // exist but no tables exist (and aFieldListStr has its length, I secure this above)
2753 OUStringBuffer aHavingStr,aCriteriaListStr;
2754
2755 // ----------------- build the criteria ----------------------
2756 if (!GenerateCriterias(this,aCriteriaListStr,aHavingStr,rFieldList, nTabcount > 1))
2757 return OUString();
2758
2759 OUString aJoinCrit;
2760 GenerateInnerJoinCriterias(xConnection,aJoinCrit,rConnList);
2761 if(!aJoinCrit.isEmpty())
2762 {
2763 OUString aTmp = "( " + aJoinCrit + " )";
2764 if(!aCriteriaListStr.isEmpty())
2765 {
2766 aTmp += C_AND;
2767 }
2768 aCriteriaListStr.insert(0, aTmp);
2769 }
2770 // ----------------- construct statement ----------------------
2771 OUStringBuffer aSqlCmd("SELECT ");
2772 if(rController.isDistinct())
2773 aSqlCmd.append(" DISTINCT ");
2774 aSqlCmd.append(aFieldListStr + " FROM " + aTableListStr);
2775
2776 if (!aCriteriaListStr.isEmpty())
2777 {
2778 aSqlCmd.append(" WHERE " + aCriteriaListStr);
2779 }
2781 if ( xConnection.is() )
2782 xMeta = xConnection->getMetaData();
2783 bool bUseAlias = nTabcount > 1;
2784 if ( xMeta.is() )
2785 bUseAlias = bUseAlias || !xMeta->supportsGroupByUnrelated();
2786
2787 aSqlCmd.append(GenerateGroupBy(this,rFieldList,bUseAlias));
2788 // ----------------- construct GroupBy and attach ------------
2789 if(!aHavingStr.isEmpty())
2790 {
2791 aSqlCmd.append(" HAVING " + aHavingStr);
2792 }
2793 // ----------------- construct sorting and attach ------------
2794 OUString sOrder;
2795 SqlParseError eErrorCode = eOk;
2796 if ( (eErrorCode = GenerateOrder(this,rFieldList,nTabcount > 1,sOrder)) == eOk)
2797 aSqlCmd.append(sOrder);
2798 else
2799 {
2800 if ( !m_rController.hasError() )
2801 m_rController.appendError( getParseErrorMessage( eErrorCode ) );
2802
2803 m_rController.displayError();
2804 }
2805 // --------------------- Limit Clause -------------------
2806 {
2807 const sal_Int64 nLimit = rController.getLimit();
2808 if( nLimit != -1 )
2809 {
2810 aSqlCmd.append( " LIMIT " + OUString::number(nLimit) );
2811 }
2812 }
2813
2814 OUString sSQL = aSqlCmd.makeStringAndClear();
2815 if ( xConnection.is() )
2816 {
2817 ::connectivity::OSQLParser& rParser( rController.getParser() );
2818 OUString sErrorMessage;
2819 std::unique_ptr<OSQLParseNode> pParseNode( rParser.parseTree( sErrorMessage, sSQL, true ) );
2820 if (pParseNode)
2821 {
2822 OSQLParseNode* pNode = pParseNode->getChild(3)->getChild(1);
2823 if ( pNode->count() > 1 )
2824 {
2825 ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1);
2826 if ( pCondition ) // no where clause
2827 {
2828 OSQLParseNode::compress(pCondition);
2829 OUString sTemp;
2830 pParseNode->parseNodeToStr(sTemp,xConnection);
2831 sSQL = sTemp;
2832 }
2833 }
2834 }
2835 }
2836 return sSQL;
2837}
2838
2839void OQueryDesignView::setSlotEnabled(sal_Int32 _nSlotId, bool _bEnable)
2840{
2841 sal_uInt16 nRow;
2842 switch (_nSlotId)
2843 {
2844 case SID_QUERY_VIEW_FUNCTIONS:
2845 nRow = BROW_FUNCTION_ROW;
2846 break;
2847 case SID_QUERY_VIEW_TABLES:
2848 nRow = BROW_TABLE_ROW;
2849 break;
2850 case SID_QUERY_VIEW_ALIASES:
2851 nRow = BROW_COLUMNALIAS_ROW;
2852 break;
2853 default:
2854 // ????????????
2855 nRow = 0;
2856 break;
2857 }
2858 m_pSelectionBox->SetRowVisible(nRow,_bEnable);
2859 m_pSelectionBox->Invalidate();
2860}
2861
2862bool OQueryDesignView::isSlotEnabled(sal_Int32 _nSlotId)
2863{
2864 sal_uInt16 nRow;
2865 switch (_nSlotId)
2866 {
2867 case SID_QUERY_VIEW_FUNCTIONS:
2868 nRow = BROW_FUNCTION_ROW;
2869 break;
2870 case SID_QUERY_VIEW_TABLES:
2871 nRow = BROW_TABLE_ROW;
2872 break;
2873 case SID_QUERY_VIEW_ALIASES:
2874 nRow = BROW_COLUMNALIAS_ROW;
2875 break;
2876 default:
2877 // ?????????
2878 nRow = 0;
2879 break;
2880 }
2881 return m_pSelectionBox->IsRowVisible(nRow);
2882}
2883
2885{
2886 OQueryController& rCtrl = static_cast<OQueryController&>(getController());
2887 rCtrl.SaveTabWinsPosSize( &m_pTableView->GetTabWinMap(), m_pScrollWindow->GetHScrollBar().GetThumbPos(), m_pScrollWindow->GetVScrollBar().GetThumbPos() );
2888 rCtrl.setVisibleRows( m_pSelectionBox->GetNoneVisibleRows() );
2889 if ( m_aSplitter->GetSplitPosPixel() != 0 )
2890 rCtrl.setSplitPos( m_aSplitter->GetSplitPosPixel() );
2891}
2892
2893std::unique_ptr<OSQLParseNode> OQueryDesignView::getPredicateTreeFromEntry(const OTableFieldDescRef& pEntry,
2894 const OUString& _sCriteria,
2895 OUString& _rsErrorMessage,
2896 Reference<XPropertySet>& _rxColumn) const
2897{
2898 OSL_ENSURE(pEntry.is(),"Entry is null!");
2899 if(!pEntry.is())
2900 return nullptr;
2902 if(!xConnection.is())
2903 return nullptr;
2904
2905 ::connectivity::OSQLParser& rParser( static_cast<OQueryController&>(getController()).getParser() );
2906 OQueryTableWindow* pWin = static_cast<OQueryTableWindow*>(pEntry->GetTabWindow());
2907
2908 // special handling for functions
2909 if ( pEntry->GetFunctionType() & (FKT_OTHER | FKT_AGGREGATE | FKT_NUMERIC) )
2910 {
2911 // we have a function here so we have to distinguish the type of return value
2912 OUString sFunction;
2913 if ( pEntry->isNumericOrAggregateFunction() )
2914 sFunction = pEntry->GetFunction().getToken(0, '(');
2915
2916 if ( sFunction.isEmpty() )
2917 sFunction = pEntry->GetField().getToken(0, '(');
2918
2919 sal_Int32 nType = ::connectivity::OSQLParser::getFunctionReturnType(sFunction,&rParser.getContext());
2920 if ( nType == DataType::OTHER || (sFunction.isEmpty() && pEntry->isNumericOrAggregateFunction()) )
2921 {
2922 // first try the international version
2923 OUString sSql = "SELECT * FROM x WHERE " + pEntry->GetField() + _sCriteria;
2924 std::unique_ptr<OSQLParseNode> pParseNode( rParser.parseTree( _rsErrorMessage, sSql, true ) );
2925 nType = DataType::DOUBLE;
2926 if (pParseNode)
2927 {
2928 OSQLParseNode* pColumnRef = pParseNode->getByRule(OSQLParseNode::column_ref);
2929 if ( pColumnRef )
2930 {
2931 OTableFieldDescRef aField = new OTableFieldDesc();
2932 if ( eOk == FillDragInfo(this,pColumnRef,aField) )
2933 {
2934 nType = aField->GetDataType();
2935 }
2936 }
2937 }
2938 }
2939
2940 Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
2941 rtl::Reference<parse::OParseColumn> pColumn = new parse::OParseColumn( pEntry->GetField(),
2942 OUString(),
2943 OUString(),
2944 OUString(),
2945 ColumnValue::NULLABLE_UNKNOWN,
2946 0,
2947 0,
2948 nType,
2949 false,
2950 false,
2951 xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),
2952 OUString(),
2953 OUString(),
2954 OUString());
2955 _rxColumn = pColumn;
2956 pColumn->setFunction(true);
2957 pColumn->setRealName(pEntry->GetField());
2958 }
2959 else
2960 {
2961 if (pWin)
2962 {
2963 Reference<XNameAccess> xColumns = pWin->GetOriginalColumns();
2964 if (xColumns.is() && xColumns->hasByName(pEntry->GetField()))
2965 xColumns->getByName(pEntry->GetField()) >>= _rxColumn;
2966 }
2967 }
2968
2969 // _rxColumn, if it is a "lookup" column, not a computed column,
2970 // is guaranteed to be the column taken from the *source* of the column,
2971 // that is either a table or another query.
2972 // _rxColumn is *not* taken from the columns of the query we are constructing
2973 // (and rightfully so, since it may not be part of these columns; SELECT A FROM t WHERE B = foo)
2974 // If it is a computed column, we just constructed it above, with same Name and RealName.
2975 // In all cases, we should use the "external" name of the column, not the "RealName";
2976 // the latter is the name that the column had in the source of the source query.
2977 // An example: we are designing "SELECT A, B FROM q WHERE C='foo'"
2978 // q itself is query "SELECT aye AS A, bee as B, cee as C FROM t"
2979 // We are currently treating the entry "C='foo'"
2980 // Then _rxColumn has Name "C" and RealName "cee". We should *obviously* use "C", not "cee".
2981 std::unique_ptr<OSQLParseNode> pParseNode = rParser.predicateTree( _rsErrorMessage,
2982 _sCriteria,
2984 _rxColumn,
2985 false);
2986 return pParseNode;
2987}
2988
2990{
2992 if ( m_pSelectionBox && !m_pSelectionBox->HasChildPathFocus() )
2993 {
2994 // first we have to deactivate the current cell to refill when necessary
2995 m_pSelectionBox->DeactivateCell();
2996 m_pSelectionBox->ActivateCell(m_pSelectionBox->GetCurRow(), m_pSelectionBox->GetCurColumnId());
2997 m_pSelectionBox->GrabFocus();
2998 }
2999}
3000
3002{
3003 m_pTableView->ClearAll();
3004 m_pTableView->ReSync();
3005}
3006
3008{
3009 m_pSelectionBox->SetNoneVisibleRow(_nRows);
3010}
3011
3013{
3014 OQueryController& rController = static_cast< OQueryController& >( getController() );
3015
3016 m_pSelectionBox->PreFill();
3017 m_pSelectionBox->SetReadOnly( rController.isReadOnly() );
3018 m_pSelectionBox->Fill();
3019
3020 for ( auto const & field : i_rFieldDescriptions )
3021 {
3023 pField->Load( field, true );
3024 InsertField( pField, false );
3025 }
3026
3027 rController.ClearUndoManager();
3028 m_pSelectionBox->Invalidate();
3029}
3030
3032{
3033 SqlParseError eErrorCode = eNativeMode;
3034 m_rController.clearError();
3035
3036 try
3037 {
3038 eErrorCode = InitFromParseNodeImpl( this, m_pSelectionBox );
3039
3040 if ( eErrorCode != eOk )
3041 {
3042 if ( !m_rController.hasError() )
3043 m_rController.appendError( getParseErrorMessage( eErrorCode ) );
3044
3045 if ( _pErrorInfo )
3046 {
3047 *_pErrorInfo = m_rController.getError();
3048 }
3049 else
3050 {
3051 m_rController.displayError();
3052 }
3053 }
3054 }
3055 catch ( const Exception& )
3056 {
3057 DBG_UNHANDLED_EXCEPTION("dbaccess");
3058 }
3059 return eErrorCode == eOk;
3060}
3061
3062// Utility function for fillFunctionInfo
3063namespace {
3064 sal_Int32 char_datatype(const::connectivity::OSQLParseNode* pDataType, const unsigned int offset) {
3065 int cnt = pDataType->count() - offset;
3066 if ( cnt < 0 )
3067 {
3068 OSL_FAIL("internal error in decoding character datatype specification");
3069 return DataType::VARCHAR;
3070 }
3071 else if ( cnt == 0 )
3072 {
3073 if ( offset == 0 )
3074 {
3075 // The datatype is the node itself
3076 if ( SQL_ISTOKENOR2 (pDataType, CHARACTER, CHAR) )
3077 return DataType::CHAR;
3078 else if ( SQL_ISTOKEN (pDataType, VARCHAR) )
3079 return DataType::VARCHAR;
3080 else if ( SQL_ISTOKEN (pDataType, CLOB) )
3081 return DataType::CLOB;
3082 else
3083 {
3084 OSL_FAIL("unknown/unexpected token in decoding character datatype specification");
3085 return DataType::VARCHAR;
3086 }
3087 }
3088 else
3089 {
3090 // No child left to read!
3091 OSL_FAIL("incomplete datatype in decoding character datatype specification");
3092 return DataType::VARCHAR;
3093 }
3094 }
3095
3096 if ( SQL_ISTOKEN(pDataType->getChild(offset), NATIONAL) )
3097 return char_datatype(pDataType, offset+1);
3098 else if ( SQL_ISTOKENOR3(pDataType->getChild(offset), CHARACTER, CHAR, NCHAR) )
3099 {
3100 if ( cnt > 2 && SQL_ISTOKEN(pDataType->getChild(offset+1), LARGE) && SQL_ISTOKEN(pDataType->getChild(offset+2), OBJECT) )
3101 return DataType::CLOB;
3102 else if ( cnt > 1 && SQL_ISTOKEN(pDataType->getChild(offset+1), VARYING) )
3103 return DataType::VARCHAR;
3104 else
3105 return DataType::CHAR;
3106 }
3107 else if ( SQL_ISTOKEN (pDataType->getChild(offset), VARCHAR) )
3108 return DataType::VARCHAR;
3109 else if ( SQL_ISTOKENOR2 (pDataType->getChild(offset), CLOB, NCLOB) )
3110 return DataType::CLOB;
3111
3112 OSL_FAIL("unrecognised character datatype");
3113 return DataType::VARCHAR;
3114 }
3115}
3116
3117// Try to guess the type of an expression in simple cases.
3118// Originally meant to be called only on a function call (hence the misnomer),
3119// but now tries to do the best it can also in other cases.
3120// Don't completely rely on fillFunctionInfo,
3121// it won't look at the function's arguments to find the return type
3122// (in particular, in the case of general_set_fct,
3123// the return type is the type of the argument;
3124// if that is (as is typical) a column reference,
3125// it is the type of the column).
3126// TODO: There is similar "guess the expression's type" code in several places:
3127// SelectionBrowseBox.cxx: OSelectionBrowseBox::saveField
3128// QueryDesignView.cxx: InstallFields, GetOrderCriteria, GetGroupCriteria
3129// If possible, they should be factorised into this function
3130// (which should then be renamed...)
3131
3132void OQueryDesignView::fillFunctionInfo( const ::connectivity::OSQLParseNode* pNode
3133 ,const OUString& sFunctionTerm
3134 ,OTableFieldDescRef& aInfo)
3135{
3136 // get the type of the expression, as far as easily possible
3137 OQueryController& rController = static_cast<OQueryController&>(getController());
3138 sal_Int32 nDataType = DataType::DOUBLE;
3139 switch(pNode->getNodeType())
3140 {
3143 nDataType = DataType::VARCHAR;
3144 break;
3145 case SQLNodeType::IntNum:
3146 nDataType = DataType::INTEGER;
3147 break;
3148 case SQLNodeType::ApproxNum:
3149 nDataType = DataType::DOUBLE;
3150 break;
3151 case SQLNodeType::AccessDate:
3152 nDataType = DataType::TIMESTAMP;
3153 break;
3154 case SQLNodeType::Equal:
3155 case SQLNodeType::Less:
3156 case SQLNodeType::Great:
3157 case SQLNodeType::LessEq:
3158 case SQLNodeType::GreatEq:
3160 nDataType = DataType::BOOLEAN;
3161 break;
3162 case SQLNodeType::Name:
3163 case SQLNodeType::ListRule:
3164 case SQLNodeType::CommaListRule:
3165 case SQLNodeType::Keyword:
3166 case SQLNodeType::Punctuation:
3167 OSL_FAIL("Unexpected SQL Node Type");
3168 break;
3169 case SQLNodeType::Rule:
3170 switch(pNode->getKnownRuleID())
3171 {
3191 case OSQLParseNode::scalar_exp: // Seems to never be generated?
3228 OSL_FAIL("Unexpected SQL RuleID");
3229 break;
3232 OSL_FAIL("Cannot guess column type");
3233 break;
3235 OSL_FAIL("Cannot guess VALUES type");
3236 break;
3238 OSL_FAIL("Cannot guess computed column type");
3239 break;
3241 OSL_FAIL("Cannot guess subquery return type");
3242 break;
3260 nDataType = DataType::BOOLEAN;
3261 break;
3266 // Might by an integer or a float; take the most generic
3267 nDataType = DataType::DOUBLE;
3268 break;
3272 // Really, we don't know. Let the default.
3273 break;
3276 nDataType = DataType::INTEGER;
3277 break;
3284 nDataType = DataType::VARCHAR;
3285 break;
3287 nDataType = DataType::TIMESTAMP;
3288 break;
3290 nDataType = DataType::BINARY;
3291 break;
3292 case OSQLParseNode::general_set_fct: // May depend on argument; ignore that for now
3294 {
3295 if (pNode->count() == 0)
3296 {
3297 // This is not a function call, no sense to continue with a function return type lookup
3298 OSL_FAIL("Got leaf SQL node where non-leaf expected");
3299 break;
3300 }
3301 const OSQLParseNode* pFunctionName = pNode->getChild(0);
3302 if ( SQL_ISPUNCTUATION(pFunctionName,"{") )
3303 {
3304 if ( pNode->count() == 3 )
3305 return fillFunctionInfo( pNode->getChild(1), sFunctionTerm, aInfo );
3306 else
3307 OSL_FAIL("ODBC escape not in recognised form");
3308 break;
3309 }
3310 else
3311 {
3312 if ( SQL_ISRULEOR2(pNode,length_exp,char_value_fct) )
3313 pFunctionName = pFunctionName->getChild(0);
3314
3315 OUString sFunctionName = pFunctionName->getTokenValue();
3316 if ( sFunctionName.isEmpty() )
3317 sFunctionName = OStringToOUString(OSQLParser::TokenIDToStr(pFunctionName->getTokenID()),RTL_TEXTENCODING_UTF8);
3318
3320 sFunctionName
3321 ,&rController.getParser().getContext());
3322 }
3323 break;
3324 }
3326 {
3327 if (pNode->count() != 2)
3328 {
3329 OSL_FAIL("interior of ODBC escape not in recognised shape");
3330 break;
3331 }
3332
3333 const OSQLParseNode* const pEscapeType = pNode->getChild(0);
3334 if (SQL_ISTOKEN(pEscapeType, TS))
3335 nDataType = DataType::TIMESTAMP;
3336 else if (SQL_ISTOKEN(pEscapeType, D))
3337 nDataType = DataType::DATE;
3338 else if (SQL_ISTOKEN(pEscapeType, T))
3339 nDataType = DataType::TIME;
3340 else if (SQL_ISTOKEN(pEscapeType, FN))
3341 return fillFunctionInfo( pNode->getChild(1), sFunctionTerm, aInfo );
3342 else
3343 OSL_FAIL("Unknown ODBC escape");
3344 break;
3345 }
3347 {
3348 if ( pNode->count() != 6 || !SQL_ISTOKEN(pNode->getChild(3), AS) )
3349 {
3350 OSL_FAIL("CAST not in recognised shape");
3351 break;
3352 }
3353 const OSQLParseNode *pCastTarget = pNode->getChild(4);
3354 if ( SQL_ISTOKENOR2(pCastTarget, INTEGER, INT) )
3355 nDataType = DataType::INTEGER;
3356 else if ( SQL_ISTOKEN(pCastTarget, SMALLINT) )
3357 nDataType = DataType::SMALLINT;
3358 else if ( SQL_ISTOKEN(pCastTarget, BIGINT) )
3359 nDataType = DataType::BIGINT;
3360 else if ( SQL_ISTOKEN(pCastTarget, FLOAT) )
3361 nDataType = DataType::FLOAT;
3362 else if ( SQL_ISTOKEN(pCastTarget, REAL) )
3363 nDataType = DataType::REAL;
3364 else if ( SQL_ISTOKEN(pCastTarget, DOUBLE) )
3365 nDataType = DataType::DOUBLE;
3366 else if ( SQL_ISTOKEN(pCastTarget, BOOLEAN) )
3367 nDataType = DataType::BOOLEAN;
3368 else if ( SQL_ISTOKEN(pCastTarget, DATE) )
3369 nDataType = DataType::DATE;
3370 else if ( pCastTarget->count() > 0 )
3371 {
3372 const OSQLParseNode *pDataType = pCastTarget->getChild(0);
3373 while (pDataType->count() > 0)
3374 {
3375 pCastTarget = pDataType;
3376 pDataType = pDataType->getChild(0);
3377 }
3378 if ( SQL_ISTOKEN (pDataType, TIME) )
3379 nDataType = DataType::TIME;
3380 else if ( SQL_ISTOKEN (pDataType, TIMESTAMP) )
3381 nDataType = DataType::TIMESTAMP;
3382 else if ( SQL_ISTOKENOR3 (pDataType, CHARACTER, CHAR, NCHAR) )
3383 nDataType = char_datatype(pCastTarget, 0);
3384 else if ( SQL_ISTOKEN (pDataType, VARCHAR) )
3385 nDataType = DataType::VARCHAR;
3386 else if ( SQL_ISTOKEN (pDataType, CLOB) )
3387 nDataType = DataType::CLOB;
3388 else if ( SQL_ISTOKEN (pDataType, NATIONAL) )
3389 nDataType = char_datatype(pCastTarget, 1);
3390 else if ( SQL_ISTOKEN (pDataType, BINARY) )
3391 {
3392 if ( pCastTarget->count() > 2 && SQL_ISTOKEN(pCastTarget->getChild(1), LARGE) && SQL_ISTOKEN(pCastTarget->getChild(2), OBJECT) )
3393 nDataType = DataType::BLOB;
3394 else if ( pCastTarget->count() > 1 && SQL_ISTOKEN(pCastTarget->getChild(1), VARYING) )
3395 nDataType = DataType::VARBINARY;
3396 else
3397 nDataType = DataType::BINARY;
3398 }
3399 else if ( SQL_ISTOKEN (pDataType, VARBINARY) )
3400 nDataType = DataType::VARBINARY;
3401 else if ( SQL_ISTOKEN (pDataType, BLOB) )
3402 nDataType = DataType::BLOB;
3403 else if ( SQL_ISTOKEN (pDataType, NUMERIC) )
3404 nDataType = DataType::NUMERIC;
3405 else if ( SQL_ISTOKENOR2 (pDataType, DECIMAL, DEC) )
3406 nDataType = DataType::DECIMAL;
3407 else if ( SQL_ISTOKEN (pDataType, FLOAT) )
3408 nDataType = DataType::FLOAT;
3409 else if ( SQL_ISTOKEN (pDataType, DOUBLE) )
3410 nDataType = DataType::DOUBLE;
3411 else if ( SQL_ISTOKEN (pDataType, INTERVAL) )
3412 // Not in DataType published constant (because not in JDBC...)
3413 nDataType = DataType::VARCHAR;
3414 else
3415 OSL_FAIL("Failed to decode CAST target");
3416 }
3417 else
3418 OSL_FAIL("Could not decipher CAST target");
3419 break;
3420 }
3421 default:
3422 OSL_FAIL("Unknown SQL RuleID");
3423 break;
3424 }
3425 break;
3426 default:
3427 OSL_FAIL("Unknown SQL Node Type");
3428 break;
3429 }
3430
3431 aInfo->SetDataType(nDataType);
3432 aInfo->SetFieldType(TAB_NORMAL_FIELD);
3433 aInfo->SetField(sFunctionTerm);
3434 aInfo->SetTabWindow(nullptr);
3435}
3436
3437/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 nDataType
OptionalString sSchema
OptionalString sCatalog
OptionalString sComposedName
OptionalString sName
#define BROW_COLUMNALIAS_ROW
#define BROW_FUNCTION_ROW
#define BROW_TABLE_ROW
#define DOUBLE
#define ID_BROWSER_ADDTABLE
Definition: browserids.hxx:53
#define BROWSER_INVALIDID
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, const ILibreOfficeKitNotifier *pNotifier=nullptr)
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
const OUString & getNumDecimalSep() const
NotifyEventType GetType() const
constexpr tools::Long Y() const
void setY(tools::Long nY)
constexpr tools::Long X() const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
const LanguageTag & GetLanguageTag() const
const LocaleDataWrapper & GetLocaleData() const
void AddWindow(vcl::Window *pWindow)
void RemoveWindow(vcl::Window *pWindow)
void disposeAndClear()
static VclPtr< reference_type > Create(Arg &&... arg)
static void absorptions(OSQLParseNode *&pSearchCondition)
static void negateSearchCondition(OSQLParseNode *&pSearchCondition, bool bNegate=false)
static void disjunctiveNormalForm(OSQLParseNode *&pSearchCondition)
void parseNodeToStr(OUString &rString, const css::uno::Reference< css::sdbc::XConnection > &_rxConnection, const IParseContext *pContext=nullptr, bool _bIntl=false, bool _bQuote=true) const
sal_uInt32 getTokenID() const
static OUString getTableRange(const OSQLParseNode *_pTableRef)
void parseNodeToPredicateStr(OUString &rString, const css::uno::Reference< css::sdbc::XConnection > &_rxConnection, const css::uno::Reference< css::util::XNumberFormatter > &xFormatter, const css::lang::Locale &rIntl, OUString _sDec, const IParseContext *pContext=nullptr) const
const OUString & getTokenValue() const
OSQLParseNode * getChild(sal_uInt32 nPos) const
static void compress(OSQLParseNode *&pSearchCondition)
OSQLParseNode * getByRule(OSQLParseNode::Rule eRule) const
static OUString getColumnAlias(const OSQLParseNode *_pDerivedColumn)
const OSQLTables & getTables() const
void getColumnRange(const OSQLParseNode *_pColumnRef, OUString &_rColumnName, OUString &_rTableRange) const
const OSQLParseNode * getParseTree() const
static sal_Int32 getFunctionReturnType(std::u16string_view _sFunctionName, const IParseContext *pContext)
static OString TokenIDToStr(sal_uInt32 nTokenID, const IParseContext *pContext=nullptr)
std::unique_ptr< OSQLParseNode > predicateTree(OUString &rErrorMessage, const OUString &rStatement, const css::uno::Reference< css::util::XNumberFormatter > &xFormatter, const css::uno::Reference< css::beans::XPropertySet > &xField, bool bUseRealName=true)
std::unique_ptr< OSQLParseNode > parseTree(OUString &rErrorMessage, const OUString &rStatement, bool bInternational=false)
const IParseContext & getContext() const
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: dataview.cxx:96
void SaveTabWinsPosSize(OJoinTableView::OTableWindowMap *pTabWinList, tools::Long nOffsetX, tools::Long nOffsetY)
VclPtr< OJoinTableView > m_pTableView
OJoinController & m_rController
VclPtr< OScrollWindowHelper > m_pScrollWindow
virtual void Construct() override
late construction
virtual void dispose() override
OJoinController & getController() const
std::map< OUString, VclPtr< OTableWindow > > OTableWindowMap
void setVisibleRows(sal_Int32 _nVisibleRows)
OTableFields & getUnUsedFields()
::connectivity::OSQLParser & getParser()
OTableFields & getTableFieldDesc()
void setSplitPos(sal_Int32 _nSplitPos)
sal_Int64 getLimit() const
sal_Int32 getColWidth(sal_uInt16 _nColPos) const
virtual void setReadOnly(bool _bReadOnly) override
VclPtr< Splitter > m_aSplitter
virtual void GetFocus() override
void fillFunctionInfo(const ::connectivity::OSQLParseNode *pNode, const OUString &sFunctionTerm, OTableFieldDescRef &aInfo)
void setSlotEnabled(sal_Int32 _nSlotId, bool _bEnable)
VclPtr< OSelectionBrowseBox > m_pSelectionBox
virtual ~OQueryDesignView() override
void initByFieldDescriptions(const css::uno::Sequence< css::beans::PropertyValue > &i_rFieldDescriptions)
virtual void resizeDocumentView(tools::Rectangle &rRect) override
bool isSlotEnabled(sal_Int32 _nSlotId)
std::unique_ptr<::connectivity::OSQLParseNode > getPredicateTreeFromEntry(const OTableFieldDescRef &pEntry, const OUString &_sCriteria, OUString &_rsErrorMessage, css::uno::Reference< css::beans::XPropertySet > &_rxColumn) const
css::lang::Locale m_aLocale
bool HasFieldByAliasName(std::u16string_view rFieldName, OTableFieldDescRef const &rInfo) const
virtual void Construct() override
late construction
virtual void dispose() override
virtual void initialize() override
SqlParseError InsertField(const OTableFieldDescRef &rInfo, bool bActivate=true)
void setNoneVisibleRow(sal_Int32 _nRows)
void TableDeleted(const OUString &rAliasName)
virtual bool PreNotify(NotifyEvent &rNEvt) override
ChildFocusState m_eChildFocus
void fillValidFields(std::u16string_view strTableName, weld::ComboBox &rFieldList)
bool initByParseIterator(::dbtools::SQLExceptionInfo *_pErrorInfo)
initializes the view from the current parser / parse iterator of the controller
OUString const & GetAliasName() const
void ClearUndoManager()
complete clears the Undo/Redo stacks
css::uno::Reference< css::container::XNameAccess > GetOriginalColumns() const
void EnumValidFields(std::vector< OUString > &arrstrFields)
void SetSize(const Size &)
constexpr Point TopLeft() const
void SetPos(const Point &rPoint)
constexpr Size GetSize() const
constexpr Point BottomRight() const
constexpr tools::Long Left() const
tools::Long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::text::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
virtual void GetFocus()
virtual void clear()=0
void append_text(const OUString &rStr)
#define DBA_RES(id)
int nCount
#define DBG_UNHANDLED_EXCEPTION(...)
float u
Reference< XColumn > xColumn
CHARACTER
OUString aName
sal_uInt16 nPos
Sequence< sal_Int8 > aSeq
aStr
std::unique_ptr< sal_Int32[]> pData
@ table
NONE
@ Exception
OString stripEnd(const OString &rIn, char c)
sal_Int32 getTokenCount(std::string_view rIn, char cTok)
DATE
std::map< OUString, OSQLTable, comphelper::UStringMixLess > OSQLTables
css::uno::Reference< css::sdbcx::XColumnsSupplier > OSQLTable
::rtl::Reference< OTableFieldDesc > OTableFieldDescRef
IMPL_LINK_NOARG(OApplicationController, OnClipboardChanged, TransferableDataHelper *, void)
@ eNoSelectStatement
@ eIllegalJoinCondition
@ eStatementTooComplex
@ eStatementTooLong
std::vector< OConnectionLineDataRef > OConnectionLineDataVec
bool generateAsBeforeTableAlias(const css::uno::Reference< css::sdbc::XConnection > &_rxConnection)
determines whether when generating SQL statements, AS should be placed before a table alias
css::uno::Reference< css::util::XNumberFormatter > getNumberFormatter(const css::uno::Reference< css::sdbc::XConnection > &_rxConnection, const css::uno::Reference< css::uno::XComponentContext > &_rxContext)
creates a number formatter
bool isAppendTableAliasEnabled(const css::uno::Reference< css::sdbc::XConnection > &_xConnection)
check if the alias name of the table should be added at select statements
void notifySystemWindow(vcl::Window const *_pWindow, vcl::Window *_pToRegister, const ::comphelper::mem_fun1_t< TaskPaneList, vcl::Window * > &_rMemFunc)
notifySystemWindow adds or remove the given window _pToRegister at the Systemwindow found when search...
Definition: UITools.cxx:918
@ JTCS_TO
Definition: QEnumTypes.hxx:44
@ JTCS_FROM
Definition: QEnumTypes.hxx:43
@ ORDER_ASC
Definition: QEnumTypes.hxx:26
@ ORDER_DESC
Definition: QEnumTypes.hxx:27
@ ORDER_NONE
Definition: QEnumTypes.hxx:25
@ RIGHT_JOIN
Definition: QEnumTypes.hxx:57
@ FULL_JOIN
Definition: QEnumTypes.hxx:55
@ LEFT_JOIN
Definition: QEnumTypes.hxx:56
@ INNER_JOIN
Definition: QEnumTypes.hxx:59
@ CROSS_JOIN
Definition: QEnumTypes.hxx:58
@ FKT_OTHER
Definition: QEnumTypes.hxx:33
@ FKT_NONE
Definition: QEnumTypes.hxx:32
@ FKT_NUMERIC
Definition: QEnumTypes.hxx:36
@ FKT_CONDITION
Definition: QEnumTypes.hxx:35
@ FKT_AGGREGATE
Definition: QEnumTypes.hxx:34
@ TAB_NORMAL_FIELD
Definition: QEnumTypes.hxx:49
std::vector< OTableFieldDescRef > OTableFields
Reference< XConnection > getConnection(const Reference< XRowSet > &_rxRowSet)
int i
void Create(SwFormatVertOrient &rItem, SvStream &rStrm, sal_uInt16 nVersionAbusedAsSize)
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
HashMap_OWString_Interface aMap
QPRO_FUNC_TYPE nType
BINARY
#define SQL_ISRULE(pParseNode, eRule)
#define SQL_ISPUNCTUATION(pParseNode, aString)
#define SQL_ISRULEOR3(pParseNode, e1, e2, e3)
#define SQL_ISTOKEN(pParseNode, token)
#define SQL_ISTOKENOR3(pParseNode, tok0, tok1, tok2)
#define SQL_ISRULEOR2(pParseNode, e1, e2)
#define SQL_ISTOKENOR2(pParseNode, tok0, tok1)
constexpr OUStringLiteral PROPERTY_COMMAND(u"Command")
constexpr OUStringLiteral PROPERTY_OUTERJOINESCAPE(u"EnableOuterJoinEscape")
constexpr OUStringLiteral PROPERTY_NAME(u"Name")
AS