1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "file/fanalyzer.hxx"
21 #include "connectivity/sqlparse.hxx"
22 #include <osl/diagnose.h>
23 #include <tools/debug.hxx>
24 #include <comphelper/extract.hxx>
25 #include "connectivity/sqlnode.hxx"
26 #include "connectivity/dbexception.hxx"
27 #include "file/FConnection.hxx"
28 #include "resource/file_res.hrc"
30 using namespace ::connectivity
;
31 using namespace ::connectivity::file
;
32 using namespace ::com::sun::star::uno
;
33 using namespace ::com::sun::star::beans
;
34 using namespace ::com::sun::star::sdbc
;
35 using namespace ::com::sun::star::container
;
37 OSQLAnalyzer::OSQLAnalyzer(OConnection
* _pConnection
)
38 :m_pConnection(_pConnection
)
39 ,m_bHasSelectionCode(false)
40 ,m_bSelectionFirstTime(true)
42 m_aCompiler
= new OPredicateCompiler(this);
43 m_aInterpreter
= new OPredicateInterpreter(m_aCompiler
);
47 OSQLAnalyzer::~OSQLAnalyzer()
52 void OSQLAnalyzer::setIndexes(const Reference
< XNameAccess
>& _xIndexes
)
54 m_aCompiler
->m_xIndexes
= _xIndexes
;
57 void OSQLAnalyzer::start(OSQLParseNode
* pSQLParseNode
)
59 if (SQL_ISRULE(pSQLParseNode
,select_statement
))
61 DBG_ASSERT(pSQLParseNode
->count() >= 4,"OFILECursor: Fehler im Parse Tree");
63 // check that we don't use anything other than count(*) as function
64 OSQLParseNode
* pSelection
= pSQLParseNode
->getChild(2);
65 if ( SQL_ISRULE(pSelection
,scalar_exp_commalist
) )
67 for (sal_uInt32 i
= 0; i
< pSelection
->count(); i
++)
69 OSQLParseNode
*pColumnRef
= pSelection
->getChild(i
)->getChild(0);
70 if ( ( SQL_ISRULE(pColumnRef
,set_fct_spec
) && pColumnRef
->count() == 4 )
71 || SQL_ISRULE(pColumnRef
,char_value_fct
)
72 || SQL_ISRULE(pColumnRef
,char_substring_fct
)
73 || SQL_ISRULE(pColumnRef
,position_exp
)
74 || SQL_ISRULE(pColumnRef
,fold
)
75 || SQL_ISRULE(pColumnRef
,length_exp
)
76 || SQL_ISRULE(pColumnRef
,num_value_exp
)
77 || SQL_ISRULE(pColumnRef
,term
)
78 || SQL_ISRULE(pColumnRef
,factor
)
79 || SQL_ISRULE(pColumnRef
,set_fct_spec
) )
81 ::rtl::Reference
<OPredicateCompiler
> pCompiler
= new OPredicateCompiler(this);
82 pCompiler
->setOrigColumns(m_aCompiler
->getOrigColumns());
83 ::rtl::Reference
<OPredicateInterpreter
> pInterpreter
= new OPredicateInterpreter(pCompiler
);
84 pCompiler
->execute( pColumnRef
);
85 m_aSelectionEvaluations
.push_back( TPredicates(pCompiler
,pInterpreter
) );
87 else if ( ( SQL_ISRULE(pColumnRef
,general_set_fct
) && pColumnRef
->count() != 4 ) )
89 m_pConnection
->throwGenericSQLException(STR_QUERY_COMPLEX_COUNT
,NULL
);
93 if ( SQL_ISPUNCTUATION( pColumnRef
, "*" )
94 || ( SQL_ISRULE( pColumnRef
, column_ref
)
95 && ( pColumnRef
->count() == 3 )
96 && ( pColumnRef
->getChild(0)->getNodeType() == SQL_NODE_NAME
)
97 && SQL_ISPUNCTUATION( pColumnRef
->getChild(1), "." )
98 && SQL_ISRULE( pColumnRef
->getChild(2), column_val
)
99 && SQL_ISPUNCTUATION( pColumnRef
->getChild(2)->getChild(0), "*" )
103 // push one element for each column of our table
104 const Reference
< XNameAccess
> xColumnNames( m_aCompiler
->getOrigColumns() );
105 const Sequence
< OUString
> aColumnNames( xColumnNames
->getElementNames() );
106 for ( sal_Int32 j
=0; j
<aColumnNames
.getLength(); ++j
)
107 m_aSelectionEvaluations
.push_back( TPredicates() );
110 m_aSelectionEvaluations
.push_back( TPredicates() );
116 m_aCompiler
->start(pSQLParseNode
);
120 void OSQLAnalyzer::bindRow(OCodeList
& rCodeList
,const OValueRefRow
& _pRow
,OEvaluateSetList
& _rEvaluateSetList
)
123 // if only one criterion, and the corresponding field is indexed
124 // then the index will be used
125 OEvaluateSet
* pEvaluateSet
= NULL
;
127 for (OCodeList::iterator aIter
= rCodeList
.begin(); aIter
!= rCodeList
.end(); ++aIter
)
129 OOperandAttr
* pAttr
= PTR_CAST(OOperandAttr
,(*aIter
));
132 if (pAttr
->isIndexed() && !m_aCompiler
->hasORCondition())
134 OCode
* pCode1
= *(aIter
+ 1);
135 OCode
* pCode2
= *(aIter
+ 2);
137 if (PTR_CAST(OOperand
,pCode1
))
138 pEvaluateSet
= pAttr
->preProcess(PTR_CAST(OBoolOperator
,pCode2
), PTR_CAST(OOperand
,pCode1
));
140 pEvaluateSet
= pAttr
->preProcess(PTR_CAST(OBoolOperator
,pCode1
));
145 _rEvaluateSetList
.push_back(pEvaluateSet
);
148 pAttr
->bindValue(_pRow
);
153 void OSQLAnalyzer::bindSelectRow(const OValueRefRow
& _pRow
)
155 // first the select part
156 OEvaluateSetList aEvaluateSetList
;
157 for ( ::std::vector
< TPredicates
>::iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end();++aIter
)
159 if ( aIter
->first
.is() )
160 bindRow( aIter
->first
->m_aCodeList
,_pRow
,aEvaluateSetList
);
164 ::std::vector
<sal_Int32
>* OSQLAnalyzer::bindEvaluationRow(OValueRefRow
& _pRow
)
166 OEvaluateSetList aEvaluateSetList
;
167 bindRow( m_aCompiler
->m_aCodeList
,_pRow
,aEvaluateSetList
);
169 ::std::vector
<sal_Int32
>* pKeySet
= NULL
;
170 OEvaluateSet
* pEvaluateSet
= NULL
;
172 // create Keyset with smallest list
173 if(!aEvaluateSetList
.empty())
175 // which list has the smallest count?
176 OEvaluateSetList::iterator i
= aEvaluateSetList
.begin();
178 for(++i
; i
!= aEvaluateSetList
.end();++i
)
180 OEvaluateSet
* pEvaluateSetComp
= (*i
);
181 for(OEvaluateSet::reverse_iterator j
= pEvaluateSet
->rbegin(); j
!= pEvaluateSet
->rend(); ++j
)
183 if (pEvaluateSetComp
->find(j
->second
) != pEvaluateSetComp
->end())
184 pEvaluateSet
->erase(j
->second
);
187 pKeySet
= new ::std::vector
<sal_Int32
>(pEvaluateSet
->size());
189 for(OEvaluateSet::iterator j
= pEvaluateSet
->begin(); j
!= pEvaluateSet
->end(); ++j
,++k
)
191 (*pKeySet
)[k
] = j
->second
;
195 for(i
= aEvaluateSetList
.begin(); i
!= aEvaluateSetList
.end();++i
)
203 OOperandAttr
* OSQLAnalyzer::createOperandAttr(sal_Int32 _nPos
,
204 const Reference
< XPropertySet
>& _xCol
,
205 const Reference
< XNameAccess
>& /*_xIndexes*/)
207 return new OOperandAttr(static_cast<sal_uInt16
>(_nPos
),_xCol
);
210 bool OSQLAnalyzer::hasRestriction() const
212 return m_aCompiler
->hasCode();
215 bool OSQLAnalyzer::hasFunctions() const
217 if ( m_bSelectionFirstTime
)
219 m_bSelectionFirstTime
= false;
220 for ( ::std::vector
< TPredicates
>::const_iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end() && !m_bHasSelectionCode
;++aIter
)
222 if ( aIter
->first
.is() )
223 m_bHasSelectionCode
= aIter
->first
->hasCode();
226 return m_bHasSelectionCode
;
229 void OSQLAnalyzer::setSelectionEvaluationResult(OValueRefRow
& _pRow
,const ::std::vector
<sal_Int32
>& _rColumnMapping
)
232 for ( ::std::vector
< TPredicates
>::iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end();++aIter
,++nPos
)
234 if ( aIter
->second
.is() )
236 // the first column (index 0) is for convenience only. The first real select column is no 1.
237 sal_Int32 map
= nPos
;
238 if ( nPos
< static_cast< sal_Int32
>( _rColumnMapping
.size() ) )
239 map
= _rColumnMapping
[nPos
];
241 aIter
->second
->startSelection( (_pRow
->get())[map
] );
246 void OSQLAnalyzer::dispose()
248 m_aCompiler
->dispose();
249 for ( ::std::vector
< TPredicates
>::iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end();++aIter
)
251 if ( aIter
->first
.is() )
252 aIter
->first
->dispose();
256 void OSQLAnalyzer::setOrigColumns(const OFileColumns
& rCols
)
258 m_aCompiler
->setOrigColumns(rCols
);
259 for ( ::std::vector
< TPredicates
>::iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end();++aIter
)
261 if ( aIter
->first
.is() )
262 aIter
->first
->setOrigColumns(rCols
);
267 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */