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