1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: fanalyzer.cxx,v $
10 * $Revision: 1.26.56.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
33 #include "file/fanalyzer.hxx"
34 #include "connectivity/sqlparse.hxx"
35 #include <osl/diagnose.h>
36 #include <tools/debug.hxx>
37 #include <comphelper/extract.hxx>
38 #include "connectivity/sqlnode.hxx"
39 #include "connectivity/dbexception.hxx"
40 #include "file/FConnection.hxx"
41 #include "resource/file_res.hrc"
43 using namespace ::connectivity
;
44 using namespace ::connectivity::file
;
45 using namespace ::com::sun::star::uno
;
46 using namespace ::com::sun::star::beans
;
47 using namespace ::com::sun::star::sdbc
;
48 using namespace ::com::sun::star::container
;
50 DBG_NAME( file_OSQLAnalyzer
)
51 //------------------------------------------------------------------
52 OSQLAnalyzer::OSQLAnalyzer(OConnection
* _pConnection
)
53 :m_pConnection(_pConnection
)
54 ,m_bHasSelectionCode(sal_False
)
55 ,m_bSelectionFirstTime(sal_True
)
57 DBG_CTOR( file_OSQLAnalyzer
, NULL
);
58 m_aCompiler
= new OPredicateCompiler(this);
59 m_aInterpreter
= new OPredicateInterpreter(m_aCompiler
);
62 // -----------------------------------------------------------------------------
63 OSQLAnalyzer::~OSQLAnalyzer()
65 DBG_DTOR( file_OSQLAnalyzer
, NULL
);
68 // -----------------------------------------------------------------------------
69 void OSQLAnalyzer::setIndexes(const Reference
< XNameAccess
>& _xIndexes
)
71 m_aCompiler
->m_xIndexes
= _xIndexes
;
73 //------------------------------------------------------------------
74 void OSQLAnalyzer::start(OSQLParseNode
* pSQLParseNode
)
76 if (SQL_ISRULE(pSQLParseNode
,select_statement
))
78 DBG_ASSERT(pSQLParseNode
->count() >= 4,"OFILECursor: Fehler im Parse Tree");
80 // check that we don't use anything other than count(*) as function
81 OSQLParseNode
* pSelection
= pSQLParseNode
->getChild(2);
82 if ( SQL_ISRULE(pSelection
,scalar_exp_commalist
) )
84 for (sal_uInt32 i
= 0; i
< pSelection
->count(); i
++)
86 OSQLParseNode
*pColumnRef
= pSelection
->getChild(i
)->getChild(0);
87 if ( ( SQL_ISRULE(pColumnRef
,set_fct_spec
) && pColumnRef
->count() == 4 )
88 || SQL_ISRULE(pColumnRef
,char_value_fct
)
89 || SQL_ISRULE(pColumnRef
,char_substring_fct
)
90 || SQL_ISRULE(pColumnRef
,position_exp
)
91 || SQL_ISRULE(pColumnRef
,fold
)
92 || SQL_ISRULE(pColumnRef
,length_exp
)
93 || SQL_ISRULE(pColumnRef
,num_value_exp
)
94 || SQL_ISRULE(pColumnRef
,term
)
95 || SQL_ISRULE(pColumnRef
,factor
)
96 || SQL_ISRULE(pColumnRef
,set_fct_spec
) )
98 ::vos::ORef
<OPredicateCompiler
> pCompiler
= new OPredicateCompiler(this);
99 pCompiler
->setOrigColumns(m_aCompiler
->getOrigColumns());
100 ::vos::ORef
<OPredicateInterpreter
> pInterpreter
= new OPredicateInterpreter(pCompiler
);
101 pCompiler
->execute( pColumnRef
);
102 m_aSelectionEvaluations
.push_back( TPredicates(pCompiler
,pInterpreter
) );
104 else if ( ( SQL_ISRULE(pColumnRef
,general_set_fct
) && pColumnRef
->count() != 4 ) )
106 m_pConnection
->throwGenericSQLException(STR_QUERY_COMPLEX_COUNT
,NULL
);
109 m_aSelectionEvaluations
.push_back( TPredicates() );
114 m_aCompiler
->start(pSQLParseNode
);
117 //------------------------------------------------------------------
118 void OSQLAnalyzer::bindRow(OCodeList
& rCodeList
,const OValueRefRow
& _pRow
,OEvaluateSetList
& _rEvaluateSetList
)
120 // Zaehlen, wieviele Kriterien
121 // wenn nur ein Kriterium, und das entsprechende Feld ist indiziert
122 // dann wird der Index verwendet
124 OEvaluateSet
* pEvaluateSet
= NULL
;
126 for (OCodeList::iterator aIter
= rCodeList
.begin(); aIter
!= rCodeList
.end(); ++aIter
)
128 OOperandAttr
* pAttr
= PTR_CAST(OOperandAttr
,(*aIter
));
131 if (pAttr
->isIndexed() && !m_aCompiler
->hasORCondition())
133 OCode
* pCode1
= *(aIter
+ 1);
134 OCode
* pCode2
= *(aIter
+ 2);
136 if (PTR_CAST(OOperand
,pCode1
))
137 pEvaluateSet
= pAttr
->preProcess(PTR_CAST(OBoolOperator
,pCode2
), PTR_CAST(OOperand
,pCode1
));
139 pEvaluateSet
= pAttr
->preProcess(PTR_CAST(OBoolOperator
,pCode1
));
144 _rEvaluateSetList
.push_back(pEvaluateSet
);
147 pAttr
->bindValue(_pRow
);
151 //------------------------------------------------------------------
152 void OSQLAnalyzer::bindSelectRow(const OValueRefRow
& _pRow
)
154 // first the select part
155 OEvaluateSetList aEvaluateSetList
;
156 for ( ::std::vector
< TPredicates
>::iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end();++aIter
)
158 if ( aIter
->first
.isValid() )
159 bindRow( aIter
->first
->m_aCodeList
,_pRow
,aEvaluateSetList
);
162 //------------------------------------------------------------------
163 ::std::vector
<sal_Int32
>* OSQLAnalyzer::bindEvaluationRow(OValueRefRow
& _pRow
)
165 OEvaluateSetList aEvaluateSetList
;
166 bindRow( m_aCompiler
->m_aCodeList
,_pRow
,aEvaluateSetList
);
168 ::std::vector
<sal_Int32
>* pKeySet
= NULL
;
169 OEvaluateSet
* pEvaluateSet
= NULL
;
171 // Keyset erzeugen mit kleinster Liste
172 if(!aEvaluateSetList
.empty())
174 // welche Liste hat den kleinsten count ?
175 OEvaluateSetList::iterator i
= aEvaluateSetList
.begin();
177 for(++i
; i
!= aEvaluateSetList
.end();++i
)
179 OEvaluateSet
* pEvaluateSetComp
= (*i
);
180 for(OEvaluateSet::reverse_iterator j
= pEvaluateSet
->rbegin(); j
!= pEvaluateSet
->rend(); ++j
)
182 if (pEvaluateSetComp
->find(j
->second
) != pEvaluateSetComp
->end())
183 pEvaluateSet
->erase(j
->second
);
186 pKeySet
= new ::std::vector
<sal_Int32
>(pEvaluateSet
->size());
188 for(OEvaluateSet::iterator j
= pEvaluateSet
->begin(); j
!= pEvaluateSet
->end(); ++j
,++k
)
190 (*pKeySet
)[k
] = j
->second
;
194 for(i
= aEvaluateSetList
.begin(); i
!= aEvaluateSetList
.end();++i
)
201 //------------------------------------------------------------------
202 void OSQLAnalyzer::describeParam(::vos::ORef
<OSQLColumns
> rParameterColumns
)
204 OCodeList
& rCodeList
= m_aCompiler
->m_aCodeList
;
205 OCodeStack aCodeStack
;
207 if (!rCodeList
.size())
208 return; // kein Praedikat
209 if (!rParameterColumns
->get().size())
210 return; // keine Parameter
212 // Anlegen von Columns, die eine genauere Beschreibung fuer die enthalten
213 ::vos::ORef
<OSQLColumns
> aNewParamColumns
= new OSQLColumns(*rParameterColumns
);
216 // Anlegen einer Testzeile, wird benoetigt um die Parameter zu beschreiben
217 OValueRefRow aParameterRow
= new OValueRefVector(rParameterColumns
->get().size());
218 bindParameterRow(aParameterRow
);
220 OValueRefRow aTestRow
= new OValueRefVector(Reference
< XIndexAccess
>(m_aCompiler
->getOrigColumns(),UNO_QUERY
)->getCount());
221 delete bindEvaluationRow(aTestRow
); // Binden der Attribute an die Values
223 for(OCodeList::iterator aIter
= rCodeList
.begin(); aIter
!= rCodeList
.end(); ++aIter
)
225 OOperand
* pOperand
= PTR_CAST(OOperand
,(*aIter
));
226 OOperator
* pOperator
= PTR_CAST(OOperator
,(*aIter
));
228 aCodeStack
.push(pOperand
);
231 if (pOperator
->getRequestedOperands() == 2) // bei zwei Operatoren ist es moeglich
232 { // einen Parameter weiter zu spezifizieren
233 OOperandParam
*pParam
= PTR_CAST(OOperandParam
,aCodeStack
.top());
234 if (pParam
) // Anpassen des ParameterTyps, wenn der linke Operand ein Attribut ist
236 OOperandAttr
*pLeft
= PTR_CAST(OOperandAttr
,*(rCodeList
.end() - 2));
239 Reference
< XPropertySet
> xCol
;
240 Reference
< XIndexAccess
>(m_aCompiler
->getOrigColumns(),UNO_QUERY
)->getByIndex(pLeft
->getRowPos()) >>= xCol
;
241 OSL_ENSURE(xCol
.is(), "Ungueltige Struktur");
242 pParam
->describe(xCol
, aNewParamColumns
);
246 pOperator
->Exec(aCodeStack
);
249 OOperand
* pOperand
= aCodeStack
.top();
252 OSL_ENSURE(aCodeStack
.size() == 0, "StackFehler");
253 OSL_ENSURE(pOperand
, "StackFehler");
254 if (IS_TYPE(OOperandResult
,pOperand
))
257 OSL_ENSURE(0,"Illegal here!");
259 rParameterColumns
= aNewParamColumns
;
260 // m_aCompiler->setParameterColumns(rParameterColumns);
263 // -----------------------------------------------------------------------------
264 OOperandAttr
* OSQLAnalyzer::createOperandAttr(sal_Int32 _nPos
,
265 const Reference
< XPropertySet
>& _xCol
,
266 const Reference
< XNameAccess
>& /*_xIndexes*/)
268 return new OOperandAttr(static_cast<sal_uInt16
>(_nPos
),_xCol
);
270 // -----------------------------------------------------------------------------
271 BOOL
OSQLAnalyzer::hasRestriction() const
273 return m_aCompiler
->hasCode();
275 // -----------------------------------------------------------------------------
276 BOOL
OSQLAnalyzer::hasFunctions() const
278 if ( m_bSelectionFirstTime
)
280 m_bSelectionFirstTime
= sal_False
;
281 for ( ::std::vector
< TPredicates
>::const_iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end() && !m_bHasSelectionCode
;++aIter
)
283 if ( aIter
->first
.isValid() )
284 m_bHasSelectionCode
= aIter
->first
->hasCode();
287 return m_bHasSelectionCode
;;
289 // -----------------------------------------------------------------------------
290 void OSQLAnalyzer::setSelectionEvaluationResult(OValueRefRow
& _pRow
,const ::std::vector
<sal_Int32
>& _rColumnMapping
)
293 for ( ::std::vector
< TPredicates
>::iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end();++aIter
,++nPos
)
295 if ( aIter
->second
.isValid() )
297 sal_Int32 map
= nPos
;
298 // the first column (index 0) is for convenience only. The first real select column is no 1.
299 if ( (nPos
> 0) && (nPos
< static_cast<sal_Int32
>(_rColumnMapping
.size())) )
300 map
= _rColumnMapping
[nPos
];
301 aIter
->second
->startSelection((_pRow
->get())[map
]);
305 // -----------------------------------------------------------------------------
306 void OSQLAnalyzer::dispose()
308 m_aCompiler
->dispose();
309 for ( ::std::vector
< TPredicates
>::iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end();++aIter
)
311 if ( aIter
->first
.isValid() )
312 aIter
->first
->dispose();
315 // -----------------------------------------------------------------------------
316 void OSQLAnalyzer::setOrigColumns(const OFileColumns
& rCols
)
318 m_aCompiler
->setOrigColumns(rCols
);
319 for ( ::std::vector
< TPredicates
>::iterator aIter
= m_aSelectionEvaluations
.begin(); aIter
!= m_aSelectionEvaluations
.end();++aIter
)
321 if ( aIter
->first
.isValid() )
322 aIter
->first
->setOrigColumns(rCols
);
325 // -----------------------------------------------------------------------------