1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include "file/fanalyzer.hxx"
30 #include "connectivity/sqlparse.hxx"
31 #include <osl/diagnose.h>
32 #include <tools/debug.hxx>
33 #include <comphelper/extract.hxx>
34 #include "connectivity/sqlnode.hxx"
35 #include "connectivity/dbexception.hxx"
36 #include "file/FConnection.hxx"
37 #include "resource/file_res.hrc"
39 using namespace ::connectivity
;
40 using namespace ::connectivity::file
;
41 using namespace ::com::sun::star::uno
;
42 using namespace ::com::sun::star::beans
;
43 using namespace ::com::sun::star::sdbc
;
44 using namespace ::com::sun::star::container
;
46 DBG_NAME( file_OSQLAnalyzer
)
47 //------------------------------------------------------------------
48 OSQLAnalyzer::OSQLAnalyzer(OConnection
* _pConnection
)
49 :m_pConnection(_pConnection
)
50 ,m_bHasSelectionCode(sal_False
)
51 ,m_bSelectionFirstTime(sal_True
)
53 DBG_CTOR( file_OSQLAnalyzer
, NULL
);
54 m_aCompiler
= new OPredicateCompiler(this);
55 m_aInterpreter
= new OPredicateInterpreter(m_aCompiler
);
58 // -----------------------------------------------------------------------------
59 OSQLAnalyzer::~OSQLAnalyzer()
61 DBG_DTOR( file_OSQLAnalyzer
, NULL
);
64 // -----------------------------------------------------------------------------
65 void OSQLAnalyzer::setIndexes(const Reference
< XNameAccess
>& _xIndexes
)
67 m_aCompiler
->m_xIndexes
= _xIndexes
;
69 //------------------------------------------------------------------
70 void OSQLAnalyzer::start(OSQLParseNode
* pSQLParseNode
)
72 if (SQL_ISRULE(pSQLParseNode
,select_statement
))
74 DBG_ASSERT(pSQLParseNode
->count() >= 4,"OFILECursor: Fehler im Parse Tree");
76 // check that we don't use anything other than count(*) as function
77 OSQLParseNode
* pSelection
= pSQLParseNode
->getChild(2);
78 if ( SQL_ISRULE(pSelection
,scalar_exp_commalist
) )
80 for (sal_uInt32 i
= 0; i
< pSelection
->count(); i
++)
82 OSQLParseNode
*pColumnRef
= pSelection
->getChild(i
)->getChild(0);
83 if ( ( SQL_ISRULE(pColumnRef
,set_fct_spec
) && pColumnRef
->count() == 4 )
84 || SQL_ISRULE(pColumnRef
,char_value_fct
)
85 || SQL_ISRULE(pColumnRef
,char_substring_fct
)
86 || SQL_ISRULE(pColumnRef
,position_exp
)
87 || SQL_ISRULE(pColumnRef
,fold
)
88 || SQL_ISRULE(pColumnRef
,length_exp
)
89 || SQL_ISRULE(pColumnRef
,num_value_exp
)
90 || SQL_ISRULE(pColumnRef
,term
)
91 || SQL_ISRULE(pColumnRef
,factor
)
92 || SQL_ISRULE(pColumnRef
,set_fct_spec
) )
94 ::rtl::Reference
<OPredicateCompiler
> pCompiler
= new OPredicateCompiler(this);
95 pCompiler
->setOrigColumns(m_aCompiler
->getOrigColumns());
96 ::rtl::Reference
<OPredicateInterpreter
> pInterpreter
= new OPredicateInterpreter(pCompiler
);
97 pCompiler
->execute( pColumnRef
);
98 m_aSelectionEvaluations
.push_back( TPredicates(pCompiler
,pInterpreter
) );
100 else if ( ( SQL_ISRULE(pColumnRef
,general_set_fct
) && pColumnRef
->count() != 4 ) )
102 m_pConnection
->throwGenericSQLException(STR_QUERY_COMPLEX_COUNT
,NULL
);
106 if ( SQL_ISPUNCTUATION( pColumnRef
, "*" )
107 || ( SQL_ISRULE( pColumnRef
, column_ref
)
108 && ( pColumnRef
->count() == 3 )
109 && ( pColumnRef
->getChild(0)->getNodeType() == SQL_NODE_NAME
)
110 && SQL_ISPUNCTUATION( pColumnRef
->getChild(1), "." )
111 && SQL_ISRULE( pColumnRef
->getChild(2), column_val
)
112 && SQL_ISPUNCTUATION( pColumnRef
->getChild(2)->getChild(0), "*" )
116 // push one element for each column of our table
117 const Reference
< XNameAccess
> xColumnNames( m_aCompiler
->getOrigColumns() );
118 const Sequence
< ::rtl::OUString
> aColumnNames( xColumnNames
->getElementNames() );
119 for ( sal_Int32 j
=0; j
<aColumnNames
.getLength(); ++j
)
120 m_aSelectionEvaluations
.push_back( TPredicates() );
123 m_aSelectionEvaluations
.push_back( TPredicates() );
129 m_aCompiler
->start(pSQLParseNode
);
132 //------------------------------------------------------------------
133 void OSQLAnalyzer::bindRow(OCodeList
& rCodeList
,const OValueRefRow
& _pRow
,OEvaluateSetList
& _rEvaluateSetList
)
136 // if only one criterion, and the corresponding field is indexed
137 // then the index will be used
138 OEvaluateSet
* pEvaluateSet
= NULL
;
140 for (OCodeList::iterator aIter
= rCodeList
.begin(); aIter
!= rCodeList
.end(); ++aIter
)
142 OOperandAttr
* pAttr
= PTR_CAST(OOperandAttr
,(*aIter
));
145 if (pAttr
->isIndexed() && !m_aCompiler
->hasORCondition())
147 OCode
* pCode1
= *(aIter
+ 1);
148 OCode
* pCode2
= *(aIter
+ 2);
150 if (PTR_CAST(OOperand
,pCode1
))
151 pEvaluateSet
= pAttr
->preProcess(PTR_CAST(OBoolOperator
,pCode2
), PTR_CAST(OOperand
,pCode1
));
153 pEvaluateSet
= pAttr
->preProcess(PTR_CAST(OBoolOperator
,pCode1
));
158 _rEvaluateSetList
.push_back(pEvaluateSet
);
161 pAttr
->bindValue(_pRow
);
165 //------------------------------------------------------------------
166 void OSQLAnalyzer::bindSelectRow(const OValueRefRow
& _pRow
)
168 // first the select part
169 OEvaluateSetList aEvaluateSetList
;
170 for ( ::std::vector
< TPredicates
>::iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end();++aIter
)
172 if ( aIter
->first
.is() )
173 bindRow( aIter
->first
->m_aCodeList
,_pRow
,aEvaluateSetList
);
176 //------------------------------------------------------------------
177 ::std::vector
<sal_Int32
>* OSQLAnalyzer::bindEvaluationRow(OValueRefRow
& _pRow
)
179 OEvaluateSetList aEvaluateSetList
;
180 bindRow( m_aCompiler
->m_aCodeList
,_pRow
,aEvaluateSetList
);
182 ::std::vector
<sal_Int32
>* pKeySet
= NULL
;
183 OEvaluateSet
* pEvaluateSet
= NULL
;
185 // create Keyset with smallest list
186 if(!aEvaluateSetList
.empty())
188 // which list has the smallest count?
189 OEvaluateSetList::iterator i
= aEvaluateSetList
.begin();
191 for(++i
; i
!= aEvaluateSetList
.end();++i
)
193 OEvaluateSet
* pEvaluateSetComp
= (*i
);
194 for(OEvaluateSet::reverse_iterator j
= pEvaluateSet
->rbegin(); j
!= pEvaluateSet
->rend(); ++j
)
196 if (pEvaluateSetComp
->find(j
->second
) != pEvaluateSetComp
->end())
197 pEvaluateSet
->erase(j
->second
);
200 pKeySet
= new ::std::vector
<sal_Int32
>(pEvaluateSet
->size());
202 for(OEvaluateSet::iterator j
= pEvaluateSet
->begin(); j
!= pEvaluateSet
->end(); ++j
,++k
)
204 (*pKeySet
)[k
] = j
->second
;
208 for(i
= aEvaluateSetList
.begin(); i
!= aEvaluateSetList
.end();++i
)
215 // -----------------------------------------------------------------------------
216 OOperandAttr
* OSQLAnalyzer::createOperandAttr(sal_Int32 _nPos
,
217 const Reference
< XPropertySet
>& _xCol
,
218 const Reference
< XNameAccess
>& /*_xIndexes*/)
220 return new OOperandAttr(static_cast<sal_uInt16
>(_nPos
),_xCol
);
222 // -----------------------------------------------------------------------------
223 sal_Bool
OSQLAnalyzer::hasRestriction() const
225 return m_aCompiler
->hasCode();
227 // -----------------------------------------------------------------------------
228 sal_Bool
OSQLAnalyzer::hasFunctions() const
230 if ( m_bSelectionFirstTime
)
232 m_bSelectionFirstTime
= sal_False
;
233 for ( ::std::vector
< TPredicates
>::const_iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end() && !m_bHasSelectionCode
;++aIter
)
235 if ( aIter
->first
.is() )
236 m_bHasSelectionCode
= aIter
->first
->hasCode();
239 return m_bHasSelectionCode
;
241 // -----------------------------------------------------------------------------
242 void OSQLAnalyzer::setSelectionEvaluationResult(OValueRefRow
& _pRow
,const ::std::vector
<sal_Int32
>& _rColumnMapping
)
245 for ( ::std::vector
< TPredicates
>::iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end();++aIter
,++nPos
)
247 if ( aIter
->second
.is() )
249 // the first column (index 0) is for convenience only. The first real select column is no 1.
250 sal_Int32 map
= nPos
;
251 if ( nPos
< static_cast< sal_Int32
>( _rColumnMapping
.size() ) )
252 map
= _rColumnMapping
[nPos
];
254 aIter
->second
->startSelection( (_pRow
->get())[map
] );
258 // -----------------------------------------------------------------------------
259 void OSQLAnalyzer::dispose()
261 m_aCompiler
->dispose();
262 for ( ::std::vector
< TPredicates
>::iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end();++aIter
)
264 if ( aIter
->first
.is() )
265 aIter
->first
->dispose();
268 // -----------------------------------------------------------------------------
269 void OSQLAnalyzer::setOrigColumns(const OFileColumns
& rCols
)
271 m_aCompiler
->setOrigColumns(rCols
);
272 for ( ::std::vector
< TPredicates
>::iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end();++aIter
)
274 if ( aIter
->first
.is() )
275 aIter
->first
->setOrigColumns(rCols
);
278 // -----------------------------------------------------------------------------
280 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */