bump product version to 4.1.6.2
[LibreOffice.git] / dbaccess / source / ui / querydesign / QueryDesignView.cxx
bloba07b18e45ebc48e51e66b1276abb584f689c4d7b
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 <vcl/split.hxx>
26 #include <svl/undo.hxx>
27 #include <tools/diagnose_ex.h>
28 #include <osl/diagnose.h>
29 #include "adtabdlg.hxx"
30 #include <vcl/svapp.hxx>
31 #include <vcl/combobox.hxx>
32 #include <vcl/msgbox.hxx>
33 #include "browserids.hxx"
34 #include "SelectionBrowseBox.hxx"
35 #include "dbu_qry.hrc"
36 #include <unotools/configmgr.hxx>
37 #include <comphelper/extract.hxx>
38 #include <comphelper/string.hxx>
39 #include <comphelper/types.hxx>
40 #include <connectivity/dbtools.hxx>
41 #include <connectivity/dbexception.hxx>
42 #include <com/sun/star/i18n/XLocaleData.hpp>
43 #include <com/sun/star/sdbc/DataType.hpp>
44 #include <com/sun/star/container/XNameAccess.hpp>
45 #include <com/sun/star/sdbc/ColumnValue.hpp>
46 #include <connectivity/PColumn.hxx>
47 #include "QTableConnection.hxx"
48 #include "ConnectionLine.hxx"
49 #include "ConnectionLineData.hxx"
50 #include "QTableConnectionData.hxx"
51 #include "dbustrings.hrc"
52 #include "UITools.hxx"
53 #include "querycontainerwindow.hxx"
54 #include "sqlmessage.hxx"
55 #include <unotools/syslocale.hxx>
57 using namespace ::dbaui;
58 using namespace ::utl;
59 using namespace ::connectivity;
60 using namespace ::dbtools;
61 using namespace ::com::sun::star::uno;
62 using namespace ::com::sun::star::lang;
63 using namespace ::com::sun::star::i18n;
64 using namespace ::com::sun::star::sdbc;
65 using namespace ::com::sun::star::beans;
66 using namespace ::com::sun::star::container;
68 // here we define our functions used in the anonymous namespace to get our header file smaller
69 // please look at the book LargeScale C++ to know why
70 namespace
72 static const OUString C_AND(" AND ");
73 static const OUString C_OR(" OR ");
75 // forward declarations
76 sal_Bool InsertJoin( const OQueryDesignView* _pView,
77 const ::connectivity::OSQLParseNode *pNode);
79 SqlParseError InstallFields(OQueryDesignView* _pView,
80 const ::connectivity::OSQLParseNode* pNode,
81 OJoinTableView::OTableWindowMap* pTabList );
83 SqlParseError GetGroupCriteria( OQueryDesignView* _pView,
84 OSelectionBrowseBox* _pSelectionBrw,
85 const ::connectivity::OSQLParseNode* pSelectRoot );
87 SqlParseError GetHavingCriteria(OQueryDesignView* _pView,
88 OSelectionBrowseBox* _pSelectionBrw,
89 const ::connectivity::OSQLParseNode* pSelectRoot,
90 sal_uInt16& rLevel );
92 SqlParseError GetOrderCriteria( OQueryDesignView* _pView,
93 OSelectionBrowseBox* _pSelectionBrw,
94 const ::connectivity::OSQLParseNode* pParseRoot );
96 SqlParseError AddFunctionCondition(OQueryDesignView* _pView,
97 OSelectionBrowseBox* _pSelectionBrw,
98 const ::connectivity::OSQLParseNode * pCondition,
99 const sal_uInt16 nLevel,
100 sal_Bool bHaving,
101 bool _bAddOrOnOneLine);
103 //------------------------------------------------------------------------------
104 OUString quoteTableAlias(sal_Bool _bQuote, const OUString& _sAliasName, const OUString& _sQuote)
106 OUString sRet;
107 if ( _bQuote && !_sAliasName.isEmpty() )
109 sRet = ::dbtools::quoteName(_sQuote,_sAliasName);
110 const static OUString sTableSeparater('.');
111 sRet += sTableSeparater;
113 return sRet;
115 //------------------------------------------------------------------------------
116 OUString getTableRange(const OQueryDesignView* _pView,const ::connectivity::OSQLParseNode* _pTableRef)
118 Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
119 OUString sTableRange;
120 if ( _pTableRef )
122 sTableRange = ::connectivity::OSQLParseNode::getTableRange(_pTableRef);
123 if ( sTableRange.isEmpty() )
124 _pTableRef->parseNodeToStr(sTableRange,xConnection,NULL,sal_False,sal_False);
126 return sTableRange;
128 //------------------------------------------------------------------------------
129 void insertConnection(const OQueryDesignView* _pView,const EJoinType& _eJoinType,OTableFieldDescRef _aDragLeft,OTableFieldDescRef _aDragRight,bool _bNatural = false)
131 OQueryTableView* pTableView = static_cast<OQueryTableView*>(_pView->getTableView());
132 OQueryTableConnection* pConn = static_cast<OQueryTableConnection*>( pTableView->GetTabConn(static_cast<OTableWindow*>(_aDragLeft->GetTabWindow()),static_cast<OTableWindow*>(_aDragRight->GetTabWindow()),true));
134 if ( !pConn )
136 OQueryTableConnectionData* pInfoData = new OQueryTableConnectionData();
137 TTableConnectionData::value_type aInfoData(pInfoData);
138 pInfoData->InitFromDrag(_aDragLeft, _aDragRight);
139 pInfoData->SetJoinType(_eJoinType);
141 if ( _bNatural )
143 aInfoData->ResetConnLines();
144 pInfoData->setNatural(_bNatural);
147 Reference<XNameAccess> xReferencedTableColumns(aInfoData->getReferencedTable()->getColumns());
148 Sequence< OUString> aSeq = aInfoData->getReferencingTable()->getColumns()->getElementNames();
149 const OUString* pIter = aSeq.getConstArray();
150 const OUString* pEnd = pIter + aSeq.getLength();
151 for(;pIter != pEnd;++pIter)
153 if ( xReferencedTableColumns->hasByName(*pIter) )
154 aInfoData->AppendConnLine(*pIter,*pIter);
157 catch( const Exception& )
159 DBG_UNHANDLED_EXCEPTION();
163 OQueryTableConnection aInfo(pTableView, aInfoData);
164 // Because OQueryTableConnection never takes ownership of the data passed to it, but only remembers the pointer,
165 // this pointer to a local variable is not critical, as aInfoData and aInfo have the same lifetime
166 pTableView->NotifyTabConnection( aInfo );
168 else
170 OUString aSourceFieldName(_aDragLeft->GetField());
171 OUString aDestFieldName(_aDragRight->GetField());
172 // the connection could point on the other side
173 if(pConn->GetSourceWin() == _aDragRight->GetTabWindow())
175 OUString aTmp(aSourceFieldName);
176 aSourceFieldName = aDestFieldName;
177 aDestFieldName = aTmp;
179 pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName);
180 pConn->UpdateLineList();
181 // Modified-Flag
182 // SetModified();
183 // and redraw
184 pConn->RecalcLines();
185 // for the following Invalidate, the new Connection must first be able
186 // to determine its BoundingRect
187 pConn->InvalidateConnection();
190 //------------------------------------------------------------------------------
191 OUString ParseCondition( OQueryController& rController
192 ,const ::connectivity::OSQLParseNode* pCondition
193 ,const OUString _sDecimal
194 ,const ::com::sun::star::lang::Locale& _rLocale
195 ,sal_uInt32 _nStartIndex)
197 OUString aCondition;
198 Reference< XConnection> xConnection = rController.getConnection();
199 if ( xConnection.is() )
201 sal_uInt32 nCount = pCondition->count();
202 for(sal_uInt32 i = _nStartIndex ; i < nCount ; ++i)
203 pCondition->getChild(i)->parseNodeToPredicateStr(aCondition,
204 xConnection,
205 rController.getNumberFormatter(),
206 _rLocale,
207 static_cast<sal_Char>(_sDecimal.toChar()),
208 &rController.getParser().getContext());
210 return aCondition;
212 //------------------------------------------------------------------------------
213 SqlParseError FillOuterJoins(OQueryDesignView* _pView,
214 const ::connectivity::OSQLParseNode* pTableRefList)
216 SqlParseError eErrorCode = eOk;
217 sal_uInt32 nCount = pTableRefList->count();
218 sal_Bool bError = sal_False;
219 for (sal_uInt32 i=0; !bError && i < nCount; ++i)
221 const ::connectivity::OSQLParseNode* pParseNode = pTableRefList->getChild(i);
222 const ::connectivity::OSQLParseNode* pJoinNode = NULL;
224 if ( SQL_ISRULE( pParseNode, qualified_join ) || SQL_ISRULE( pParseNode, joined_table ) || SQL_ISRULE( pParseNode, cross_union ) )
225 pJoinNode = pParseNode;
226 else if( SQL_ISRULE(pParseNode,table_ref)
227 && pParseNode->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
228 pJoinNode = pParseNode->getChild(2);
230 if ( pJoinNode )
232 if ( !InsertJoin(_pView,pJoinNode) )
233 bError = sal_True;
236 // check if error occurred
237 if ( bError )
238 eErrorCode = eIllegalJoin;
240 return eErrorCode;
242 // -----------------------------------------------------------------------------
244 /** FillDragInfo fills the field description out of the table
246 //------------------------------------------------------------------------------
247 SqlParseError FillDragInfo( const OQueryDesignView* _pView,
248 const ::connectivity::OSQLParseNode* pColumnRef,
249 OTableFieldDescRef& _rDragInfo)
251 SqlParseError eErrorCode = eOk;
253 sal_Bool bErg = sal_False;
255 OUString aTableRange,aColumnName;
256 sal_uInt16 nCntAccount;
257 ::connectivity::OSQLParseTreeIterator& rParseIter = static_cast<OQueryController&>(_pView->getController()).getParseIterator();
258 rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange );
260 if ( !aTableRange.isEmpty() )
262 OQueryTableWindow* pSTW = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( aTableRange );
263 bErg = (pSTW && pSTW->ExistsField( aColumnName, _rDragInfo ) );
265 if ( !bErg )
267 bErg = static_cast<OQueryTableView*>(_pView->getTableView())->FindTableFromField(aColumnName, _rDragInfo, nCntAccount);
268 if ( !bErg )
269 bErg = _pView->HasFieldByAliasName(aColumnName, _rDragInfo);
271 if ( !bErg )
273 eErrorCode = eColumnNotFound;
274 String sError(ModuleRes(STR_QRY_COLUMN_NOT_FOUND));
275 sError.SearchAndReplaceAscii("$name$",aColumnName);
276 _pView->getController().appendError( sError );
280 Reference<XDatabaseMetaData> xMeta = _pView->getController().getConnection()->getMetaData();
281 if ( xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() )
282 _pView->getController().appendError( String( ModuleRes( STR_QRY_CHECK_CASESENSITIVE ) ) );
284 catch(Exception&)
289 return eErrorCode;
291 //------------------------------------------------------------------------------
292 OUString BuildJoinCriteria( const Reference< XConnection>& _xConnection,
293 const OConnectionLineDataVec* pLineDataList,
294 const OQueryTableConnectionData* pData)
296 OUStringBuffer aCondition;
297 if ( _xConnection.is() )
299 OConnectionLineDataVec::const_iterator aIter = pLineDataList->begin();
300 OConnectionLineDataVec::const_iterator aEnd = pLineDataList->end();
303 const Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData();
304 const OUString aQuote = xMetaData->getIdentifierQuoteString();
305 const OUString sEqual(" = ");
307 for(;aIter != aEnd;++aIter)
309 OConnectionLineDataRef pLineData = *aIter;
310 if(aCondition.getLength())
311 aCondition.append(C_AND);
312 aCondition.append(quoteTableAlias(sal_True,pData->GetAliasName(JTCS_FROM),aQuote));
313 aCondition.append(::dbtools::quoteName(aQuote, pLineData->GetFieldName(JTCS_FROM) ));
314 aCondition.append(sEqual);
315 aCondition.append(quoteTableAlias(sal_True,pData->GetAliasName(JTCS_TO),aQuote));
316 aCondition.append(::dbtools::quoteName(aQuote, pLineData->GetFieldName(JTCS_TO) ));
319 catch(SQLException&)
321 OSL_FAIL("Failure while building Join criteria!");
325 return aCondition.makeStringAndClear();
327 //------------------------------------------------------------------------------
328 /** JoinCycle looks for a join cycle and append it to the string
329 @param _xConnection the connection
330 @param _pEntryConn the table connection which holds the data
331 @param _pEntryTabTo the corresponding table window
332 @param _rJoin the String which will contain the resulting string
334 void JoinCycle( const Reference< XConnection>& _xConnection,
335 OQueryTableConnection* _pEntryConn,
336 const OQueryTableWindow* _pEntryTabTo,
337 OUString& _rJoin )
339 OSL_ENSURE(_pEntryConn,"TableConnection can not be null!");
341 OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pEntryConn->GetData().get());
342 if ( pData->GetJoinType() != INNER_JOIN && _pEntryTabTo->ExistsAVisitedConn() )
344 sal_Bool bBrace = sal_False;
345 if(!_rJoin.isEmpty() && _rJoin.lastIndexOf(')') == (_rJoin.getLength()-1))
347 bBrace = sal_True;
348 _rJoin = _rJoin.replaceAt(_rJoin.getLength()-1,1,OUString(' '));
350 (_rJoin += C_AND) += BuildJoinCriteria(_xConnection,pData->GetConnLineDataList(),pData);
351 if(bBrace)
352 _rJoin += OUString(')');
353 _pEntryConn->SetVisited(sal_True);
356 //------------------------------------------------------------------------------
357 OUString BuildTable( const Reference< XConnection>& _xConnection,
358 const OQueryTableWindow* pEntryTab,
359 bool _bForce = false
362 OUString aDBName(pEntryTab->GetComposedName());
364 if( _xConnection.is() )
368 Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData();
370 OUString sCatalog, sSchema, sTable;
371 ::dbtools::qualifiedNameComponents( xMetaData, aDBName, sCatalog, sSchema, sTable, ::dbtools::eInDataManipulation );
372 OUString aTableListStr = ::dbtools::composeTableNameForSelect( _xConnection, sCatalog, sSchema, sTable );
374 OUString aQuote = xMetaData->getIdentifierQuoteString();
375 if ( _bForce || isAppendTableAliasEnabled( _xConnection ) || pEntryTab->GetAliasName() != aDBName )
377 aTableListStr += " ";
378 if ( generateAsBeforeTableAlias( _xConnection ) )
379 aTableListStr += "AS ";
380 aTableListStr += ::dbtools::quoteName( aQuote, pEntryTab->GetAliasName() );
382 aDBName = aTableListStr;
384 catch(const SQLException&)
386 DBG_UNHANDLED_EXCEPTION();
389 return aDBName;
391 //------------------------------------------------------------------------------
392 OUString BuildJoin( const Reference< XConnection>& _xConnection,
393 const OUString& rLh,
394 const OUString& rRh,
395 const OQueryTableConnectionData* pData)
398 OUString aErg(rLh);
399 if ( pData->isNatural() && pData->GetJoinType() != CROSS_JOIN )
400 aErg += " NATURAL ";
401 switch(pData->GetJoinType())
403 case LEFT_JOIN:
404 aErg += " LEFT OUTER ";
405 break;
406 case RIGHT_JOIN:
407 aErg += " RIGHT OUTER ";
408 break;
409 case CROSS_JOIN:
410 OSL_ENSURE(!pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!");
411 aErg += " CROSS ";
412 break;
413 case INNER_JOIN:
414 OSL_ENSURE(pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!");
415 aErg += " INNER ";
416 break;
417 default:
418 aErg += " FULL OUTER ";
419 break;
421 aErg += "JOIN ";
422 aErg += rRh;
423 if ( CROSS_JOIN != pData->GetJoinType() && !pData->isNatural() )
425 aErg += " ON ";
426 aErg += BuildJoinCriteria(_xConnection,pData->GetConnLineDataList(),pData);
429 return aErg;
431 //------------------------------------------------------------------------------
432 OUString BuildJoin( const Reference< XConnection>& _xConnection,
433 const OQueryTableWindow* pLh,
434 const OQueryTableWindow* pRh,
435 const OQueryTableConnectionData* pData
438 bool bForce = pData->GetJoinType() == CROSS_JOIN || pData->isNatural();
439 return BuildJoin(_xConnection,BuildTable(_xConnection,pLh,bForce),BuildTable(_xConnection,pRh,bForce),pData);
441 //------------------------------------------------------------------------------
442 OUString BuildJoin( const Reference< XConnection>& _xConnection,
443 const OUString &rLh,
444 const OQueryTableWindow* pRh,
445 const OQueryTableConnectionData* pData
448 return BuildJoin(_xConnection,rLh,BuildTable(_xConnection,pRh),pData);
450 //------------------------------------------------------------------------------
451 OUString BuildJoin( const Reference< XConnection>& _xConnection,
452 const OQueryTableWindow* pLh,
453 const OUString &rRh,
454 const OQueryTableConnectionData* pData
457 // strict ANSI SQL:
458 // - does not support any bracketing of JOINS
459 // - supports nested joins only in the LEFT HAND SIDE
460 // In this case, we are trying to build a join with a nested join
461 // in the right hand side.
462 // So switch the direction of the join and both hand sides.
463 OQueryTableConnectionData data(*pData);
464 switch (data.GetJoinType())
466 case LEFT_JOIN:
467 data.SetJoinType(RIGHT_JOIN);
468 break;
469 case RIGHT_JOIN:
470 data.SetJoinType(LEFT_JOIN);
471 break;
472 default:
473 // the other join types are symmetric, so nothing to change
474 break;
476 return BuildJoin(_xConnection, rRh, BuildTable(_xConnection,pLh), &data);
478 //------------------------------------------------------------------------------
479 typedef ::std::map< OUString,sal_Bool,::comphelper::UStringMixLess> tableNames_t;
480 //------------------------------------------------------------------------------
481 void addConnectionTableNames( const Reference< XConnection>& _xConnection,
482 const OQueryTableConnection* const pEntryConn,
483 tableNames_t &_rTableNames )
485 // insert tables into table list to avoid double entries
486 const OQueryTableWindow* const pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
487 const OQueryTableWindow* const pEntryTabTo = static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin());
489 OUString sTabName(BuildTable(_xConnection,pEntryTabFrom));
490 if(_rTableNames.find(sTabName) == _rTableNames.end())
491 _rTableNames[sTabName] = sal_True;
492 sTabName = BuildTable(_xConnection,pEntryTabTo);
493 if(_rTableNames.find(sTabName) == _rTableNames.end())
494 _rTableNames[sTabName] = sal_True;
496 //------------------------------------------------------------------------------
497 void GetNextJoin( const Reference< XConnection>& _xConnection,
498 OQueryTableConnection* pEntryConn,
499 OQueryTableWindow* pEntryTabTo,
500 OUString &aJoin,
501 tableNames_t &_rTableNames)
503 OQueryTableConnectionData* pEntryConnData = static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get());
504 if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() )
505 return;
507 if(aJoin.isEmpty())
509 addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
510 OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
511 aJoin = BuildJoin(_xConnection,pEntryTabFrom,pEntryTabTo,pEntryConnData);
513 else if(pEntryTabTo == pEntryConn->GetDestWin())
515 addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
516 aJoin = BuildJoin(_xConnection,aJoin,pEntryTabTo,pEntryConnData);
518 else if(pEntryTabTo == pEntryConn->GetSourceWin())
520 addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
521 aJoin = BuildJoin(_xConnection,pEntryTabTo,aJoin,pEntryConnData);
524 pEntryConn->SetVisited(sal_True);
526 // first search for the "to" window
527 const ::std::vector<OTableConnection*>* pConnections = pEntryConn->GetParent()->getTableConnections();
528 ::std::vector<OTableConnection*>::const_iterator aIter = pConnections->begin();
529 ::std::vector<OTableConnection*>::const_iterator aEnd = pConnections->end();
530 for(;aIter != aEnd;++aIter)
532 OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(*aIter);
533 if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabTo || pNext->GetDestWin() == pEntryTabTo))
535 OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabTo ? static_cast<OQueryTableWindow*>(pNext->GetDestWin()) : static_cast<OQueryTableWindow*>(pNext->GetSourceWin());
536 // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
537 JoinCycle(_xConnection,pNext,pEntryTab,aJoin);
538 if(!pNext->IsVisited())
539 GetNextJoin(_xConnection, pNext, pEntryTab, aJoin, _rTableNames);
543 // when nothing found found look for the "from" window
544 if(aIter == aEnd)
546 OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
547 aIter = pConnections->begin();
548 for(;aIter != aEnd;++aIter)
550 OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(*aIter);
551 if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabFrom || pNext->GetDestWin() == pEntryTabFrom))
553 OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabFrom ? static_cast<OQueryTableWindow*>(pNext->GetDestWin()) : static_cast<OQueryTableWindow*>(pNext->GetSourceWin());
554 // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
555 JoinCycle(_xConnection,pNext,pEntryTab,aJoin);
556 if(!pNext->IsVisited())
557 GetNextJoin(_xConnection, pNext, pEntryTab, aJoin, _rTableNames);
562 //------------------------------------------------------------------------------
563 SqlParseError InsertJoinConnection( const OQueryDesignView* _pView,
564 const ::connectivity::OSQLParseNode *pNode,
565 const EJoinType& _eJoinType,
566 const ::connectivity::OSQLParseNode *pLeftTable,
567 const ::connectivity::OSQLParseNode *pRightTable)
569 SqlParseError eErrorCode = eOk;
570 if (pNode->count() == 3 && // statement between brackets
571 SQL_ISPUNCTUATION(pNode->getChild(0),"(") &&
572 SQL_ISPUNCTUATION(pNode->getChild(2),")"))
574 eErrorCode = InsertJoinConnection(_pView,pNode->getChild(1), _eJoinType,pLeftTable,pRightTable);
576 else if (SQL_ISRULEOR2(pNode,search_condition,boolean_term) && // AND/OR-joints:
577 pNode->count() == 3)
579 // only allow AND joints
580 if (!SQL_ISTOKEN(pNode->getChild(1),AND))
581 eErrorCode = eIllegalJoinCondition;
582 else if ( eOk == (eErrorCode = InsertJoinConnection(_pView,pNode->getChild(0), _eJoinType,pLeftTable,pRightTable)) )
583 eErrorCode = InsertJoinConnection(_pView,pNode->getChild(2), _eJoinType,pLeftTable,pRightTable);
585 else if (SQL_ISRULE(pNode,comparison_predicate))
587 // only the comparison of columns is allowed
588 OSL_ENSURE(pNode->count() == 3,"OQueryDesignView::InsertJoinConnection: Error in Parse Tree");
589 if (!(SQL_ISRULE(pNode->getChild(0),column_ref) &&
590 SQL_ISRULE(pNode->getChild(2),column_ref) &&
591 pNode->getChild(1)->getNodeType() == SQL_NODE_EQUAL))
593 String sError(ModuleRes(STR_QRY_JOIN_COLUMN_COMPARE));
594 _pView->getController().appendError( sError );
595 return eIllegalJoin;
598 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
599 OTableFieldDescRef aDragRight = new OTableFieldDesc();
600 if ( eOk != ( eErrorCode = FillDragInfo(_pView,pNode->getChild(0),aDragLeft)) ||
601 eOk != ( eErrorCode = FillDragInfo(_pView,pNode->getChild(2),aDragRight)))
602 return eErrorCode;
604 if ( pLeftTable )
606 OQueryTableWindow* pLeftWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pLeftTable->getByRule(OSQLParseNode::table_ref) ));
607 if ( pLeftWindow == aDragLeft->GetTabWindow() )
608 insertConnection(_pView,_eJoinType,aDragLeft,aDragRight);
609 else
610 insertConnection(_pView,_eJoinType,aDragRight,aDragLeft);
612 else
613 insertConnection(_pView,_eJoinType,aDragLeft,aDragRight);
615 else
616 eErrorCode = eIllegalJoin;
617 return eErrorCode;
619 //------------------------------------------------------------------------------
620 sal_Bool GetInnerJoinCriteria( const OQueryDesignView* _pView,
621 const ::connectivity::OSQLParseNode *pCondition)
623 return InsertJoinConnection(_pView,pCondition, INNER_JOIN,NULL,NULL) != eOk;
625 //------------------------------------------------------------------------------
626 OUString GenerateSelectList( const OQueryDesignView* _pView,
627 OTableFields& _rFieldList,
628 sal_Bool bAlias)
630 Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
631 if ( !xConnection.is() )
632 return OUString();
634 OUStringBuffer aTmpStr,aFieldListStr;
636 sal_Bool bAsterix = sal_False;
637 int nVis = 0;
638 OTableFields::iterator aIter = _rFieldList.begin();
639 OTableFields::iterator aEnd = _rFieldList.end();
640 for(;aIter != aEnd;++aIter)
642 OTableFieldDescRef pEntryField = *aIter;
643 if ( pEntryField->IsVisible() )
645 if ( pEntryField->GetField().toChar() == '*' )
646 bAsterix = sal_True;
647 ++nVis;
650 if(nVis == 1)
651 bAsterix = sal_False;
655 const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
656 const OUString aQuote = xMetaData->getIdentifierQuoteString();
658 OJoinTableView::OTableWindowMap* pTabList = _pView->getTableView()->GetTabWinMap();
660 const static OUString sFieldSeparator(", ");
661 const static OUString s_sAs(" AS ");
663 aIter = _rFieldList.begin();
664 for(;aIter != aEnd;++aIter)
666 OTableFieldDescRef pEntryField = *aIter;
667 OUString rFieldName = pEntryField->GetField();
668 if ( !rFieldName.isEmpty() && pEntryField->IsVisible() )
670 aTmpStr = OUString();
671 const OUString rAlias = pEntryField->GetAlias();
672 const OUString rFieldAlias = pEntryField->GetFieldAlias();
674 aTmpStr.append(quoteTableAlias((bAlias || bAsterix),rAlias,aQuote));
676 // if we have a none numeric field, the table alias could be in the name
677 // otherwise we are not allowed to do this (e.g. 0.1 * PRICE )
678 if ( !pEntryField->isOtherFunction() )
680 // we have to look if we have alias.* here but before we have to check if the column doesn't already exist
681 OTableFieldDescRef aInfo = new OTableFieldDesc();
682 OJoinTableView::OTableWindowMap::iterator tableIter = pTabList->begin();
683 OJoinTableView::OTableWindowMap::iterator tableEnd = pTabList->end();
684 sal_Bool bFound = sal_False;
685 for(;!bFound && tableIter != tableEnd ;++tableIter)
687 OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(tableIter->second);
689 bFound = pTabWin->ExistsField( rFieldName, aInfo );
690 if ( bFound )
691 rFieldName = aInfo->GetField();
693 if ( ( rFieldName.toChar() != '*' ) && ( rFieldName.indexOf( aQuote ) == -1 ) )
695 OSL_ENSURE(!pEntryField->GetTable().isEmpty(),"No table field name!");
696 aTmpStr.append(::dbtools::quoteName(aQuote, rFieldName));
698 else
699 aTmpStr.append(rFieldName);
701 else
702 aTmpStr.append(rFieldName);
704 if ( pEntryField->isAggreateFunction() )
706 OSL_ENSURE(!pEntryField->GetFunction().isEmpty(),"Function name must not be empty! ;-(");
707 OUStringBuffer aTmpStr2( pEntryField->GetFunction());
708 aTmpStr2.appendAscii("(");
709 aTmpStr2.append(aTmpStr.makeStringAndClear());
710 aTmpStr2.appendAscii(")");
711 aTmpStr = aTmpStr2;
714 if (!rFieldAlias.isEmpty() &&
715 (rFieldName.toChar() != '*' ||
716 pEntryField->isNumericOrAggreateFunction() ||
717 pEntryField->isOtherFunction()))
719 aTmpStr.append(s_sAs);
720 aTmpStr.append(::dbtools::quoteName(aQuote, rFieldAlias));
722 aFieldListStr.append(aTmpStr.makeStringAndClear());
723 aFieldListStr.append(sFieldSeparator);
726 if(aFieldListStr.getLength())
727 aFieldListStr.setLength(aFieldListStr.getLength()-2);
729 catch(SQLException&)
731 OSL_FAIL("Failure while building select list!");
733 return aFieldListStr.makeStringAndClear();
735 //------------------------------------------------------------------------------
736 sal_Bool GenerateCriterias( OQueryDesignView* _pView,
737 OUStringBuffer& rRetStr,
738 OUStringBuffer& rHavingStr,
739 OTableFields& _rFieldList,
740 sal_Bool bMulti )
742 // * must not contain a filter : have I already shown the correct warning ?
743 sal_Bool bCritsOnAsterikWarning = sal_False; // ** TMFS **
745 OUString aFieldName,aCriteria,aWhereStr,aHavingStr,aWork/*,aOrderStr*/;
746 // print line by line joined with AND
747 sal_uInt16 nMaxCriteria = 0;
748 OTableFields::iterator aIter = _rFieldList.begin();
749 OTableFields::iterator aEnd = _rFieldList.end();
750 for(;aIter != aEnd;++aIter)
752 nMaxCriteria = ::std::max<sal_uInt16>(nMaxCriteria,(sal_uInt16)(*aIter)->GetCriteria().size());
754 Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
755 if(!xConnection.is())
756 return sal_False;
759 const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
760 const OUString aQuote = xMetaData->getIdentifierQuoteString();
761 const IParseContext& rContext = static_cast<OQueryController&>(_pView->getController()).getParser().getContext();
763 for (sal_uInt16 i=0 ; i < nMaxCriteria ; i++)
765 aHavingStr = aWhereStr = OUString();
767 for(aIter = _rFieldList.begin();aIter != aEnd;++aIter)
769 OTableFieldDescRef pEntryField = *aIter;
770 aFieldName = pEntryField->GetField();
772 if (aFieldName.isEmpty())
773 continue;
774 aCriteria = pEntryField->GetCriteria( i );
775 if ( !aCriteria.isEmpty() )
777 // * is not allowed to contain any filter, only when used in combination an aggregate function
778 if ( aFieldName.toChar() == '*' && pEntryField->isNoneFunction() )
780 // only show the messagebox the first time
781 if (!bCritsOnAsterikWarning)
782 ErrorBox(_pView, ModuleRes( ERR_QRY_CRITERIA_ON_ASTERISK)).Execute();
783 bCritsOnAsterikWarning = sal_True;
784 continue;
786 aWork = OUString();
789 aWork += quoteTableAlias(bMulti,pEntryField->GetAlias(),aQuote);
791 if ( (pEntryField->GetFunctionType() & (FKT_OTHER|FKT_NUMERIC)) || (aFieldName.toChar() == '*') )
792 aWork += aFieldName;
793 else
794 aWork += ::dbtools::quoteName(aQuote, aFieldName);
796 if ( pEntryField->isAggreateFunction() || pEntryField->IsGroupBy() )
798 if (aHavingStr.isEmpty()) // no more criteria
799 aHavingStr += OUString('('); // bracket
800 else
801 aHavingStr += C_AND;
803 if ( pEntryField->isAggreateFunction() )
805 OSL_ENSURE(!pEntryField->GetFunction().isEmpty(),"No function name for aggregate given!");
806 aHavingStr += pEntryField->GetFunction();
807 aHavingStr += OUString('('); // bracket
808 aHavingStr += aWork;
809 aHavingStr += OUString(')'); // bracket
811 else
812 aHavingStr += aWork;
814 OUString aTmp = aCriteria;
815 OUString aErrorMsg;
816 Reference<XPropertySet> xColumn;
817 SAL_WNODEPRECATED_DECLARATIONS_PUSH
818 ::std::auto_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(pEntryField,aTmp,aErrorMsg,xColumn));
819 SAL_WNODEPRECATED_DECLARATIONS_POP
820 if (pParseNode.get())
822 if (bMulti && !(pEntryField->isOtherFunction() || (aFieldName.toChar() == '*')))
823 pParseNode->replaceNodeValue(pEntryField->GetAlias(),aFieldName);
824 OUString sHavingStr = aHavingStr;
826 sal_uInt32 nCount = pParseNode->count();
827 for( sal_uInt32 node = 1 ; node < nCount ; ++node)
828 pParseNode->getChild(node)->parseNodeToStr( sHavingStr,
829 xConnection,
830 &rContext,
831 sal_False,
832 !pEntryField->isOtherFunction());
833 aHavingStr = sHavingStr;
835 else
836 aHavingStr += aCriteria;
838 else
840 if ( aWhereStr.isEmpty() ) // no more criteria
841 aWhereStr += OUString('('); // bracket
842 else
843 aWhereStr += C_AND;
845 aWhereStr += OUString(' ');
846 // aCriteria could have some german numbers so I have to be sure here
847 OUString aTmp = aCriteria;
848 OUString aErrorMsg;
849 Reference<XPropertySet> xColumn;
850 SAL_WNODEPRECATED_DECLARATIONS_PUSH
851 ::std::auto_ptr< ::connectivity::OSQLParseNode> pParseNode( _pView->getPredicateTreeFromEntry(pEntryField,aTmp,aErrorMsg,xColumn));
852 SAL_WNODEPRECATED_DECLARATIONS_POP
853 if (pParseNode.get())
855 if (bMulti && !(pEntryField->isOtherFunction() || (aFieldName.toChar() == '*')))
856 pParseNode->replaceNodeValue(pEntryField->GetAlias(),aFieldName);
857 OUString aWhere = aWhereStr;
858 pParseNode->parseNodeToStr( aWhere,
859 xConnection,
860 &rContext,
861 sal_False,
862 !pEntryField->isOtherFunction() );
863 aWhereStr = aWhere;
865 else
867 aWhereStr += aWork + "=" + aCriteria;
871 // only once for each field
872 else if ( !i && pEntryField->isCondition() )
874 if (aWhereStr.isEmpty()) // no more criteria
875 aWhereStr += OUString('('); // bracket
876 else
877 aWhereStr += C_AND;
878 aWhereStr += pEntryField->GetField();
881 if (!aWhereStr.isEmpty())
883 aWhereStr += OUString(')'); // close bracket for the AND branch
884 if (rRetStr.getLength()) // are there conditions on the field?
885 rRetStr.append(C_OR);
886 else // open bracket for the OR branch
887 rRetStr.append(sal_Unicode('('));
888 rRetStr.append(aWhereStr);
890 if (!aHavingStr.isEmpty())
892 aHavingStr += OUString(')'); // close bracket for the AND branch
893 if (rHavingStr.getLength()) // are there conditions on the field?
894 rHavingStr.append(C_OR);
895 else // Open bracket for the OR branch
896 rHavingStr.append(sal_Unicode('('));
897 rHavingStr.append(aHavingStr);
901 if (rRetStr.getLength())
902 rRetStr.append(sal_Unicode(')')); // close bracket for the OR branch
903 if (rHavingStr.getLength())
904 rHavingStr.append(sal_Unicode(')')); // close bracket for the OR branch
906 catch(SQLException&)
908 OSL_FAIL("Failure while building where clause!");
910 return sal_True;
912 //------------------------------------------------------------------------------
913 SqlParseError GenerateOrder( OQueryDesignView* _pView,
914 OTableFields& _rFieldList,
915 sal_Bool bMulti,
916 OUString& _rsRet)
918 const OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
919 Reference< XConnection> xConnection = rController.getConnection();
920 if ( !xConnection.is() )
921 return eNoConnection;
923 SqlParseError eErrorCode = eOk;
925 OUString aColumnName;
926 OUString aWorkStr;
929 const bool bColumnAliasInOrderBy = rController.getSdbMetaData().supportsColumnAliasInOrderBy();
930 Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
931 OUString aQuote = xMetaData->getIdentifierQuoteString();
932 // * must not containa filter - have I already shown the warning?
933 sal_Bool bCritsOnAsterikWarning = sal_False; // ** TMFS **
934 OTableFields::iterator aIter = _rFieldList.begin();
935 OTableFields::iterator aEnd = _rFieldList.end();
936 for(;aIter != aEnd;++aIter)
938 OTableFieldDescRef pEntryField = *aIter;
939 EOrderDir eOrder = pEntryField->GetOrderDir();
940 // only create a sort expression when the table name and the sort criteria are defined
941 // otherwise they will be built in GenerateCriteria
942 if ( eOrder != ORDER_NONE )
944 aColumnName = pEntryField->GetField();
945 if(aColumnName.toChar() == '*')
947 // only show the MessageBox the first time
948 if (!bCritsOnAsterikWarning)
949 ErrorBox(_pView, ModuleRes( ERR_QRY_ORDERBY_ON_ASTERISK)).Execute();
950 bCritsOnAsterikWarning = sal_True;
951 continue;
954 if ( bColumnAliasInOrderBy && !pEntryField->GetFieldAlias().isEmpty() )
956 aWorkStr += ::dbtools::quoteName(aQuote, pEntryField->GetFieldAlias());
958 else if ( pEntryField->isNumericOrAggreateFunction() )
960 OSL_ENSURE(!pEntryField->GetFunction().isEmpty(),"Function name cannot be empty! ;-(");
961 aWorkStr += pEntryField->GetFunction();
962 aWorkStr += OUString('(');
963 aWorkStr += quoteTableAlias(bMulti,pEntryField->GetAlias(),aQuote);
964 // only quote column name when we don't have a numeric
965 if ( pEntryField->isNumeric() )
966 aWorkStr += aColumnName;
967 else
968 aWorkStr += ::dbtools::quoteName(aQuote, aColumnName);
970 aWorkStr += OUString(')');
972 else if ( pEntryField->isOtherFunction() )
974 aWorkStr += aColumnName;
976 else
978 aWorkStr += quoteTableAlias(bMulti,pEntryField->GetAlias(),aQuote);
979 aWorkStr += ::dbtools::quoteName(aQuote, aColumnName);
981 aWorkStr += OUString(' ');
982 aWorkStr += OUString( ";ASC;DESC" ).getToken( (sal_uInt16)eOrder, ';' );
983 aWorkStr += OUString(',');
988 String sTemp(comphelper::string::stripEnd(aWorkStr, ','));
989 aWorkStr = sTemp;
992 if ( !aWorkStr.isEmpty() )
994 const sal_Int32 nMaxOrder = xMetaData->getMaxColumnsInOrderBy();
995 String sToken(aWorkStr);
996 if ( nMaxOrder && nMaxOrder < comphelper::string::getTokenCount(sToken, ',') )
997 eErrorCode = eStatementTooLong;
998 else
1000 _rsRet = OUString(" ORDER BY ");
1001 _rsRet += aWorkStr;
1005 catch(SQLException&)
1007 OSL_FAIL("Failure while building group by!");
1010 return eErrorCode;
1013 //------------------------------------------------------------------------------
1014 void GenerateInnerJoinCriterias(const Reference< XConnection>& _xConnection,
1015 OUString& _rJoinCrit,
1016 const ::std::vector<OTableConnection*>* _pConnList)
1018 ::std::vector<OTableConnection*>::const_iterator aIter = _pConnList->begin();
1019 ::std::vector<OTableConnection*>::const_iterator aEnd = _pConnList->end();
1020 for(;aIter != aEnd;++aIter)
1022 const OQueryTableConnection* pEntryConn = static_cast<const OQueryTableConnection*>(*aIter);
1023 OQueryTableConnectionData* pEntryConnData = static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get());
1024 if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() )
1026 if(!_rJoinCrit.isEmpty())
1027 _rJoinCrit += C_AND;
1028 _rJoinCrit += BuildJoinCriteria(_xConnection,pEntryConnData->GetConnLineDataList(),pEntryConnData);
1032 //------------------------------------------------------------------------------
1033 void searchAndAppendName(const Reference< XConnection>& _xConnection,
1034 const OQueryTableWindow* _pTableWindow,
1035 tableNames_t& _rTableNames,
1036 OUString& _rsTableListStr
1039 OUString sTabName(BuildTable(_xConnection,_pTableWindow));
1041 if(_rTableNames.find(sTabName) == _rTableNames.end())
1043 _rTableNames[sTabName] = sal_True;
1044 _rsTableListStr += sTabName;
1045 _rsTableListStr += OUString(',');
1048 //------------------------------------------------------------------------------
1049 OUString GenerateFromClause( const Reference< XConnection>& _xConnection,
1050 const OQueryTableView::OTableWindowMap* pTabList,
1051 const ::std::vector<OTableConnection*>* pConnList
1055 OUString aTableListStr;
1056 // used to avoid putting a table twice in FROM clause
1057 tableNames_t aTableNames;
1059 // generate outer join clause in from
1060 if(!pConnList->empty())
1062 ::std::vector<OTableConnection*>::const_iterator aIter = pConnList->begin();
1063 ::std::vector<OTableConnection*>::const_iterator aEnd = pConnList->end();
1064 ::std::map<OTableWindow*,sal_Int32> aConnectionCount;
1065 for(;aIter != aEnd;++aIter)
1067 static_cast<OQueryTableConnection*>(*aIter)->SetVisited(sal_False);
1068 ++aConnectionCount[(*aIter)->GetSourceWin()];
1069 ++aConnectionCount[(*aIter)->GetDestWin()];
1071 ::std::multimap<sal_Int32 , OTableWindow*> aMulti;
1072 ::std::map<OTableWindow*,sal_Int32>::iterator aCountIter = aConnectionCount.begin();
1073 ::std::map<OTableWindow*,sal_Int32>::iterator aCountEnd = aConnectionCount.end();
1074 for(;aCountIter != aCountEnd;++aCountIter)
1076 aMulti.insert(::std::multimap<sal_Int32 , OTableWindow*>::value_type(aCountIter->second,aCountIter->first));
1079 const sal_Bool bUseEscape = ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_OUTERJOINESCAPE );
1080 ::std::multimap<sal_Int32 , OTableWindow*>::reverse_iterator aRIter = aMulti.rbegin();
1081 ::std::multimap<sal_Int32 , OTableWindow*>::reverse_iterator aREnd = aMulti.rend();
1082 for(;aRIter != aREnd;++aRIter)
1084 ::std::vector<OTableConnection*>::const_iterator aConIter = aRIter->second->getTableView()->getTableConnections(aRIter->second);
1085 for(;aConIter != aEnd;++aConIter)
1087 OQueryTableConnection* pEntryConn = static_cast<OQueryTableConnection*>(*aConIter);
1088 if(!pEntryConn->IsVisited() && pEntryConn->GetSourceWin() == aRIter->second )
1090 OUString aJoin;
1091 GetNextJoin(_xConnection,
1092 pEntryConn,
1093 static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin()),
1094 aJoin,
1095 aTableNames);
1097 if(!aJoin.isEmpty())
1099 OUString aStr;
1100 switch(static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get())->GetJoinType())
1102 case LEFT_JOIN:
1103 case RIGHT_JOIN:
1104 case FULL_JOIN:
1106 // create outer join
1107 if ( bUseEscape )
1108 aStr += "{ OJ ";
1109 aStr += aJoin;
1110 if ( bUseEscape )
1111 aStr += " }";
1113 break;
1114 default:
1115 aStr += aJoin;
1116 break;
1118 aStr += ",";
1119 aTableListStr += aStr;
1125 // and now all inner joins
1126 // these are implemented as
1127 // "FROM tbl1, tbl2 WHERE tbl1.col1=tlb2.col2"
1128 // rather than
1129 // "FROM tbl1 INNER JOIN tbl2 ON tbl1.col1=tlb2.col2"
1130 aIter = pConnList->begin();
1131 for(;aIter != aEnd;++aIter)
1133 OQueryTableConnection* pEntryConn = static_cast<OQueryTableConnection*>(*aIter);
1134 if(!pEntryConn->IsVisited())
1136 searchAndAppendName(_xConnection,
1137 static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin()),
1138 aTableNames,
1139 aTableListStr);
1141 searchAndAppendName(_xConnection,
1142 static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin()),
1143 aTableNames,
1144 aTableListStr);
1148 // all tables that haven't a connection to anyone
1149 OQueryTableView::OTableWindowMap::const_iterator aTabIter = pTabList->begin();
1150 OQueryTableView::OTableWindowMap::const_iterator aTabEnd = pTabList->end();
1151 for(;aTabIter != aTabEnd;++aTabIter)
1153 const OQueryTableWindow* pEntryTab = static_cast<const OQueryTableWindow*>(aTabIter->second);
1154 if(!pEntryTab->ExistsAConn())
1156 aTableListStr += BuildTable(_xConnection,pEntryTab);
1157 aTableListStr += OUString(',');
1161 if(!aTableListStr.isEmpty())
1162 aTableListStr = aTableListStr.replaceAt(aTableListStr.getLength()-1,1, OUString() );
1163 return aTableListStr;
1165 //------------------------------------------------------------------------------
1166 OUString GenerateGroupBy(const OQueryDesignView* _pView,OTableFields& _rFieldList, sal_Bool bMulti )
1168 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1169 const Reference< XConnection> xConnection = rController.getConnection();
1170 if(!xConnection.is())
1171 return OUString();
1173 ::std::map< OUString,bool> aGroupByNames;
1175 OUString aGroupByStr;
1178 const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
1179 const OUString aQuote = xMetaData->getIdentifierQuoteString();
1181 OTableFields::iterator aIter = _rFieldList.begin();
1182 OTableFields::iterator aEnd = _rFieldList.end();
1183 for(;aIter != aEnd;++aIter)
1185 OTableFieldDescRef pEntryField = *aIter;
1186 if ( pEntryField->IsGroupBy() )
1188 OSL_ENSURE(!pEntryField->GetField().isEmpty(),"No Field Name available!;-(");
1189 OUString sGroupByPart = quoteTableAlias(bMulti,pEntryField->GetAlias(),aQuote);
1191 // only quote the field name when it isn't calculated
1192 if ( pEntryField->isNoneFunction() )
1194 sGroupByPart += ::dbtools::quoteName(aQuote, pEntryField->GetField());
1196 else
1198 OUString aTmp = pEntryField->GetField();
1199 OUString aErrorMsg;
1200 Reference<XPropertySet> xColumn;
1201 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1202 ::std::auto_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(pEntryField,aTmp,aErrorMsg,xColumn));
1203 SAL_WNODEPRECATED_DECLARATIONS_POP
1204 if (pParseNode.get())
1206 OUString sGroupBy;
1207 pParseNode->getChild(0)->parseNodeToStr( sGroupBy,
1208 xConnection,
1209 &rController.getParser().getContext(),
1210 sal_False,
1211 !pEntryField->isOtherFunction());
1212 sGroupByPart += sGroupBy;
1214 else
1215 sGroupByPart += pEntryField->GetField();
1217 if ( aGroupByNames.find(sGroupByPart) == aGroupByNames.end() )
1219 aGroupByNames.insert(::std::map< OUString,bool>::value_type(sGroupByPart,true));
1220 aGroupByStr += sGroupByPart;
1221 aGroupByStr += OUString(',');
1225 if ( !aGroupByStr.isEmpty() )
1227 aGroupByStr = aGroupByStr.replaceAt(aGroupByStr.getLength()-1,1, OUString(' ') );
1228 OUString aGroupByStr2(" GROUP BY ");
1229 aGroupByStr2 += aGroupByStr;
1230 aGroupByStr = aGroupByStr2;
1233 catch(SQLException&)
1235 OSL_FAIL("Failure while building group by!");
1237 return aGroupByStr;
1239 // -----------------------------------------------------------------------------
1240 SqlParseError GetORCriteria(OQueryDesignView* _pView,
1241 OSelectionBrowseBox* _pSelectionBrw,
1242 const ::connectivity::OSQLParseNode * pCondition,
1243 sal_uInt16& nLevel ,
1244 sal_Bool bHaving = sal_False,
1245 bool bAddOrOnOneLine = false);
1246 // -----------------------------------------------------------------------------
1247 SqlParseError GetSelectionCriteria( OQueryDesignView* _pView,
1248 OSelectionBrowseBox* _pSelectionBrw,
1249 const ::connectivity::OSQLParseNode* pNode,
1250 sal_uInt16& rLevel )
1252 if (!SQL_ISRULE(pNode, select_statement))
1253 return eNoSelectStatement;
1255 // nyi: more checking for the correct structure!
1256 pNode = pNode ? pNode->getChild(3)->getChild(1) : NULL;
1257 // no where clause found
1258 if (!pNode || pNode->isLeaf())
1259 return eOk;
1261 // Next free sentence...
1262 SqlParseError eErrorCode = eOk;
1263 ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1);
1264 if ( pCondition ) // no where clause
1266 // now we have to check the other conditions
1267 // first make the logical easier
1268 ::connectivity::OSQLParseNode::negateSearchCondition(pCondition);
1269 ::connectivity::OSQLParseNode *pNodeTmp = pNode->getChild(1);
1271 ::connectivity::OSQLParseNode::disjunctiveNormalForm(pNodeTmp);
1272 pNodeTmp = pNode->getChild(1);
1273 ::connectivity::OSQLParseNode::absorptions(pNodeTmp);
1274 pNodeTmp = pNode->getChild(1);
1275 // compress sort the criteria @see http://www.openoffice.org/issues/show_bug.cgi?id=24079
1276 OSQLParseNode::compress(pNodeTmp);
1277 pNodeTmp = pNode->getChild(1);
1279 // first extract the inner joins conditions
1280 GetInnerJoinCriteria(_pView,pNodeTmp);
1281 // now simplify again, join are checked in ComparisonPredicate
1282 ::connectivity::OSQLParseNode::absorptions(pNodeTmp);
1283 pNodeTmp = pNode->getChild(1);
1285 // it could happen that pCondition is not more valid
1286 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pNodeTmp, rLevel);
1288 return eErrorCode;
1290 //------------------------------------------------------------------------------
1291 SqlParseError GetANDCriteria( OQueryDesignView* _pView,
1292 OSelectionBrowseBox* _pSelectionBrw,
1293 const ::connectivity::OSQLParseNode * pCondition,
1294 sal_uInt16& nLevel,
1295 sal_Bool bHaving,
1296 bool bAddOrOnOneLine);
1297 //------------------------------------------------------------------------------
1298 SqlParseError ComparisonPredicate(OQueryDesignView* _pView,
1299 OSelectionBrowseBox* _pSelectionBrw,
1300 const ::connectivity::OSQLParseNode * pCondition,
1301 const sal_uInt16 nLevel,
1302 sal_Bool bHaving,
1303 bool bAddOrOnOneLine);
1304 //------------------------------------------------------------------------------
1305 SqlParseError GetORCriteria(OQueryDesignView* _pView,
1306 OSelectionBrowseBox* _pSelectionBrw,
1307 const ::connectivity::OSQLParseNode * pCondition,
1308 sal_uInt16& nLevel ,
1309 sal_Bool bHaving,
1310 bool bAddOrOnOneLine)
1312 SqlParseError eErrorCode = eOk;
1314 // round brackets around the printout
1315 if (pCondition->count() == 3 &&
1316 SQL_ISPUNCTUATION(pCondition->getChild(0),"(") &&
1317 SQL_ISPUNCTUATION(pCondition->getChild(2),")"))
1319 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pCondition->getChild(1),nLevel,bHaving,bAddOrOnOneLine);
1321 // OR condition
1322 // a searchcondition can only look like this: search_condition SQL_TOKEN_OR boolean_term
1323 else if (SQL_ISRULE(pCondition,search_condition))
1325 for (int i = 0; i < 3 && eErrorCode == eOk ; i+=2)
1327 const ::connectivity::OSQLParseNode* pChild = pCondition->getChild(i);
1328 if ( SQL_ISRULE(pChild,search_condition) )
1329 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pChild,nLevel,bHaving,bAddOrOnOneLine);
1330 else
1332 eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pChild, nLevel,bHaving, i == 0 ? false : bAddOrOnOneLine);
1333 if ( !bAddOrOnOneLine)
1334 nLevel++;
1338 else
1339 eErrorCode = GetANDCriteria( _pView,_pSelectionBrw,pCondition, nLevel, bHaving,bAddOrOnOneLine );
1341 return eErrorCode;
1343 //--------------------------------------------------------------------------------------------------
1344 bool CheckOrCriteria(const ::connectivity::OSQLParseNode* _pCondition,::connectivity::OSQLParseNode* _pFirstColumnRef)
1346 bool bRet = true;
1347 ::connectivity::OSQLParseNode* pFirstColumnRef = _pFirstColumnRef;
1348 for (int i = 0; i < 3 && bRet; i+=2)
1350 const ::connectivity::OSQLParseNode* pChild = _pCondition->getChild(i);
1351 if ( SQL_ISRULE(pChild,search_condition) )
1352 bRet = CheckOrCriteria(pChild,pFirstColumnRef);
1353 else
1355 // this is a simple way to test columns are the same, may be we have to adjust this algo a little bit in future. :-)
1356 ::connectivity::OSQLParseNode* pSecondColumnRef = pChild->getByRule(::connectivity::OSQLParseNode::column_ref);
1357 if ( pFirstColumnRef && pSecondColumnRef )
1358 bRet = *pFirstColumnRef == *pSecondColumnRef;
1359 else if ( !pFirstColumnRef )
1360 pFirstColumnRef = pSecondColumnRef;
1363 return bRet;
1365 //--------------------------------------------------------------------------------------------------
1366 SqlParseError GetANDCriteria( OQueryDesignView* _pView,
1367 OSelectionBrowseBox* _pSelectionBrw,
1368 const ::connectivity::OSQLParseNode * pCondition,
1369 sal_uInt16& nLevel,
1370 sal_Bool bHaving,
1371 bool bAddOrOnOneLine)
1373 const ::com::sun::star::lang::Locale aLocale = _pView->getLocale();
1374 const OUString sDecimal = _pView->getDecimalSeparator();
1376 // I will need a cast pointer to my com::sun::star::sdbcx::Container
1377 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1378 SqlParseError eErrorCode = eOk;
1380 // round brackets
1381 if (SQL_ISRULE(pCondition,boolean_primary))
1383 // check if we have to put the or criteria on one line.
1384 const ::connectivity::OSQLParseNode* pSearchCondition = pCondition->getChild(1);
1385 bool bMustAddOrOnOneLine = CheckOrCriteria(pSearchCondition,NULL);
1386 if ( SQL_ISRULE( pSearchCondition, search_condition) ) // we have a or
1388 _pSelectionBrw->DuplicateConditionLevel( nLevel);
1389 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(0), nLevel,bHaving,bMustAddOrOnOneLine );
1390 ++nLevel;
1391 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(2), nLevel,bHaving,bMustAddOrOnOneLine );
1393 else
1394 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition, nLevel,bHaving,bMustAddOrOnOneLine );
1396 // The first element is (again) an AND condition
1397 else if ( SQL_ISRULE(pCondition,boolean_term) )
1399 OSL_ENSURE(pCondition->count() == 3,"Illegal definifiton of boolean_term");
1400 eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pCondition->getChild(0), nLevel,bHaving,bAddOrOnOneLine );
1401 if ( eErrorCode == eOk )
1402 eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pCondition->getChild(2), nLevel,bHaving,bAddOrOnOneLine );
1404 else if (SQL_ISRULE( pCondition, comparison_predicate))
1406 eErrorCode = ComparisonPredicate(_pView,_pSelectionBrw,pCondition,nLevel,bHaving,bAddOrOnOneLine);
1408 else if( SQL_ISRULE(pCondition,like_predicate) )
1410 const ::connectivity::OSQLParseNode* pValueExp = pCondition->getChild(0);
1411 if (SQL_ISRULE(pValueExp, column_ref ) )
1413 OUString aColumnName;
1414 OUString aCondition;
1415 Reference< XConnection> xConnection = rController.getConnection();
1416 if ( xConnection.is() )
1418 Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
1419 // the international doesn't matter I have a string
1420 pCondition->parseNodeToPredicateStr(aCondition,
1421 xConnection,
1422 rController.getNumberFormatter(),
1423 aLocale,
1424 static_cast<sal_Char>(sDecimal.toChar()),
1425 &rController.getParser().getContext());
1427 pValueExp->parseNodeToPredicateStr( aColumnName,
1428 xConnection,
1429 rController.getNumberFormatter(),
1430 aLocale,
1431 static_cast<sal_Char>(sDecimal.toChar()),
1432 &rController.getParser().getContext());
1434 // don't display the column name
1435 aCondition = aCondition.copy(aColumnName.getLength());
1436 aCondition = aCondition.trim();
1439 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1440 if ( eOk == ( eErrorCode = FillDragInfo(_pView,pValueExp,aDragLeft) ))
1442 if ( bHaving )
1443 aDragLeft->SetGroupBy(sal_True);
1444 _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
1447 else if(SQL_ISRULEOR3(pValueExp, general_set_fct, set_fct_spec, position_exp) ||
1448 SQL_ISRULEOR3(pValueExp, extract_exp, fold, char_substring_fct) ||
1449 SQL_ISRULEOR2(pValueExp, length_exp, char_value_fct))
1451 AddFunctionCondition( _pView,
1452 _pSelectionBrw,
1453 pCondition,
1454 nLevel,
1455 bHaving,
1456 bAddOrOnOneLine);
1458 else
1460 eErrorCode = eNoColumnInLike;
1461 String sError(ModuleRes(STR_QRY_LIKE_LEFT_NO_COLUMN));
1462 _pView->getController().appendError( sError );
1465 else if( SQL_ISRULEOR2(pCondition,test_for_null,in_predicate)
1466 || SQL_ISRULEOR2(pCondition,all_or_any_predicate,between_predicate))
1468 if ( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , general_set_fct ) )
1470 AddFunctionCondition( _pView,
1471 _pSelectionBrw,
1472 pCondition,
1473 nLevel,
1474 bHaving,
1475 bAddOrOnOneLine);
1477 else if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) )
1479 // parse condition
1480 OUString sCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,1);
1481 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1482 if ( eOk == ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(0),aDragLeft)) )
1484 if ( bHaving )
1485 aDragLeft->SetGroupBy(sal_True);
1486 _pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine);
1489 else
1491 // Parse the function condition
1492 OUString sCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,1);
1493 Reference< XConnection> xConnection = rController.getConnection();
1494 Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
1495 // the international doesn't matter I have a string
1496 OUString sName;
1497 pCondition->getChild(0)->parseNodeToPredicateStr(sName,
1498 xConnection,
1499 rController.getNumberFormatter(),
1500 aLocale,
1501 static_cast<sal_Char>(sDecimal.toChar()),
1502 &rController.getParser().getContext());
1504 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1505 aDragLeft->SetField(sName);
1506 aDragLeft->SetFunctionType(FKT_OTHER);
1508 if ( bHaving )
1509 aDragLeft->SetGroupBy(sal_True);
1510 _pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine);
1513 else if( SQL_ISRULEOR2(pCondition,existence_test,unique_test) )
1515 // Parse the function condition
1516 OUString aCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,0);
1518 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1519 aDragLeft->SetField(aCondition);
1520 aDragLeft->SetFunctionType(FKT_CONDITION);
1522 eErrorCode = _pSelectionBrw->InsertField(aDragLeft,BROWSER_INVALIDID,sal_False,sal_True).is() ? eOk : eTooManyColumns;
1524 else //! TODO not supported yet
1525 eErrorCode = eStatementTooComplex;
1526 // Pass on the error code
1527 return eErrorCode;
1529 //------------------------------------------------------------------------------
1530 SqlParseError AddFunctionCondition(OQueryDesignView* _pView,
1531 OSelectionBrowseBox* _pSelectionBrw,
1532 const ::connectivity::OSQLParseNode * pCondition,
1533 const sal_uInt16 nLevel,
1534 sal_Bool bHaving,
1535 bool bAddOrOnOneLine)
1537 SqlParseError eErrorCode = eOk;
1538 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1540 OSQLParseNode* pFunction = pCondition->getChild(0);
1542 OSL_ENSURE(SQL_ISRULEOR3(pFunction, general_set_fct, set_fct_spec, position_exp) ||
1543 SQL_ISRULEOR3(pFunction, extract_exp, fold, char_substring_fct) ||
1544 SQL_ISRULEOR2(pFunction,length_exp,char_value_fct),
1545 "Illegal call!");
1546 OUString aCondition;
1547 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1549 OUString aColumnName;
1550 Reference< XConnection> xConnection = rController.getConnection();
1551 if(xConnection.is())
1553 Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
1554 pCondition->parseNodeToPredicateStr(aCondition,
1555 xConnection,
1556 rController.getNumberFormatter(),
1557 _pView->getLocale(),
1558 static_cast<sal_Char>(_pView->getDecimalSeparator().toChar()),
1559 &rController.getParser().getContext());
1561 pFunction->parseNodeToStr( aColumnName,
1562 xConnection,
1563 &rController.getParser().getContext(),
1564 sal_True,
1565 sal_True); // quote is to true because we need quoted elements inside the function
1566 // don't display the column name
1567 aCondition = aCondition.copy(aColumnName.getLength());
1568 aCondition = aCondition.trim();
1569 if ( aCondition.indexOf('=',0) == 0 ) // ignore the equal sign
1570 aCondition = aCondition.copy(1);
1573 if ( SQL_ISRULE(pFunction, general_set_fct ) )
1575 sal_Int32 nFunctionType = FKT_AGGREGATE;
1576 OSQLParseNode* pParamNode = pFunction->getChild(pFunction->count()-2);
1577 if ( pParamNode && pParamNode->getTokenValue().toChar() == '*' )
1579 OJoinTableView::OTableWindowMap* pTabList = _pView->getTableView()->GetTabWinMap();
1580 OJoinTableView::OTableWindowMap::iterator aIter = pTabList->begin();
1581 OJoinTableView::OTableWindowMap::iterator aTabEnd = pTabList->end();
1582 for(;aIter != aTabEnd;++aIter)
1584 OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(aIter->second);
1585 if (pTabWin->ExistsField( OUString("*"), aDragLeft ))
1587 aDragLeft->SetAlias(String());
1588 aDragLeft->SetTable(String());
1589 break;
1593 else if( eOk != ( eErrorCode = FillDragInfo(_pView,pParamNode,aDragLeft))
1594 && SQL_ISRULE(pParamNode,num_value_exp) )
1596 OUString sParameterValue;
1597 pParamNode->parseNodeToStr( sParameterValue,
1598 xConnection,
1599 &rController.getParser().getContext());
1600 nFunctionType |= FKT_NUMERIC;
1601 aDragLeft->SetField(sParameterValue);
1602 eErrorCode = eOk;
1604 aDragLeft->SetFunctionType(nFunctionType);
1605 if ( bHaving )
1606 aDragLeft->SetGroupBy(sal_True);
1607 sal_Int32 nIndex = 0;
1608 aDragLeft->SetFunction(aColumnName.getToken(0,'(',nIndex));
1610 else
1612 // for an unknown function we write the whole text in the field
1613 aDragLeft->SetField(aColumnName);
1614 if(bHaving)
1615 aDragLeft->SetGroupBy(sal_True);
1616 aDragLeft->SetFunctionType(FKT_OTHER|FKT_NUMERIC);
1618 _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
1621 return eErrorCode;
1623 //------------------------------------------------------------------------------
1624 SqlParseError ComparisonPredicate(OQueryDesignView* _pView,
1625 OSelectionBrowseBox* _pSelectionBrw,
1626 const ::connectivity::OSQLParseNode * pCondition,
1627 const sal_uInt16 nLevel,
1628 sal_Bool bHaving
1629 ,bool bAddOrOnOneLine)
1631 SqlParseError eErrorCode = eOk;
1632 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1634 OSL_ENSURE(SQL_ISRULE( pCondition, comparison_predicate),"ComparisonPredicate: pCondition is not a Comparison Predicate");
1635 if ( SQL_ISRULE(pCondition->getChild(0), column_ref )
1636 || SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref) )
1638 OUString aCondition;
1639 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1641 if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) && SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref ) )
1643 OTableFieldDescRef aDragRight = new OTableFieldDesc();
1644 if (eOk != ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(0),aDragLeft)) ||
1645 eOk != ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(2),aDragRight)))
1646 return eErrorCode;
1648 OQueryTableConnection* pConn = static_cast<OQueryTableConnection*>(
1649 _pView->getTableView()->GetTabConn(static_cast<OQueryTableWindow*>(aDragLeft->GetTabWindow()),
1650 static_cast<OQueryTableWindow*>(aDragRight->GetTabWindow()),
1651 true));
1652 if ( pConn )
1654 OConnectionLineDataVec* pLineDataList = pConn->GetData()->GetConnLineDataList();
1655 OConnectionLineDataVec::iterator aIter = pLineDataList->begin();
1656 OConnectionLineDataVec::iterator aEnd = pLineDataList->end();
1657 for(;aIter != aEnd;++aIter)
1659 if((*aIter)->GetSourceFieldName() == aDragLeft->GetField() ||
1660 (*aIter)->GetDestFieldName() == aDragLeft->GetField() )
1661 break;
1663 if(aIter != aEnd)
1664 return eOk;
1668 sal_uInt32 nPos = 0;
1669 if(SQL_ISRULE(pCondition->getChild(0), column_ref ))
1671 nPos = 0;
1672 sal_uInt32 i=1;
1674 // don't display the equal
1675 if (pCondition->getChild(i)->getNodeType() == SQL_NODE_EQUAL)
1676 i++;
1678 // Bedingung parsen
1679 aCondition = ParseCondition(rController
1680 ,pCondition
1681 ,_pView->getDecimalSeparator()
1682 ,_pView->getLocale()
1683 ,i);
1685 else if( SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref ) )
1687 nPos = pCondition->count()-1;
1689 sal_Int32 i = static_cast<sal_Int32>(pCondition->count() - 2);
1690 switch (pCondition->getChild(i)->getNodeType())
1692 case SQL_NODE_EQUAL:
1693 // don't display the equal
1694 i--;
1695 break;
1696 case SQL_NODE_LESS:
1697 // take the opposite as we change the order
1698 i--;
1699 aCondition = aCondition + OUString(">");
1700 break;
1701 case SQL_NODE_LESSEQ:
1702 // take the opposite as we change the order
1703 i--;
1704 aCondition = aCondition + OUString(">=");
1705 break;
1706 case SQL_NODE_GREAT:
1707 // take the opposite as we change the order
1708 i--;
1709 aCondition = aCondition + OUString("<");
1710 break;
1711 case SQL_NODE_GREATEQ:
1712 // take the opposite as we change the order
1713 i--;
1714 aCondition = aCondition + OUString("<=");
1715 break;
1716 default:
1717 break;
1720 // go backward
1721 Reference< XConnection> xConnection = rController.getConnection();
1722 if(xConnection.is())
1724 Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
1725 for (; i >= 0; i--)
1726 pCondition->getChild(i)->parseNodeToPredicateStr(aCondition,
1727 xConnection,
1728 rController.getNumberFormatter(),
1729 _pView->getLocale(),
1730 static_cast<sal_Char>(_pView->getDecimalSeparator().toChar()),
1731 &rController.getParser().getContext());
1734 // else ???
1737 if( eOk == ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(nPos),aDragLeft)))
1739 if(bHaving)
1740 aDragLeft->SetGroupBy(sal_True);
1741 _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
1744 else if( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , general_set_fct ) )
1746 AddFunctionCondition( _pView,
1747 _pSelectionBrw,
1748 pCondition,
1749 nLevel,
1750 bHaving,
1751 bAddOrOnOneLine);
1753 else // it can only be an Expr
1755 OUString aName,aCondition;
1757 ::connectivity::OSQLParseNode *pLhs = pCondition->getChild(0);
1758 ::connectivity::OSQLParseNode *pRhs = pCondition->getChild(2);
1759 // Field name
1760 Reference< XConnection> xConnection = rController.getConnection();
1761 if(xConnection.is())
1763 pLhs->parseNodeToStr(aName,
1764 xConnection,
1765 &rController.getParser().getContext(),
1766 sal_True);
1767 // Criteria
1768 aCondition = pCondition->getChild(1)->getTokenValue();
1769 pRhs->parseNodeToPredicateStr(aCondition,
1770 xConnection,
1771 rController.getNumberFormatter(),
1772 _pView->getLocale(),
1773 static_cast<sal_Char>(_pView->getDecimalSeparator().toChar()),
1774 &rController.getParser().getContext());
1777 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1778 aDragLeft->SetField(aName);
1779 aDragLeft->SetFunctionType(FKT_OTHER|FKT_NUMERIC);
1780 // and add it on
1781 _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
1783 return eErrorCode;
1786 //------------------------------------------------------------------------------
1787 namespace
1789 OQueryTableWindow* lcl_findColumnInTables( const OUString& _rColumName, const OJoinTableView::OTableWindowMap& _rTabList, OTableFieldDescRef& _rInfo )
1791 OJoinTableView::OTableWindowMap::const_iterator aIter = _rTabList.begin();
1792 OJoinTableView::OTableWindowMap::const_iterator aEnd = _rTabList.end();
1793 for ( ; aIter != aEnd; ++aIter )
1795 OQueryTableWindow* pTabWin = static_cast< OQueryTableWindow* >( aIter->second );
1796 if ( pTabWin && pTabWin->ExistsField( _rColumName, _rInfo ) )
1797 return pTabWin;
1799 return NULL;
1803 //------------------------------------------------------------------------------
1804 void InsertColumnRef(const OQueryDesignView* _pView,
1805 const ::connectivity::OSQLParseNode * pColumnRef,
1806 OUString& aColumnName,
1807 const OUString& aColumnAlias,
1808 OUString& aTableRange,
1809 OTableFieldDescRef& _raInfo,
1810 OJoinTableView::OTableWindowMap* pTabList)
1813 // Put the table names together
1814 ::connectivity::OSQLParseTreeIterator& rParseIter = static_cast<OQueryController&>(_pView->getController()).getParseIterator();
1815 rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange );
1817 sal_Bool bFound(sal_False);
1818 OSL_ENSURE(!aColumnName.isEmpty(),"Column name must not be empty");
1819 if (aTableRange.isEmpty())
1821 // SELECT column, ...
1822 bFound = NULL != lcl_findColumnInTables( aColumnName, *pTabList, _raInfo );
1823 if ( bFound && ( aColumnName.toChar() != '*' ) )
1824 _raInfo->SetFieldAlias(aColumnAlias);
1826 else
1828 // SELECT range.column, ...
1829 OQueryTableWindow* pTabWin = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable(aTableRange);
1831 if (pTabWin && pTabWin->ExistsField(aColumnName, _raInfo))
1833 if(aColumnName.toChar() != '*')
1834 _raInfo->SetFieldAlias(aColumnAlias);
1835 bFound = sal_True;
1838 if (!bFound)
1840 _raInfo->SetTable(OUString());
1841 _raInfo->SetAlias(OUString());
1842 _raInfo->SetField(aColumnName);
1843 _raInfo->SetFieldAlias(aColumnAlias); // nyi : here it continues Expr_1, Expr_2 ...
1844 _raInfo->SetFunctionType(FKT_OTHER);
1847 //-----------------------------------------------------------------------------
1848 sal_Bool checkJoinConditions( const OQueryDesignView* _pView,
1849 const ::connectivity::OSQLParseNode* _pNode )
1851 const ::connectivity::OSQLParseNode* pJoinNode = NULL;
1852 sal_Bool bRet = sal_True;
1853 if (SQL_ISRULE(_pNode,qualified_join))
1854 pJoinNode = _pNode;
1855 else if (SQL_ISRULE(_pNode,table_ref)
1856 && _pNode->count() == 3
1857 && SQL_ISPUNCTUATION(_pNode->getChild(0),"(")
1858 && SQL_ISPUNCTUATION(_pNode->getChild(2),")") ) // '(' joined_table ')'
1859 pJoinNode = _pNode->getChild(1);
1860 else if (! ( SQL_ISRULE(_pNode, table_ref) && _pNode->count() == 2) ) // table_node table_primary_as_range_column
1861 bRet = sal_False;
1863 if (pJoinNode && !InsertJoin(_pView,pJoinNode))
1864 bRet = sal_False;
1865 return bRet;
1867 //-----------------------------------------------------------------------------
1868 sal_Bool InsertJoin(const OQueryDesignView* _pView,
1869 const ::connectivity::OSQLParseNode *pNode)
1871 OSL_ENSURE( SQL_ISRULE( pNode, qualified_join ) || SQL_ISRULE( pNode, joined_table ) || SQL_ISRULE( pNode, cross_union ),
1872 "OQueryDesignView::InsertJoin: Error in the Parse Tree");
1874 if (SQL_ISRULE(pNode,joined_table))
1875 return InsertJoin(_pView,pNode->getChild(1));
1877 // first check the left and right side
1878 const ::connectivity::OSQLParseNode* pRightTableRef = pNode->getChild(3); // table_ref
1879 if ( SQL_ISRULE(pNode, qualified_join) && SQL_ISTOKEN(pNode->getChild(1),NATURAL) )
1880 pRightTableRef = pNode->getChild(4); // table_ref
1882 if ( !checkJoinConditions(_pView,pNode->getChild(0)) || !checkJoinConditions(_pView,pRightTableRef))
1883 return sal_False;
1885 // named column join may be implemented later
1886 // SQL_ISRULE(pNode->getChild(4),named_columns_join)
1887 EJoinType eJoinType = INNER_JOIN;
1888 bool bNatural = false;
1889 if ( SQL_ISRULE(pNode, qualified_join) )
1891 ::connectivity::OSQLParseNode* pJoinType = pNode->getChild(1); // join_type
1892 if ( SQL_ISTOKEN(pJoinType,NATURAL) )
1894 bNatural = true;
1895 pJoinType = pNode->getChild(2);
1898 if (SQL_ISRULE(pJoinType,join_type) && (!pJoinType->count() || SQL_ISTOKEN(pJoinType->getChild(0),INNER)))
1900 eJoinType = INNER_JOIN;
1902 else
1904 if (SQL_ISRULE(pJoinType,join_type)) // one level deeper
1905 pJoinType = pJoinType->getChild(0);
1907 if (SQL_ISTOKEN(pJoinType->getChild(0),LEFT))
1908 eJoinType = LEFT_JOIN;
1909 else if(SQL_ISTOKEN(pJoinType->getChild(0),RIGHT))
1910 eJoinType = RIGHT_JOIN;
1911 else
1912 eJoinType = FULL_JOIN;
1914 if ( SQL_ISRULE(pNode->getChild(4),join_condition) )
1916 if ( InsertJoinConnection(_pView,pNode->getChild(4)->getChild(1), eJoinType,pNode->getChild(0),pRightTableRef) != eOk )
1917 return sal_False;
1920 else if ( SQL_ISRULE(pNode, cross_union) )
1922 eJoinType = CROSS_JOIN;
1923 pRightTableRef = pNode->getChild(pNode->count() - 1);
1925 else
1926 return sal_False;
1928 if ( eJoinType == CROSS_JOIN || bNatural )
1931 OQueryTableWindow* pLeftWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pNode->getChild(0)) );
1932 OQueryTableWindow* pRightWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pRightTableRef) );
1933 OSL_ENSURE(pLeftWindow && pRightWindow,"Table Windows could not be found!");
1934 if ( !pLeftWindow || !pRightWindow )
1935 return sal_False;
1937 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
1938 aDragLeft->SetTabWindow(pLeftWindow);
1939 aDragLeft->SetTable(pLeftWindow->GetTableName());
1940 aDragLeft->SetAlias(pLeftWindow->GetAliasName());
1942 OTableFieldDescRef aDragRight = new OTableFieldDesc();
1943 aDragRight->SetTabWindow(pRightWindow);
1944 aDragRight->SetTable(pRightWindow->GetTableName());
1945 aDragRight->SetAlias(pRightWindow->GetAliasName());
1947 insertConnection(_pView,eJoinType,aDragLeft,aDragRight,bNatural);
1951 return sal_True;
1953 //------------------------------------------------------------------------------
1954 void insertUnUsedFields(OQueryDesignView* _pView,OSelectionBrowseBox* _pSelectionBrw)
1956 // now we have to insert the fields which aren't in the statement
1957 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1958 OTableFields& rUnUsedFields = rController.getUnUsedFields();
1959 OTableFields::iterator aEnd = rUnUsedFields.end();
1960 for(OTableFields::iterator aIter = rUnUsedFields.begin();aIter != aEnd;++aIter)
1961 if(_pSelectionBrw->InsertField(*aIter,BROWSER_INVALIDID,sal_False,sal_False).is())
1962 (*aIter) = NULL;
1963 OTableFields().swap( rUnUsedFields );
1966 //------------------------------------------------------------------------------
1967 SqlParseError InitFromParseNodeImpl(OQueryDesignView* _pView,OSelectionBrowseBox* _pSelectionBrw)
1969 SqlParseError eErrorCode = eOk;
1971 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
1973 _pSelectionBrw->PreFill();
1974 _pSelectionBrw->SetReadOnly(rController.isReadOnly());
1975 _pSelectionBrw->Fill();
1978 ::connectivity::OSQLParseTreeIterator& aIterator = rController.getParseIterator();
1979 const ::connectivity::OSQLParseNode* pParseTree = aIterator.getParseTree();
1983 if ( !pParseTree )
1985 // now we have to insert the fields which aren't in the statement
1986 insertUnUsedFields(_pView,_pSelectionBrw);
1987 break;
1990 if ( !rController.isEsacpeProcessing() ) // not allowed in this mode
1992 eErrorCode = eNativeMode;
1993 break;
1996 if ( !( SQL_ISRULE( pParseTree, select_statement ) ) )
1998 eErrorCode = eNoSelectStatement;
1999 break;
2002 const OSQLParseNode* pTableExp = pParseTree->getChild(3);
2003 if ( pTableExp->getChild(7)->count() > 0 || pTableExp->getChild(8)->count() > 0)
2005 eErrorCode = eStatementTooComplex;
2006 break;
2009 Reference< XConnection> xConnection = rController.getConnection();
2010 if ( !xConnection.is() )
2012 OSL_FAIL( "InitFromParseNodeImpl: no connection? no connection!" );
2013 break;
2016 const OSQLTables& aMap = aIterator.getTables();
2017 ::comphelper::UStringMixLess aTmp(aMap.key_comp());
2018 ::comphelper::UStringMixEqual aKeyComp( aTmp.isCaseSensitive() );
2020 Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
2023 sal_Int32 nMax = xMetaData->getMaxTablesInSelect();
2024 if ( nMax && nMax < (sal_Int32)aMap.size() )
2026 eErrorCode = eTooManyTables;
2027 break;
2030 OUString sComposedName;
2031 OUString sAlias;
2033 OQueryTableView* pTableView = static_cast<OQueryTableView*>(_pView->getTableView());
2034 pTableView->clearLayoutInformation();
2035 OSQLTables::const_iterator aIter = aMap.begin();
2036 OSQLTables::const_iterator aEnd = aMap.end();
2037 for(;aIter != aEnd;++aIter)
2039 OSQLTable xTable = aIter->second;
2040 Reference< XPropertySet > xTableProps( xTable, UNO_QUERY_THROW );
2042 sAlias = aIter->first;
2044 // check whether this is a query
2045 Reference< XPropertySetInfo > xPSI = xTableProps->getPropertySetInfo();
2046 bool bIsQuery = xPSI.is() && xPSI->hasPropertyByName( PROPERTY_COMMAND );
2048 if ( bIsQuery )
2049 OSL_VERIFY( xTableProps->getPropertyValue( PROPERTY_NAME ) >>= sComposedName );
2050 else
2052 sComposedName = ::dbtools::composeTableName( xMetaData, xTableProps, ::dbtools::eInDataManipulation, false, false, false );
2054 // if the alias is the complete (composed) table, then shorten it
2055 if ( aKeyComp( sComposedName, aIter->first ) )
2057 OUString sCatalog, sSchema, sTable;
2058 ::dbtools::qualifiedNameComponents( xMetaData, sComposedName, sCatalog, sSchema, sTable, ::dbtools::eInDataManipulation );
2059 sAlias = sTable;
2063 // find the existent window for this alias
2064 OQueryTableWindow* pExistentWin = pTableView->FindTable( sAlias );
2065 if ( !pExistentWin )
2067 pTableView->AddTabWin( sComposedName, sAlias, sal_False ); // don't create data here
2069 else
2071 // there already exists a window for this alias ....
2072 if ( !aKeyComp( pExistentWin->GetData()->GetComposedName(), sComposedName ) )
2073 // ... but for another complete table name -> new window
2074 pTableView->AddTabWin(sComposedName, sAlias);
2078 // now delete the data for which we haven't any tablewindow
2079 OJoinTableView::OTableWindowMap aTableMap(*pTableView->GetTabWinMap());
2080 OJoinTableView::OTableWindowMap::iterator aIterTableMap = aTableMap.begin();
2081 OJoinTableView::OTableWindowMap::iterator aIterTableEnd = aTableMap.end();
2082 for(;aIterTableMap != aIterTableEnd;++aIterTableMap)
2084 if(aMap.find(aIterTableMap->second->GetComposedName()) == aMap.end() &&
2085 aMap.find(aIterTableMap->first) == aMap.end())
2086 pTableView->RemoveTabWin(aIterTableMap->second);
2089 if ( eOk == (eErrorCode = FillOuterJoins(_pView,pTableExp->getChild(0)->getChild(1))) )
2091 // check if we have a distinct statement
2092 if(SQL_ISTOKEN(pParseTree->getChild(1),DISTINCT))
2094 rController.setDistinct(sal_True);
2095 rController.InvalidateFeature(SID_QUERY_DISTINCT_VALUES);
2097 else
2099 rController.setDistinct(sal_False);
2102 ///check if query has a limit
2103 if( pTableExp->getChild(6)->count() >= 2 && pTableExp->getChild(6)->getChild(1) )
2105 rController.setLimit(
2106 pTableExp->getChild(6)->getChild(1)->getTokenValue().toInt64() );
2108 else
2110 rController.setLimit(-1);
2113 if ( (eErrorCode = InstallFields(_pView,pParseTree, pTableView->GetTabWinMap())) == eOk )
2115 // GetSelectionCriteria must be called before GetHavingCriteria
2116 sal_uInt16 nLevel=0;
2118 if ( eOk == (eErrorCode = GetSelectionCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) )
2120 if ( eOk == (eErrorCode = GetGroupCriteria(_pView,_pSelectionBrw,pParseTree)) )
2122 if ( eOk == (eErrorCode = GetHavingCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) )
2124 if ( eOk == (eErrorCode = GetOrderCriteria(_pView,_pSelectionBrw,pParseTree)) )
2125 insertUnUsedFields(_pView,_pSelectionBrw);
2132 catch(SQLException&)
2134 OSL_FAIL("getMaxTablesInSelect!");
2137 while ( false );
2139 // New Undo-Actions were created in the Manager by the regeneration
2140 rController.ClearUndoManager();
2141 _pSelectionBrw->Invalidate();
2142 return eErrorCode;
2144 //------------------------------------------------------------------------------
2145 /** fillSelectSubList
2146 @return
2147 <TRUE/> when columns could be inserted otherwise <FALSE/>
2149 //------------------------------------------------------------------------------
2150 SqlParseError fillSelectSubList( OQueryDesignView* _pView,
2151 OJoinTableView::OTableWindowMap* _pTabList)
2153 SqlParseError eErrorCode = eOk;
2154 sal_Bool bFirstField = sal_True;
2155 OUString sAsterix("*");
2156 OJoinTableView::OTableWindowMap::iterator aIter = _pTabList->begin();
2157 OJoinTableView::OTableWindowMap::iterator aEnd = _pTabList->end();
2158 for(;aIter != aEnd && eOk == eErrorCode ;++aIter)
2160 OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(aIter->second);
2161 OTableFieldDescRef aInfo = new OTableFieldDesc();
2162 if (pTabWin->ExistsField( sAsterix, aInfo ))
2164 eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField);
2165 bFirstField = sal_False;
2168 return eErrorCode;
2170 //------------------------------------------------------------------------------
2171 SqlParseError InstallFields(OQueryDesignView* _pView,
2172 const ::connectivity::OSQLParseNode* pNode,
2173 OJoinTableView::OTableWindowMap* pTabList )
2175 if( pNode==0 || !SQL_ISRULE(pNode,select_statement))
2176 return eNoSelectStatement;
2178 ::connectivity::OSQLParseNode* pParseTree = pNode->getChild(2); // selection
2179 sal_Bool bFirstField = sal_True; // When initializing, the first field must be reactivated
2181 SqlParseError eErrorCode = eOk;
2183 if ( pParseTree->isRule() && SQL_ISPUNCTUATION(pParseTree->getChild(0),"*") )
2185 // SELECT * ...
2186 eErrorCode = fillSelectSubList(_pView,pTabList);
2188 else if (SQL_ISRULE(pParseTree,scalar_exp_commalist) )
2190 // SELECT column, ...
2191 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
2192 Reference< XConnection> xConnection = rController.getConnection();
2194 OUString aColumnName,aTableRange;
2195 for (sal_uInt32 i = 0; i < pParseTree->count() && eOk == eErrorCode ; ++i)
2197 ::connectivity::OSQLParseNode * pColumnRef = pParseTree->getChild(i);
2199 do {
2201 if ( SQL_ISRULE(pColumnRef,select_sublist) )
2203 eErrorCode = fillSelectSubList(_pView,pTabList);
2204 break;
2207 if ( SQL_ISRULE(pColumnRef,derived_column) )
2209 OUString aColumnAlias(rController.getParseIterator().getColumnAlias(pColumnRef)); // might be empty
2210 pColumnRef = pColumnRef->getChild(0);
2211 OTableFieldDescRef aInfo = new OTableFieldDesc();
2213 if ( pColumnRef->getKnownRuleID() != OSQLParseNode::subquery &&
2214 pColumnRef->count() == 3 &&
2215 SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") &&
2216 SQL_ISPUNCTUATION(pColumnRef->getChild(2),")")
2218 pColumnRef = pColumnRef->getChild(1);
2220 if (SQL_ISRULE(pColumnRef,column_ref))
2222 InsertColumnRef(_pView,pColumnRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList);
2223 eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField);
2224 bFirstField = sal_False;
2226 else if(SQL_ISRULEOR3(pColumnRef, general_set_fct, set_fct_spec, position_exp) ||
2227 SQL_ISRULEOR3(pColumnRef, extract_exp, fold, char_substring_fct) ||
2228 SQL_ISRULEOR2(pColumnRef,length_exp,char_value_fct))
2230 OUString aColumns;
2231 pColumnRef->parseNodeToPredicateStr(aColumns,
2232 xConnection,
2233 rController.getNumberFormatter(),
2234 _pView->getLocale(),
2235 static_cast<sal_Char>(_pView->getDecimalSeparator().toChar()),
2236 &rController.getParser().getContext());
2238 sal_Int32 nFunctionType = FKT_NONE;
2239 ::connectivity::OSQLParseNode* pParamRef = NULL;
2240 sal_Int32 nColumnRefPos = pColumnRef->count() - 2;
2241 if ( nColumnRefPos >= 0 && static_cast<sal_uInt32>(nColumnRefPos) < pColumnRef->count() )
2242 pParamRef = pColumnRef->getChild(nColumnRefPos);
2244 if ( SQL_ISRULE(pColumnRef,general_set_fct)
2245 && SQL_ISRULE(pParamRef,column_ref) )
2247 // Check the parameters for Column references
2248 InsertColumnRef(_pView,pParamRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList);
2250 else if ( SQL_ISRULE(pColumnRef,general_set_fct) )
2252 if ( pParamRef && pParamRef->getTokenValue().toChar() == '*' )
2254 OJoinTableView::OTableWindowMap::iterator aIter = pTabList->begin();
2255 const OJoinTableView::OTableWindowMap::const_iterator aEnd = pTabList->end();
2256 for(;aIter != aEnd;++aIter)
2258 OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(aIter->second);
2259 if (pTabWin->ExistsField( OUString("*"), aInfo ))
2261 aInfo->SetAlias(String());
2262 aInfo->SetTable(String());
2263 break;
2267 else
2269 OUString sFieldName = aColumns;
2270 if ( pParamRef )
2271 { // we got an aggregate function but without column name inside
2272 // so we set the whole argument of the function as field name
2273 nFunctionType |= FKT_NUMERIC;
2274 sFieldName = OUString();
2275 pParamRef->parseNodeToStr( sFieldName,
2276 xConnection,
2277 &rController.getParser().getContext(),
2278 sal_True,
2279 sal_True); // quote is to true because we need quoted elements inside the function
2281 aInfo->SetDataType(DataType::DOUBLE);
2282 aInfo->SetFieldType(TAB_NORMAL_FIELD);
2283 aInfo->SetField(sFieldName);
2285 aInfo->SetTabWindow(NULL);
2286 aInfo->SetFieldAlias(aColumnAlias);
2288 else
2290 _pView->fillFunctionInfo(pColumnRef,aColumns,aInfo);
2291 aInfo->SetFieldAlias(aColumnAlias);
2294 if ( SQL_ISRULE(pColumnRef,general_set_fct) )
2296 aInfo->SetFunctionType(nFunctionType|FKT_AGGREGATE);
2297 String aCol(aColumns);
2298 aInfo->SetFunction(comphelper::string::stripEnd(aCol.GetToken(0,'('), ' '));
2300 else
2301 aInfo->SetFunctionType(nFunctionType|FKT_OTHER);
2303 eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField);
2304 bFirstField = sal_False;
2306 else
2308 OUString aColumns;
2309 pColumnRef->parseNodeToStr( aColumns,
2310 xConnection,
2311 &rController.getParser().getContext(),
2312 sal_True,
2313 sal_True); // quote is to true because we need quoted elements inside the function
2315 aInfo->SetTabWindow( NULL );
2317 // since we support queries in queries, the thingie might belong to an existing "table"
2318 OQueryTableWindow* pExistingTable = lcl_findColumnInTables( aColumns, *pTabList, aInfo );
2319 if ( pExistingTable )
2321 aInfo->SetTabWindow( pExistingTable );
2322 aInfo->SetTable( pExistingTable->GetTableName() );
2323 aInfo->SetAlias( pExistingTable->GetAliasName() );
2326 aInfo->SetDataType(DataType::DOUBLE);
2327 aInfo->SetFieldType(TAB_NORMAL_FIELD);
2328 aInfo->SetField(aColumns);
2329 aInfo->SetFieldAlias(aColumnAlias);
2330 aInfo->SetFunctionType(FKT_NUMERIC | FKT_OTHER);
2332 eErrorCode = _pView->InsertField(aInfo, sal_True, bFirstField);
2333 bFirstField = sal_False;
2336 break;
2339 OSL_FAIL( "InstallFields: don't know how to interpret this parse node!" );
2341 } while ( false );
2344 else
2345 eErrorCode = eStatementTooComplex;
2347 return eErrorCode;
2349 //------------------------------------------------------------------------------
2350 SqlParseError GetOrderCriteria( OQueryDesignView* _pView,
2351 OSelectionBrowseBox* _pSelectionBrw,
2352 const ::connectivity::OSQLParseNode* pParseRoot )
2354 SqlParseError eErrorCode = eOk;
2355 if (!pParseRoot->getChild(3)->getChild(ORDER_BY_CHILD_POS)->isLeaf())
2357 ::connectivity::OSQLParseNode* pNode = pParseRoot->getChild(3)->getChild(ORDER_BY_CHILD_POS)->getChild(2);
2358 ::connectivity::OSQLParseNode* pParamRef = NULL;
2360 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
2361 EOrderDir eOrderDir;
2362 for( sal_uInt32 i=0 ; i<pNode->count() ; i++ )
2364 OTableFieldDescRef aDragLeft = new OTableFieldDesc();
2365 eOrderDir = ORDER_ASC;
2366 ::connectivity::OSQLParseNode* pChild = pNode->getChild( i );
2368 if (SQL_ISTOKEN( pChild->getChild(1), DESC ) )
2369 eOrderDir = ORDER_DESC;
2371 ::connectivity::OSQLParseNode* pArgument = pChild->getChild(0);
2373 if(SQL_ISRULE(pArgument,column_ref))
2375 if( eOk == FillDragInfo(_pView,pArgument,aDragLeft))
2376 _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i);
2377 else // it could be a alias name for a field
2379 OUString aTableRange,aColumnName;
2380 ::connectivity::OSQLParseTreeIterator& rParseIter = rController.getParseIterator();
2381 rParseIter.getColumnRange( pArgument, aColumnName, aTableRange );
2383 OTableFields& aList = rController.getTableFieldDesc();
2384 OTableFields::iterator aIter = aList.begin();
2385 OTableFields::iterator aEnd = aList.end();
2386 for(;aIter != aEnd;++aIter)
2388 OTableFieldDescRef pEntry = *aIter;
2389 if(pEntry.is() && pEntry->GetFieldAlias() == aColumnName)
2390 pEntry->SetOrderDir( eOrderDir );
2394 else if(SQL_ISRULE(pArgument, general_set_fct ) &&
2395 SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref) &&
2396 eOk == FillDragInfo(_pView,pParamRef,aDragLeft))
2397 _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i );
2398 else if( SQL_ISRULE(pArgument, set_fct_spec ) )
2401 Reference< XConnection> xConnection = rController.getConnection();
2402 if(xConnection.is())
2404 OUString sCondition;
2405 pArgument->parseNodeToPredicateStr(sCondition,
2406 xConnection,
2407 rController.getNumberFormatter(),
2408 _pView->getLocale(),
2409 static_cast<sal_Char>(_pView->getDecimalSeparator().toChar()),
2410 &rController.getParser().getContext());
2411 _pView->fillFunctionInfo(pArgument,sCondition,aDragLeft);
2412 aDragLeft->SetFunctionType(FKT_OTHER);
2413 aDragLeft->SetOrderDir(eOrderDir);
2414 aDragLeft->SetVisible(sal_False);
2415 _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i );
2417 else
2418 eErrorCode = eColumnNotFound;
2420 else
2421 eErrorCode = eColumnNotFound;
2424 return eErrorCode;
2426 //------------------------------------------------------------------------------
2427 SqlParseError GetHavingCriteria( OQueryDesignView* _pView,
2428 OSelectionBrowseBox* _pSelectionBrw,
2429 const ::connectivity::OSQLParseNode* pSelectRoot,
2430 sal_uInt16& rLevel )
2432 SqlParseError eErrorCode = eOk;
2433 if (!pSelectRoot->getChild(3)->getChild(3)->isLeaf())
2434 eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSelectRoot->getChild(3)->getChild(3)->getChild(1),rLevel, sal_True);
2435 return eErrorCode;
2437 //------------------------------------------------------------------------------
2438 SqlParseError GetGroupCriteria( OQueryDesignView* _pView,
2439 OSelectionBrowseBox* _pSelectionBrw,
2440 const ::connectivity::OSQLParseNode* pSelectRoot )
2442 SqlParseError eErrorCode = eOk;
2443 if (!pSelectRoot->getChild(3)->getChild(2)->isLeaf()) // opt_group_by_clause
2445 OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
2446 ::connectivity::OSQLParseNode* pGroupBy = pSelectRoot->getChild(3)->getChild(2)->getChild(2);
2448 for( sal_uInt32 i=0 ; i < pGroupBy->count() && eOk == eErrorCode; ++i )
2450 OTableFieldDescRef aDragInfo = new OTableFieldDesc();
2451 ::connectivity::OSQLParseNode* pParamRef = NULL;
2452 ::connectivity::OSQLParseNode* pArgument = pGroupBy->getChild( i );
2453 if(SQL_ISRULE(pArgument,column_ref))
2455 if ( eOk == (eErrorCode = FillDragInfo(_pView,pArgument,aDragInfo)) )
2457 aDragInfo->SetGroupBy(sal_True);
2458 _pSelectionBrw->AddGroupBy(aDragInfo,i);
2461 else if(SQL_ISRULE(pArgument, general_set_fct ) &&
2462 SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref) &&
2463 eOk == FillDragInfo(_pView,pParamRef,aDragInfo))
2465 aDragInfo->SetGroupBy(sal_True);
2466 _pSelectionBrw->AddGroupBy( aDragInfo, i );
2468 else if( SQL_ISRULE(pArgument, set_fct_spec ) )
2470 Reference< XConnection> xConnection = rController.getConnection();
2471 if(xConnection.is())
2473 OUString sGroupByExpression;
2474 pArgument->parseNodeToStr( sGroupByExpression,
2475 xConnection,
2476 &rController.getParser().getContext(),
2477 sal_True,
2478 sal_True); // quote is to true because we need quoted elements inside the function
2479 _pView->fillFunctionInfo(pArgument,sGroupByExpression,aDragInfo);
2480 aDragInfo->SetFunctionType(FKT_OTHER);
2481 aDragInfo->SetGroupBy(sal_True);
2482 aDragInfo->SetVisible(sal_False);
2483 _pSelectionBrw->AddGroupBy( aDragInfo, i );
2485 else
2486 eErrorCode = eColumnNotFound;
2490 return eErrorCode;
2493 //------------------------------------------------------------------------------
2494 String getParseErrorMessage( SqlParseError _eErrorCode )
2496 sal_uInt16 nResId;
2497 switch(_eErrorCode)
2499 case eIllegalJoin:
2500 nResId = STR_QRY_ILLEGAL_JOIN;
2501 break;
2502 case eStatementTooLong:
2503 nResId = STR_QRY_TOO_LONG_STATEMENT;
2504 break;
2505 case eNoConnection:
2506 nResId = STR_QRY_SYNTAX;
2507 break;
2508 case eNoSelectStatement:
2509 nResId = STR_QRY_NOSELECT;
2510 break;
2511 case eColumnInLikeNotFound:
2512 nResId = STR_QRY_SYNTAX;
2513 break;
2514 case eNoColumnInLike:
2515 nResId = STR_QRY_SYNTAX;
2516 break;
2517 case eColumnNotFound:
2518 nResId = STR_QRY_SYNTAX;
2519 break;
2520 case eNativeMode:
2521 nResId = STR_QRY_NATIVE;
2522 break;
2523 case eTooManyTables:
2524 nResId = STR_QRY_TOO_MANY_TABLES;
2525 break;
2526 case eTooManyConditions:
2527 nResId = STR_QRY_TOOMANYCOND;
2528 break;
2529 case eTooManyColumns:
2530 nResId = STR_QRY_TOO_MANY_COLUMNS;
2531 break;
2532 case eStatementTooComplex:
2533 nResId = STR_QRY_TOOCOMPLEX;
2534 break;
2535 default:
2536 nResId = STR_QRY_SYNTAX;
2537 break;
2540 return String( ModuleRes( nResId ) );
2543 //------------------------------------------------------------------------------
2544 //------------------------------------------------------------------------------
2546 // end of anonymouse namespace
2547 DBG_NAME(OQueryDesignView)
2549 OQueryDesignView::OQueryDesignView( OQueryContainerWindow* _pParent,
2550 OQueryController& _rController,
2551 const Reference< XComponentContext >& _rxContext)
2552 :OQueryView( _pParent, _rController, _rxContext )
2553 ,m_aSplitter( this )
2554 ,m_eChildFocus(NONE)
2555 ,m_bInSplitHandler( sal_False )
2557 DBG_CTOR(OQueryDesignView,NULL);
2561 SvtSysLocale aSysLocale;
2562 m_aLocale = aSysLocale.GetLanguageTag().getLocale();
2563 m_sDecimalSep = aSysLocale.GetLocaleData().getNumDecimalSep();
2565 catch(Exception&)
2569 m_pSelectionBox = new OSelectionBrowseBox(this);
2571 setNoneVisbleRow(static_cast<OQueryController&>(getController()).getVisibleRows());
2572 m_pSelectionBox->Show();
2573 // setup Splitter
2574 m_aSplitter.SetSplitHdl(LINK(this, OQueryDesignView,SplitHdl));
2575 m_aSplitter.Show();
2578 // -----------------------------------------------------------------------------
2579 OQueryDesignView::~OQueryDesignView()
2581 if ( m_pTableView )
2582 ::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::RemoveWindow));
2583 SAL_WNODEPRECATED_DECLARATIONS_PUSH
2584 ::std::auto_ptr<Window> aTemp(m_pSelectionBox);
2585 SAL_WNODEPRECATED_DECLARATIONS_POP
2586 m_pSelectionBox = NULL;
2588 DBG_DTOR(OQueryDesignView,NULL);
2590 //------------------------------------------------------------------------------
2591 IMPL_LINK( OQueryDesignView, SplitHdl, void*, /*p*/ )
2593 if (!getController().isReadOnly())
2595 m_bInSplitHandler = sal_True;
2596 m_aSplitter.SetPosPixel( Point( m_aSplitter.GetPosPixel().X(),m_aSplitter.GetSplitPosPixel() ) );
2597 static_cast<OQueryController&>(getController()).setSplitPos(m_aSplitter.GetSplitPosPixel());
2598 static_cast<OQueryController&>(getController()).setModified( sal_True );
2599 Resize();
2600 m_bInSplitHandler = sal_True;
2602 return 0L;
2604 // -------------------------------------------------------------------------
2605 void OQueryDesignView::Construct()
2607 m_pTableView = new OQueryTableView(m_pScrollWindow,this);
2608 ::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::AddWindow));
2609 OQueryView::Construct();
2611 // -----------------------------------------------------------------------------
2612 void OQueryDesignView::initialize()
2614 if(static_cast<OQueryController&>(getController()).getSplitPos() != -1)
2616 m_aSplitter.SetPosPixel( Point( m_aSplitter.GetPosPixel().X(),static_cast<OQueryController&>(getController()).getSplitPos() ) );
2617 m_aSplitter.SetSplitPosPixel(static_cast<OQueryController&>(getController()).getSplitPos());
2619 m_pSelectionBox->initialize();
2620 reset();
2622 // -------------------------------------------------------------------------
2623 void OQueryDesignView::resizeDocumentView(Rectangle& _rPlayground)
2625 Point aPlaygroundPos( _rPlayground.TopLeft() );
2626 Size aPlaygroundSize( _rPlayground.GetSize() );
2628 // calc the split pos, and forward it to the controller
2629 sal_Int32 nSplitPos = static_cast<OQueryController&>(getController()).getSplitPos();
2630 if ( 0 != aPlaygroundSize.Height() )
2632 if ( ( -1 == nSplitPos )
2633 || ( nSplitPos >= aPlaygroundSize.Height() )
2636 // let the selection browse box determine an optimal size
2637 Size aSelectionBoxSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize );
2638 nSplitPos = aPlaygroundSize.Height() - aSelectionBoxSize.Height() - m_aSplitter.GetSizePixel().Height();
2639 // still an invalid size?
2640 if ( nSplitPos == -1 || nSplitPos >= aPlaygroundSize.Height() )
2641 nSplitPos = sal_Int32(aPlaygroundSize.Height()*0.6);
2643 static_cast<OQueryController&>(getController()).setSplitPos(nSplitPos);
2646 if ( !m_bInSplitHandler )
2647 { // the resize is triggered by something else than the split handler
2648 // our main focus is to try to preserve the size of the selectionbrowse box
2649 Size aSelBoxSize = m_pSelectionBox->GetSizePixel();
2650 if ( aSelBoxSize.Height() )
2652 // keep the size of the sel box constant
2653 nSplitPos = aPlaygroundSize.Height() - m_aSplitter.GetSizePixel().Height() - aSelBoxSize.Height();
2655 // and if the box is smaller than the optimal size, try to do something about it
2656 Size aSelBoxOptSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize );
2657 if ( aSelBoxOptSize.Height() > aSelBoxSize.Height() )
2659 nSplitPos = aPlaygroundSize.Height() - m_aSplitter.GetSizePixel().Height() - aSelBoxOptSize.Height();
2662 static_cast< OQueryController& >(getController()).setSplitPos( nSplitPos );
2667 // normalize the split pos
2668 Point aSplitPos = Point( _rPlayground.Left(), nSplitPos );
2669 Size aSplitSize = Size( _rPlayground.GetSize().Width(), m_aSplitter.GetSizePixel().Height() );
2671 if( ( aSplitPos.Y() + aSplitSize.Height() ) > ( aPlaygroundSize.Height() ))
2672 aSplitPos.Y() = aPlaygroundSize.Height() - aSplitSize.Height();
2674 if( aSplitPos.Y() <= aPlaygroundPos.Y() )
2675 aSplitPos.Y() = aPlaygroundPos.Y() + sal_Int32(aPlaygroundSize.Height() * 0.2);
2677 // position the table
2678 Size aTableViewSize(aPlaygroundSize.Width(), aSplitPos.Y() - aPlaygroundPos.Y());
2679 m_pScrollWindow->SetPosSizePixel(aPlaygroundPos, aTableViewSize);
2681 // position the selection browse box
2682 Point aPos( aPlaygroundPos.X(), aSplitPos.Y() + aSplitSize.Height() );
2683 m_pSelectionBox->SetPosSizePixel( aPos, Size( aPlaygroundSize.Width(), aPlaygroundSize.Height() - aSplitSize.Height() - aTableViewSize.Height() ));
2685 // set the size of the splitter
2686 m_aSplitter.SetPosSizePixel( aSplitPos, aSplitSize );
2687 m_aSplitter.SetDragRectPixel( _rPlayground );
2689 // just for completeness: there is no space left, we occupied it all ...
2690 _rPlayground.SetPos( _rPlayground.BottomRight() );
2691 _rPlayground.SetSize( Size( 0, 0 ) );
2693 // -----------------------------------------------------------------------------
2694 void OQueryDesignView::setReadOnly(sal_Bool _bReadOnly)
2696 m_pSelectionBox->SetReadOnly(_bReadOnly);
2698 // -----------------------------------------------------------------------------
2699 void OQueryDesignView::clear()
2701 m_pSelectionBox->ClearAll(); // clear the whole selection
2702 m_pTableView->ClearAll();
2704 // -----------------------------------------------------------------------------
2705 void OQueryDesignView::setStatement(const OUString& /*_rsStatement*/)
2708 // -----------------------------------------------------------------------------
2709 void OQueryDesignView::copy()
2711 if( m_eChildFocus == SELECTION)
2712 m_pSelectionBox->copy();
2714 // -----------------------------------------------------------------------------
2715 sal_Bool OQueryDesignView::isCutAllowed()
2717 sal_Bool bAllowed = sal_False;
2718 if ( SELECTION == m_eChildFocus )
2719 bAllowed = m_pSelectionBox->isCutAllowed();
2720 return bAllowed;
2722 // -----------------------------------------------------------------------------
2723 sal_Bool OQueryDesignView::isPasteAllowed()
2725 sal_Bool bAllowed = sal_False;
2726 if ( SELECTION == m_eChildFocus )
2727 bAllowed = m_pSelectionBox->isPasteAllowed();
2728 return bAllowed;
2730 // -----------------------------------------------------------------------------
2731 sal_Bool OQueryDesignView::isCopyAllowed()
2733 sal_Bool bAllowed = sal_False;
2734 if ( SELECTION == m_eChildFocus )
2735 bAllowed = m_pSelectionBox->isCopyAllowed();
2736 return bAllowed;
2738 // -----------------------------------------------------------------------------
2739 void OQueryDesignView::stopTimer()
2741 m_pSelectionBox->stopTimer();
2743 // -----------------------------------------------------------------------------
2744 void OQueryDesignView::startTimer()
2746 m_pSelectionBox->startTimer();
2748 // -----------------------------------------------------------------------------
2749 void OQueryDesignView::cut()
2751 if( m_eChildFocus == SELECTION)
2753 m_pSelectionBox->cut();
2754 static_cast<OQueryController&>(getController()).setModified(sal_True);
2757 // -----------------------------------------------------------------------------
2758 void OQueryDesignView::paste()
2760 if( m_eChildFocus == SELECTION)
2762 m_pSelectionBox->paste();
2763 static_cast<OQueryController&>(getController()).setModified(sal_True);
2766 // -----------------------------------------------------------------------------
2767 void OQueryDesignView::TableDeleted(const OUString& rAliasName)
2769 // message that the table was removed from the window
2770 DeleteFields(rAliasName);
2771 static_cast<OQueryController&>(getController()).InvalidateFeature(ID_BROWSER_ADDTABLE); // inform the view again
2773 //------------------------------------------------------------------------------
2774 void OQueryDesignView::DeleteFields( const OUString& rAliasName )
2776 m_pSelectionBox->DeleteFields( rAliasName );
2778 // -----------------------------------------------------------------------------
2779 bool OQueryDesignView::HasFieldByAliasName(const OUString& rFieldName, OTableFieldDescRef& rInfo) const
2781 return m_pSelectionBox->HasFieldByAliasName( rFieldName, rInfo);
2783 // -----------------------------------------------------------------------------
2784 SqlParseError OQueryDesignView::InsertField( const OTableFieldDescRef& rInfo, sal_Bool bVis, sal_Bool bActivate)
2786 return m_pSelectionBox->InsertField( rInfo, BROWSER_INVALIDID,bVis, bActivate ).is() ? eOk : eTooManyColumns;
2788 // -----------------------------------------------------------------------------
2789 sal_Int32 OQueryDesignView::getColWidth(sal_uInt16 _nColPos) const
2791 static sal_Int32 s_nDefaultWidth = GetTextWidth(String(RTL_CONSTASCII_USTRINGPARAM("0"))) * 15;
2792 sal_Int32 nWidth = static_cast<OQueryController&>(getController()).getColWidth(_nColPos);
2793 if ( !nWidth )
2794 nWidth = s_nDefaultWidth;
2795 return nWidth;
2797 //------------------------------------------------------------------------------
2798 void OQueryDesignView::fillValidFields(const OUString& sAliasName, ComboBox* pFieldList)
2800 OSL_ENSURE(pFieldList != NULL, "OQueryDesignView::FillValidFields : What the hell do you think I can do with a NULL-ptr ? This will crash !");
2801 pFieldList->Clear();
2803 sal_Bool bAllTables = sAliasName.isEmpty();
2805 OJoinTableView::OTableWindowMap* pTabWins = m_pTableView->GetTabWinMap();
2806 OUString strCurrentPrefix;
2807 ::std::vector< OUString> aFields;
2808 OJoinTableView::OTableWindowMap::iterator aIter = pTabWins->begin();
2809 OJoinTableView::OTableWindowMap::iterator aEnd = pTabWins->end();
2810 for(;aIter != aEnd;++aIter)
2812 OQueryTableWindow* pCurrentWin = static_cast<OQueryTableWindow*>(aIter->second);
2813 if (bAllTables || (pCurrentWin->GetAliasName() == sAliasName))
2815 strCurrentPrefix = pCurrentWin->GetAliasName();
2816 strCurrentPrefix += OUString('.');
2818 pCurrentWin->EnumValidFields(aFields);
2820 ::std::vector< OUString>::iterator aStrIter = aFields.begin();
2821 ::std::vector< OUString>::iterator aStrEnd = aFields.end();
2822 for(;aStrIter != aStrEnd;++aStrIter)
2824 if (bAllTables || aStrIter->toChar() == '*')
2825 pFieldList->InsertEntry(OUString(strCurrentPrefix) += *aStrIter);
2826 else
2827 pFieldList->InsertEntry(*aStrIter);
2830 if (!bAllTables)
2831 // this means that I came into this block because the table name was exactly what I was looking for so I can end here
2832 // (and I prevent that fields get added more than once, if a table is repeated in TabWin)
2833 break;
2837 // -----------------------------------------------------------------------------
2838 long OQueryDesignView::PreNotify(NotifyEvent& rNEvt)
2840 switch (rNEvt.GetType())
2842 case EVENT_GETFOCUS:
2843 #if OSL_DEBUG_LEVEL > 0
2845 Window* pFocus = Application::GetFocusWindow();
2846 (void)pFocus;
2848 #endif
2850 if ( m_pSelectionBox && m_pSelectionBox->HasChildPathFocus() )
2851 m_eChildFocus = SELECTION;
2852 else
2853 m_eChildFocus = TABLEVIEW;
2854 break;
2857 return OQueryView::PreNotify(rNEvt);
2859 //------------------------------------------------------------------------------
2862 // -----------------------------------------------------------------------------
2863 // check if the statement is correct when not returning false
2864 sal_Bool OQueryDesignView::checkStatement()
2866 sal_Bool bRet = sal_True;
2867 if ( m_pSelectionBox )
2868 bRet = m_pSelectionBox->Save(); // an error occurred so we return no
2869 return bRet;
2871 //-------------------------------------------------------------------------------
2872 OUString OQueryDesignView::getStatement()
2874 OQueryController& rController = static_cast<OQueryController&>(getController());
2875 m_rController.clearError();
2876 // used for fields which aren't any longer in the statement
2877 OTableFields& rUnUsedFields = rController.getUnUsedFields();
2878 OTableFields().swap( rUnUsedFields );
2880 // create the select columns
2881 sal_uInt32 nFieldcount = 0;
2882 OTableFields& rFieldList = rController.getTableFieldDesc();
2883 OTableFields::iterator aIter = rFieldList.begin();
2884 OTableFields::iterator aEnd = rFieldList.end();
2885 for(;aIter != aEnd;++aIter)
2887 OTableFieldDescRef pEntryField = *aIter;
2888 if (!pEntryField->GetField().isEmpty() && pEntryField->IsVisible() )
2889 ++nFieldcount;
2890 else if (!pEntryField->GetField().isEmpty() &&
2891 !pEntryField->HasCriteria() &&
2892 pEntryField->isNoneFunction() &&
2893 pEntryField->GetOrderDir() == ORDER_NONE &&
2894 !pEntryField->IsGroupBy() &&
2895 pEntryField->GetFunction().isEmpty() )
2896 rUnUsedFields.push_back(pEntryField);
2898 if ( !nFieldcount ) // no visible fields so return
2900 rUnUsedFields = rFieldList;
2901 return OUString();
2904 OQueryTableView::OTableWindowMap* pTabList = m_pTableView->GetTabWinMap();
2905 sal_uInt32 nTabcount = pTabList->size();
2907 OUString aFieldListStr(GenerateSelectList(this,rFieldList,nTabcount>1));
2908 if( aFieldListStr.isEmpty() )
2909 return OUString();
2911 // Exceptionhandling, if no fields have been passed we should not
2912 // change the tab page
2913 // TabBarSelectHdl will query the SQL-OUString for STATEMENT_NOFIELDS
2914 // and trigger a error message
2915 // ----------------- Build table list ----------------------
2917 const ::std::vector<OTableConnection*>* pConnList = m_pTableView->getTableConnections();
2918 Reference< XConnection> xConnection = rController.getConnection();
2919 OUString aTableListStr(GenerateFromClause(xConnection,pTabList,pConnList));
2920 OSL_ENSURE(!aTableListStr.isEmpty(), "OQueryDesignView::getStatement() : unexpected : have Fields, but no Tables !");
2921 // if fields exist now, these only can be created by inserting from an already existing table; if on the other hand
2922 // a table is deleted, also the belonging fields will be deleted -> therefore it CANNOT occur that fields
2923 // exist but no tables exist (and aFieldListStr has its length, I secure this above)
2924 OUStringBuffer aHavingStr,aCriteriaListStr;
2925 // ----------------- Kriterien aufbauen ----------------------
2926 if (!GenerateCriterias(this,aCriteriaListStr,aHavingStr,rFieldList, nTabcount > 1))
2927 return OUString();
2929 OUString aJoinCrit;
2930 GenerateInnerJoinCriterias(xConnection,aJoinCrit,pConnList);
2931 if(!aJoinCrit.isEmpty())
2933 OUString aTmp("( ");
2934 aTmp += aJoinCrit;
2935 aTmp += OUString(" )");
2936 if(aCriteriaListStr.getLength())
2938 aTmp += C_AND;
2939 aTmp += aCriteriaListStr.makeStringAndClear();
2941 aCriteriaListStr = aTmp;
2943 // ----------------- construct statement ----------------------
2944 OUStringBuffer aSqlCmd(OUString("SELECT "));
2945 if(rController.isDistinct())
2946 aSqlCmd.append(OUString(" DISTINCT "));
2947 aSqlCmd.append(aFieldListStr);
2948 aSqlCmd.append(OUString(" FROM "));
2949 aSqlCmd.append(aTableListStr);
2951 if (aCriteriaListStr.getLength())
2953 aSqlCmd.append(OUString(" WHERE "));
2954 aSqlCmd.append(aCriteriaListStr.makeStringAndClear());
2956 // ----------------- construct GroupBy and attachen ------------
2957 Reference<XDatabaseMetaData> xMeta;
2958 if ( xConnection.is() )
2959 xMeta = xConnection->getMetaData();
2960 sal_Bool bUseAlias = nTabcount > 1;
2961 if ( xMeta.is() )
2962 bUseAlias = bUseAlias || !xMeta->supportsGroupByUnrelated();
2964 aSqlCmd.append(GenerateGroupBy(this,rFieldList,bUseAlias));
2965 // ----------------- attache having ------------
2966 if(aHavingStr.getLength())
2968 aSqlCmd.append(OUString(" HAVING "));
2969 aSqlCmd.append(aHavingStr.makeStringAndClear());
2971 // ----------------- construct sorting and attach ------------
2972 OUString sOrder;
2973 SqlParseError eErrorCode = eOk;
2974 if ( (eErrorCode = GenerateOrder(this,rFieldList,nTabcount > 1,sOrder)) == eOk)
2975 aSqlCmd.append(sOrder);
2976 else
2978 if ( !m_rController.hasError() )
2979 m_rController.appendError( getParseErrorMessage( eErrorCode ) );
2981 m_rController.displayError();
2983 // --------------------- Limit Clause -------------------
2985 const sal_Int64 nLimit = rController.getLimit();
2986 if( nLimit != -1 )
2988 aSqlCmd.append( " LIMIT " + OUString::number(nLimit) );
2992 OUString sSQL = aSqlCmd.makeStringAndClear();
2993 if ( xConnection.is() )
2995 ::connectivity::OSQLParser& rParser( rController.getParser() );
2996 OUString sErrorMessage;
2997 SAL_WNODEPRECATED_DECLARATIONS_PUSH
2998 ::std::auto_ptr<OSQLParseNode> pParseNode( rParser.parseTree( sErrorMessage, sSQL, sal_True ) );
2999 SAL_WNODEPRECATED_DECLARATIONS_POP
3000 if ( pParseNode.get() )
3002 OSQLParseNode* pNode = pParseNode->getChild(3)->getChild(1);
3003 if ( pNode->count() > 1 )
3005 ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1);
3006 if ( pCondition ) // no where clause
3008 OSQLParseNode::compress(pCondition);
3009 OUString sTemp;
3010 pParseNode->parseNodeToStr(sTemp,xConnection);
3011 sSQL = sTemp;
3016 return sSQL;
3018 // -----------------------------------------------------------------------------
3019 // -----------------------------------------------------------------------------
3020 void OQueryDesignView::setSlotEnabled(sal_Int32 _nSlotId,sal_Bool _bEnable)
3022 sal_uInt16 nRow;
3023 switch (_nSlotId)
3025 case SID_QUERY_VIEW_FUNCTIONS:
3026 nRow = BROW_FUNCTION_ROW;
3027 break;
3028 case SID_QUERY_VIEW_TABLES:
3029 nRow = BROW_TABLE_ROW;
3030 break;
3031 case SID_QUERY_VIEW_ALIASES:
3032 nRow = BROW_COLUMNALIAS_ROW;
3033 break;
3034 default:
3035 // ????????????
3036 nRow = 0;
3037 break;
3039 m_pSelectionBox->SetRowVisible(nRow,_bEnable);
3040 m_pSelectionBox->Invalidate();
3042 // -----------------------------------------------------------------------------
3043 sal_Bool OQueryDesignView::isSlotEnabled(sal_Int32 _nSlotId)
3045 sal_uInt16 nRow;
3046 switch (_nSlotId)
3048 case SID_QUERY_VIEW_FUNCTIONS:
3049 nRow = BROW_FUNCTION_ROW;
3050 break;
3051 case SID_QUERY_VIEW_TABLES:
3052 nRow = BROW_TABLE_ROW;
3053 break;
3054 case SID_QUERY_VIEW_ALIASES:
3055 nRow = BROW_COLUMNALIAS_ROW;
3056 break;
3057 default:
3058 // ?????????
3059 nRow = 0;
3060 break;
3062 return m_pSelectionBox->IsRowVisible(nRow);
3064 // -----------------------------------------------------------------------------
3065 void OQueryDesignView::SaveUIConfig()
3067 OQueryController& rCtrl = static_cast<OQueryController&>(getController());
3068 rCtrl.SaveTabWinsPosSize( m_pTableView->GetTabWinMap(), m_pScrollWindow->GetHScrollBar()->GetThumbPos(), m_pScrollWindow->GetVScrollBar()->GetThumbPos() );
3069 rCtrl.setVisibleRows( m_pSelectionBox->GetNoneVisibleRows() );
3070 if ( m_aSplitter.GetSplitPosPixel() != 0 )
3071 rCtrl.setSplitPos( m_aSplitter.GetSplitPosPixel() );
3073 // -----------------------------------------------------------------------------
3074 OSQLParseNode* OQueryDesignView::getPredicateTreeFromEntry(OTableFieldDescRef pEntry,
3075 const OUString& _sCriteria,
3076 OUString& _rsErrorMessage,
3077 Reference<XPropertySet>& _rxColumn) const
3079 OSL_ENSURE(pEntry.is(),"Entry is null!");
3080 if(!pEntry.is())
3081 return NULL;
3082 Reference< XConnection> xConnection = static_cast<OQueryController&>(getController()).getConnection();
3083 if(!xConnection.is())
3084 return NULL;
3086 ::connectivity::OSQLParser& rParser( static_cast<OQueryController&>(getController()).getParser() );
3087 OQueryTableWindow* pWin = static_cast<OQueryTableWindow*>(pEntry->GetTabWindow());
3089 // special handling for functions
3090 if ( pEntry->GetFunctionType() & (FKT_OTHER | FKT_AGGREGATE | FKT_NUMERIC) )
3092 // we have a function here so we have to distinguish the type of return value
3093 String sFunction;
3094 if ( pEntry->isNumericOrAggreateFunction() )
3095 sFunction = pEntry->GetFunction();
3097 if ( !sFunction.Len() )
3098 sFunction = pEntry->GetField();
3100 if (comphelper::string::getTokenCount(sFunction, '(') > 1)
3101 sFunction = sFunction.GetToken(0,'('); // this should be the name of the function
3103 sal_Int32 nType = ::connectivity::OSQLParser::getFunctionReturnType(sFunction,&rParser.getContext());
3104 if ( nType == DataType::OTHER || (!sFunction.Len() && pEntry->isNumericOrAggreateFunction()) )
3106 // first try the international version
3107 OUString sSql;
3108 sSql += "SELECT * ";
3109 sSql += " FROM x WHERE ";
3110 sSql += pEntry->GetField();
3111 sSql += _sCriteria;
3112 SAL_WNODEPRECATED_DECLARATIONS_PUSH
3113 ::std::auto_ptr<OSQLParseNode> pParseNode( rParser.parseTree( _rsErrorMessage, sSql, sal_True ) );
3114 SAL_WNODEPRECATED_DECLARATIONS_POP
3115 nType = DataType::DOUBLE;
3116 if ( pParseNode.get() )
3118 OSQLParseNode* pColumnRef = pParseNode->getByRule(OSQLParseNode::column_ref);
3119 if ( pColumnRef )
3121 OTableFieldDescRef aField = new OTableFieldDesc();
3122 if ( eOk == FillDragInfo(this,pColumnRef,aField) )
3124 nType = aField->GetDataType();
3130 Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
3131 parse::OParseColumn* pColumn = new parse::OParseColumn( pEntry->GetField(),
3132 OUString(),
3133 OUString(),
3134 OUString(),
3135 ColumnValue::NULLABLE_UNKNOWN,
3138 nType,
3139 sal_False,
3140 sal_False,
3141 xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),
3142 OUString(),
3143 OUString(),
3144 OUString());
3145 _rxColumn = pColumn;
3146 pColumn->setFunction(sal_True);
3147 pColumn->setRealName(pEntry->GetField());
3149 else
3151 if (pWin)
3153 Reference<XNameAccess> xColumns = pWin->GetOriginalColumns();
3154 if (xColumns.is() && xColumns->hasByName(pEntry->GetField()))
3155 xColumns->getByName(pEntry->GetField()) >>= _rxColumn;
3159 OUString sTest(_sCriteria);
3160 OSQLParseNode* pParseNode = rParser.predicateTree( _rsErrorMessage,
3161 sTest,
3162 static_cast<OQueryController&>(getController()).getNumberFormatter(),
3163 _rxColumn);
3164 return pParseNode;
3166 // -----------------------------------------------------------------------------
3167 void OQueryDesignView::GetFocus()
3169 OQueryView::GetFocus();
3170 if ( m_pSelectionBox && !m_pSelectionBox->HasChildPathFocus() )
3172 // first we have to deactivate the current cell to refill when necessary
3173 m_pSelectionBox->DeactivateCell();
3174 m_pSelectionBox->ActivateCell(m_pSelectionBox->GetCurRow(), m_pSelectionBox->GetCurColumnId());
3175 m_pSelectionBox->GrabFocus();
3178 // -----------------------------------------------------------------------------
3179 void OQueryDesignView::reset()
3181 m_pTableView->ClearAll();
3182 m_pTableView->ReSync();
3184 // -----------------------------------------------------------------------------
3185 void OQueryDesignView::setNoneVisbleRow(sal_Int32 _nRows)
3187 m_pSelectionBox->SetNoneVisbleRow(_nRows);
3190 // -----------------------------------------------------------------------------
3191 void OQueryDesignView::initByFieldDescriptions( const Sequence< PropertyValue >& i_rFieldDescriptions )
3193 OQueryController& rController = static_cast< OQueryController& >( getController() );
3195 m_pSelectionBox->PreFill();
3196 m_pSelectionBox->SetReadOnly( rController.isReadOnly() );
3197 m_pSelectionBox->Fill();
3199 for ( const PropertyValue* field = i_rFieldDescriptions.getConstArray();
3200 field != i_rFieldDescriptions.getConstArray() + i_rFieldDescriptions.getLength();
3201 ++field
3204 ::rtl::Reference< OTableFieldDesc > pField( new OTableFieldDesc() );
3205 pField->Load( *field, true );
3206 InsertField( pField, sal_True, sal_False );
3209 rController.ClearUndoManager();
3210 m_pSelectionBox->Invalidate();
3213 // -----------------------------------------------------------------------------
3214 bool OQueryDesignView::initByParseIterator( ::dbtools::SQLExceptionInfo* _pErrorInfo )
3216 SqlParseError eErrorCode = eNativeMode;
3217 m_rController.clearError();
3221 eErrorCode = InitFromParseNodeImpl( this, m_pSelectionBox );
3223 if ( eErrorCode != eOk )
3225 if ( !m_rController.hasError() )
3226 m_rController.appendError( getParseErrorMessage( eErrorCode ) );
3228 if ( _pErrorInfo )
3230 *_pErrorInfo = m_rController.getError();
3232 else
3234 m_rController.displayError();
3238 catch ( const Exception& )
3240 DBG_UNHANDLED_EXCEPTION();
3242 return eErrorCode == eOk;
3245 // Utility function for fillFunctionInfo
3246 namespace {
3247 sal_Int32 char_datatype(const::connectivity::OSQLParseNode* pDataType, const unsigned int offset) {
3248 int cnt = pDataType->count() - offset;
3249 if ( cnt < 0 )
3251 OSL_FAIL("internal error in decoding character datatype specification");
3252 return DataType::VARCHAR;
3254 else if ( cnt == 0 )
3256 if ( offset == 0 )
3258 // The datatype is the node itself
3259 if ( SQL_ISTOKENOR2 (pDataType, CHARACTER, CHAR) )
3260 return DataType::CHAR;
3261 else if ( SQL_ISTOKEN (pDataType, VARCHAR) )
3262 return DataType::VARCHAR;
3263 else if ( SQL_ISTOKEN (pDataType, CLOB) )
3264 return DataType::CLOB;
3265 else
3267 OSL_FAIL("unknown/unexpected token in decoding character datatype specification");
3268 return DataType::VARCHAR;
3271 else
3273 // No child left to read!
3274 OSL_FAIL("incomplete datatype in decoding character datatype specification");
3275 return DataType::VARCHAR;
3279 if ( SQL_ISTOKEN(pDataType->getChild(offset), NATIONAL) )
3280 return char_datatype(pDataType, offset+1);
3281 else if ( SQL_ISTOKENOR3(pDataType->getChild(offset), CHARACTER, CHAR, NCHAR) )
3283 if ( cnt > 2 && SQL_ISTOKEN(pDataType->getChild(offset+1), LARGE) && SQL_ISTOKEN(pDataType->getChild(offset+2), OBJECT) )
3284 return DataType::CLOB;
3285 else if ( cnt > 1 && SQL_ISTOKEN(pDataType->getChild(offset+1), VARYING) )
3286 return DataType::VARCHAR;
3287 else
3288 return DataType::CHAR;
3290 else if ( SQL_ISTOKEN (pDataType->getChild(offset), VARCHAR) )
3291 return DataType::VARCHAR;
3292 else if ( SQL_ISTOKENOR2 (pDataType->getChild(offset), CLOB, NCLOB) )
3293 return DataType::CLOB;
3295 OSL_FAIL("unrecognised character datatype");
3296 return DataType::VARCHAR;
3300 //------------------------------------------------------------------------------
3301 // Try to guess the type of an expression in simple cases.
3302 // Originally meant to be called only on a function call (hence the misnomer),
3303 // but now tries to do the best it can also in other cases.
3304 // Don't completely rely on fillFunctionInfo,
3305 // it won't look at the function's arguments to find the return type
3306 // (in particular, in the case of general_set_fct,
3307 // the return type is the type of the argument;
3308 // if that is (as is typical) a column reference,
3309 // it is the type of the column).
3310 // TODO: There is similar "guess the expression's type" code in several places:
3311 // SelectionBrowseBox.cxx: OSelectionBrowseBox::saveField
3312 // QueryDesignView.cxx: InstallFields, GetOrderCriteria, GetGroupCriteria
3313 // If possible, they should be factorised into this function
3314 // (which should then be renamed...)
3316 void OQueryDesignView::fillFunctionInfo( const ::connectivity::OSQLParseNode* pNode
3317 ,const OUString& sFunctionTerm
3318 ,OTableFieldDescRef& aInfo)
3320 // get the type of the expression, as far as easily possible
3321 OQueryController& rController = static_cast<OQueryController&>(getController());
3322 sal_Int32 nDataType = DataType::DOUBLE;
3323 switch(pNode->getNodeType())
3325 case SQL_NODE_CONCAT:
3326 case SQL_NODE_STRING:
3327 nDataType = DataType::VARCHAR;
3328 break;
3329 case SQL_NODE_INTNUM:
3330 nDataType = DataType::INTEGER;
3331 break;
3332 case SQL_NODE_APPROXNUM:
3333 nDataType = DataType::DOUBLE;
3334 break;
3335 case SQL_NODE_DATE:
3336 case SQL_NODE_ACCESS_DATE:
3337 nDataType = DataType::TIMESTAMP;
3338 break;
3339 case SQL_NODE_COMPARISON:
3340 case SQL_NODE_EQUAL:
3341 case SQL_NODE_LESS:
3342 case SQL_NODE_GREAT:
3343 case SQL_NODE_LESSEQ:
3344 case SQL_NODE_GREATEQ:
3345 case SQL_NODE_NOTEQUAL:
3346 nDataType = DataType::BOOLEAN;
3347 break;
3348 case SQL_NODE_NAME:
3349 case SQL_NODE_LISTRULE:
3350 case SQL_NODE_COMMALISTRULE:
3351 case SQL_NODE_KEYWORD:
3352 case SQL_NODE_AMMSC: //??
3353 case SQL_NODE_PUNCTUATION:
3354 OSL_FAIL("Unexpected SQL Node Type");
3355 break;
3356 case SQL_NODE_RULE:
3357 switch(pNode->getKnownRuleID())
3359 case OSQLParseNode::select_statement:
3360 case OSQLParseNode::table_exp:
3361 case OSQLParseNode::table_ref_commalist:
3362 case OSQLParseNode::table_ref:
3363 case OSQLParseNode::catalog_name:
3364 case OSQLParseNode::schema_name:
3365 case OSQLParseNode::table_name:
3366 case OSQLParseNode::opt_column_commalist:
3367 case OSQLParseNode::column_commalist:
3368 case OSQLParseNode::column_ref_commalist:
3369 case OSQLParseNode::column_ref:
3370 case OSQLParseNode::opt_order_by_clause:
3371 case OSQLParseNode::ordering_spec_commalist:
3372 case OSQLParseNode::ordering_spec:
3373 case OSQLParseNode::opt_asc_desc:
3374 case OSQLParseNode::where_clause:
3375 case OSQLParseNode::opt_where_clause:
3376 case OSQLParseNode::opt_escape:
3377 case OSQLParseNode::scalar_exp_commalist:
3378 case OSQLParseNode::scalar_exp: // Seems to never be generated?
3379 case OSQLParseNode::parameter_ref:
3380 case OSQLParseNode::parameter:
3381 case OSQLParseNode::range_variable:
3382 case OSQLParseNode::delete_statement_positioned:
3383 case OSQLParseNode::delete_statement_searched:
3384 case OSQLParseNode::update_statement_positioned:
3385 case OSQLParseNode::update_statement_searched:
3386 case OSQLParseNode::assignment_commalist:
3387 case OSQLParseNode::assignment:
3388 case OSQLParseNode::insert_statement:
3389 case OSQLParseNode::insert_atom_commalist:
3390 case OSQLParseNode::insert_atom:
3391 case OSQLParseNode::from_clause:
3392 case OSQLParseNode::qualified_join:
3393 case OSQLParseNode::cross_union:
3394 case OSQLParseNode::select_sublist:
3395 case OSQLParseNode::join_type:
3396 case OSQLParseNode::named_columns_join:
3397 case OSQLParseNode::joined_table:
3398 case OSQLParseNode::sql_not:
3399 case OSQLParseNode::manipulative_statement:
3400 case OSQLParseNode::value_exp_commalist:
3401 case OSQLParseNode::union_statement:
3402 case OSQLParseNode::outer_join_type:
3403 case OSQLParseNode::selection:
3404 case OSQLParseNode::base_table_def:
3405 case OSQLParseNode::base_table_element_commalist:
3406 case OSQLParseNode::data_type:
3407 case OSQLParseNode::column_def:
3408 case OSQLParseNode::table_node:
3409 case OSQLParseNode::as_clause:
3410 case OSQLParseNode::opt_as:
3411 case OSQLParseNode::op_column_commalist:
3412 case OSQLParseNode::table_primary_as_range_column:
3413 case OSQLParseNode::character_string_type:
3414 OSL_FAIL("Unexpected SQL RuleID");
3415 break;
3416 case OSQLParseNode::column:
3417 case OSQLParseNode::column_val:
3418 OSL_FAIL("Cannot guess column type");
3419 break;
3420 case OSQLParseNode::values_or_query_spec:
3421 OSL_FAIL("Cannot guess VALUES type");
3422 break;
3423 case OSQLParseNode::derived_column:
3424 OSL_FAIL("Cannot guess computed column type");
3425 break;
3426 case OSQLParseNode::subquery:
3427 OSL_FAIL("Cannot guess subquery return type");
3428 break;
3429 case OSQLParseNode::search_condition:
3430 case OSQLParseNode::comparison_predicate:
3431 case OSQLParseNode::between_predicate:
3432 case OSQLParseNode::like_predicate:
3433 case OSQLParseNode::test_for_null:
3434 case OSQLParseNode::boolean_term:
3435 case OSQLParseNode::boolean_primary:
3436 case OSQLParseNode::in_predicate:
3437 case OSQLParseNode::existence_test:
3438 case OSQLParseNode::unique_test:
3439 case OSQLParseNode::all_or_any_predicate:
3440 case OSQLParseNode::join_condition:
3441 case OSQLParseNode::boolean_factor:
3442 case OSQLParseNode::boolean_test:
3443 case OSQLParseNode::comparison_predicate_part_2:
3444 case OSQLParseNode::parenthesized_boolean_value_expression:
3445 case OSQLParseNode::other_like_predicate_part_2:
3446 case OSQLParseNode::between_predicate_part_2:
3447 nDataType = DataType::BOOLEAN;
3448 break;
3449 case OSQLParseNode::num_value_exp:
3450 case OSQLParseNode::extract_exp:
3451 case OSQLParseNode::term:
3452 case OSQLParseNode::factor:
3453 // Might by an integer or a float; take the most generic
3454 nDataType = DataType::DOUBLE;
3455 break;
3456 case OSQLParseNode::value_exp_primary:
3457 case OSQLParseNode::value_exp:
3458 case OSQLParseNode::odbc_call_spec:
3459 // Really, we don't know. Let the default.
3460 break;
3461 case OSQLParseNode::position_exp:
3462 case OSQLParseNode::length_exp:
3463 nDataType = DataType::INTEGER;
3464 break;
3465 case OSQLParseNode::char_value_exp:
3466 case OSQLParseNode::char_value_fct:
3467 case OSQLParseNode::fold:
3468 case OSQLParseNode::char_substring_fct:
3469 case OSQLParseNode::char_factor:
3470 case OSQLParseNode::concatenation:
3471 nDataType = DataType::VARCHAR;
3472 break;
3473 case OSQLParseNode::datetime_primary:
3474 nDataType = DataType::TIMESTAMP;
3475 break;
3476 case OSQLParseNode::bit_value_fct:
3477 nDataType = DataType::BINARY;
3478 break;
3479 case OSQLParseNode::general_set_fct: // May depend on argument; ignore that for now
3480 case OSQLParseNode::set_fct_spec:
3482 if (pNode->count() == 0)
3484 // This is not a function call, no sense to continue with a function return type lookup
3485 OSL_FAIL("Got leaf SQL node where non-leaf expected");
3486 break;
3488 const OSQLParseNode* pFunctionName = pNode->getChild(0);
3489 if ( SQL_ISPUNCTUATION(pFunctionName,"{") )
3491 if ( pNode->count() == 3 )
3492 return fillFunctionInfo( pNode->getChild(1), sFunctionTerm, aInfo );
3493 else
3494 OSL_FAIL("ODBC escape not in recognised form");
3495 break;
3497 else
3499 if ( SQL_ISRULEOR2(pNode,length_exp,char_value_fct) )
3500 pFunctionName = pFunctionName->getChild(0);
3502 OUString sFunctionName = pFunctionName->getTokenValue();
3503 if ( sFunctionName.isEmpty() )
3504 sFunctionName = OStringToOUString(OSQLParser::TokenIDToStr(pFunctionName->getTokenID()),RTL_TEXTENCODING_UTF8);
3506 nDataType = OSQLParser::getFunctionReturnType(
3507 sFunctionName
3508 ,&rController.getParser().getContext());
3510 break;
3512 case OSQLParseNode::odbc_fct_spec:
3514 if (pNode->count() != 2)
3516 OSL_FAIL("interior of ODBC escape not in recognised shape");
3517 break;
3520 const OSQLParseNode* const pEscapeType = pNode->getChild(0);
3521 if (SQL_ISTOKEN(pEscapeType, TS))
3522 nDataType = DataType::TIMESTAMP;
3523 else if (SQL_ISTOKEN(pEscapeType, D))
3524 nDataType = DataType::DATE;
3525 else if (SQL_ISTOKEN(pEscapeType, T))
3526 nDataType = DataType::TIME;
3527 else if (SQL_ISTOKEN(pEscapeType, FN))
3528 return fillFunctionInfo( pNode->getChild(1), sFunctionTerm, aInfo );
3529 else
3530 OSL_FAIL("Unknown ODBC escape");
3531 break;
3533 case OSQLParseNode::cast_spec:
3535 if ( pNode->count() != 6 || !SQL_ISTOKEN(pNode->getChild(3), AS) )
3537 OSL_FAIL("CAST not in recognised shape");
3538 break;
3540 const OSQLParseNode *pCastTarget = pNode->getChild(4);
3541 if ( SQL_ISTOKENOR2(pCastTarget, INTEGER, INT) )
3542 nDataType = DataType::INTEGER;
3543 else if ( SQL_ISTOKEN(pCastTarget, SMALLINT) )
3544 nDataType = DataType::SMALLINT;
3545 else if ( SQL_ISTOKEN(pCastTarget, BIGINT) )
3546 nDataType = DataType::BIGINT;
3547 else if ( SQL_ISTOKEN(pCastTarget, FLOAT) )
3548 nDataType = DataType::FLOAT;
3549 else if ( SQL_ISTOKEN(pCastTarget, REAL) )
3550 nDataType = DataType::REAL;
3551 else if ( SQL_ISTOKEN(pCastTarget, DOUBLE) )
3552 nDataType = DataType::DOUBLE;
3553 else if ( SQL_ISTOKEN(pCastTarget, BOOLEAN) )
3554 nDataType = DataType::BOOLEAN;
3555 else if ( SQL_ISTOKEN(pCastTarget, DATE) )
3556 nDataType = DataType::DATE;
3557 else if ( pCastTarget->count() > 0 )
3559 const OSQLParseNode *pDataType = pCastTarget->getChild(0);
3560 while (pDataType->count() > 0)
3562 pCastTarget = pDataType;
3563 pDataType = pDataType->getChild(0);
3565 if ( SQL_ISTOKEN (pDataType, TIME) )
3566 nDataType = DataType::TIME;
3567 else if ( SQL_ISTOKEN (pDataType, TIMESTAMP) )
3568 nDataType = DataType::TIMESTAMP;
3569 else if ( SQL_ISTOKENOR3 (pDataType, CHARACTER, CHAR, NCHAR) )
3570 nDataType = char_datatype(pCastTarget, 0);
3571 else if ( SQL_ISTOKEN (pDataType, VARCHAR) )
3572 nDataType = DataType::VARCHAR;
3573 else if ( SQL_ISTOKEN (pDataType, CLOB) )
3574 nDataType = DataType::CLOB;
3575 else if ( SQL_ISTOKEN (pDataType, NATIONAL) )
3576 nDataType = char_datatype(pCastTarget, 1);
3577 else if ( SQL_ISTOKEN (pDataType, BINARY) )
3579 if ( pCastTarget->count() > 2 && SQL_ISTOKEN(pCastTarget->getChild(1), LARGE) && SQL_ISTOKEN(pCastTarget->getChild(2), OBJECT) )
3580 nDataType = DataType::BLOB;
3581 else if ( pCastTarget->count() > 1 && SQL_ISTOKEN(pCastTarget->getChild(1), VARYING) )
3582 nDataType = DataType::VARBINARY;
3583 else
3584 nDataType = DataType::BINARY;
3586 else if ( SQL_ISTOKEN (pDataType, VARBINARY) )
3587 nDataType = DataType::VARBINARY;
3588 else if ( SQL_ISTOKEN (pDataType, BLOB) )
3589 nDataType = DataType::BLOB;
3590 else if ( SQL_ISTOKEN (pDataType, NUMERIC) )
3591 nDataType = DataType::NUMERIC;
3592 else if ( SQL_ISTOKENOR2 (pDataType, DECIMAL, DEC) )
3593 nDataType = DataType::DECIMAL;
3594 else if ( SQL_ISTOKEN (pDataType, FLOAT) )
3595 nDataType = DataType::FLOAT;
3596 else if ( SQL_ISTOKEN (pDataType, DOUBLE) )
3597 nDataType = DataType::DOUBLE;
3598 else if ( SQL_ISTOKEN (pDataType, TIME) )
3599 nDataType = DataType::TIME;
3600 else if ( SQL_ISTOKEN (pDataType, TIMESTAMP) )
3601 nDataType = DataType::TIMESTAMP;
3602 else if ( SQL_ISTOKEN (pDataType, INTERVAL) )
3603 // Not in DataType published constant (because not in JDBC...)
3604 nDataType = DataType::VARCHAR;
3605 else
3606 OSL_FAIL("Failed to decode CAST target");
3608 else
3609 OSL_FAIL("Could not decipher CAST target");
3610 break;
3612 default:
3613 OSL_FAIL("Unknown SQL RuleID");
3614 break;
3616 break;
3617 default:
3618 OSL_FAIL("Unknown SQL Node Type");
3619 break;
3622 aInfo->SetDataType(nDataType);
3623 aInfo->SetFieldType(TAB_NORMAL_FIELD);
3624 aInfo->SetField(sFunctionTerm);
3625 aInfo->SetTabWindow(NULL);
3627 // -----------------------------------------------------------------------------
3629 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */