1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_connectivity.hxx"
30 #include "file/fanalyzer.hxx"
31 #include "connectivity/sqlparse.hxx"
32 #include <osl/diagnose.h>
33 #include <tools/debug.hxx>
34 #include <comphelper/extract.hxx>
35 #include "connectivity/sqlnode.hxx"
36 #include "connectivity/dbexception.hxx"
37 #include "file/FConnection.hxx"
38 #include "resource/file_res.hrc"
39 
40 using namespace ::connectivity;
41 using namespace ::connectivity::file;
42 using namespace ::com::sun::star::uno;
43 using namespace ::com::sun::star::beans;
44 using namespace ::com::sun::star::sdbc;
45 using namespace ::com::sun::star::container;
46 
47 DBG_NAME( file_OSQLAnalyzer )
48 //------------------------------------------------------------------
49 OSQLAnalyzer::OSQLAnalyzer(OConnection* _pConnection)
50 			   :m_pConnection(_pConnection)
51                ,m_bHasSelectionCode(sal_False)
52                ,m_bSelectionFirstTime(sal_True)
53 {
54 	DBG_CTOR( file_OSQLAnalyzer, NULL );
55 	m_aCompiler = new OPredicateCompiler(this);
56 	m_aInterpreter = new OPredicateInterpreter(m_aCompiler);
57 }
58 
59 // -----------------------------------------------------------------------------
60 OSQLAnalyzer::~OSQLAnalyzer()
61 {
62 	DBG_DTOR( file_OSQLAnalyzer, NULL );
63 }
64 
65 // -----------------------------------------------------------------------------
66 void OSQLAnalyzer::setIndexes(const Reference< XNameAccess>& _xIndexes)
67 {
68 	m_aCompiler->m_xIndexes = _xIndexes;
69 }
70 //------------------------------------------------------------------
71 void OSQLAnalyzer::start(OSQLParseNode* pSQLParseNode)
72 {
73 	if (SQL_ISRULE(pSQLParseNode,select_statement))
74 	{
75 		DBG_ASSERT(pSQLParseNode->count() >= 4,"OFILECursor: Fehler im Parse Tree");
76 
77 		// check that we don't use anything other than count(*) as function
78 		OSQLParseNode* pSelection = pSQLParseNode->getChild(2);
79 		if ( SQL_ISRULE(pSelection,scalar_exp_commalist) )
80 		{
81 			for (sal_uInt32 i = 0; i < pSelection->count(); i++)
82 			{
83 				OSQLParseNode *pColumnRef = pSelection->getChild(i)->getChild(0);
84 				if (	( SQL_ISRULE(pColumnRef,set_fct_spec) && pColumnRef->count() == 4 )
85 					||	SQL_ISRULE(pColumnRef,char_value_fct)
86 					||	SQL_ISRULE(pColumnRef,char_substring_fct)
87 					||	SQL_ISRULE(pColumnRef,position_exp)
88 					||	SQL_ISRULE(pColumnRef,fold)
89 					||	SQL_ISRULE(pColumnRef,length_exp)
90                     ||	SQL_ISRULE(pColumnRef,num_value_exp)
91                     ||	SQL_ISRULE(pColumnRef,term)
92                     ||	SQL_ISRULE(pColumnRef,factor)
93 					||	SQL_ISRULE(pColumnRef,set_fct_spec) )
94 				{
95 					::vos::ORef<OPredicateCompiler>		pCompiler = new OPredicateCompiler(this);
96 					pCompiler->setOrigColumns(m_aCompiler->getOrigColumns());
97 					::vos::ORef<OPredicateInterpreter>	pInterpreter = new OPredicateInterpreter(pCompiler);
98 					pCompiler->execute( pColumnRef );
99 					m_aSelectionEvaluations.push_back( TPredicates(pCompiler,pInterpreter) );
100 				}
101 				else if ( ( SQL_ISRULE(pColumnRef,general_set_fct) && pColumnRef->count() != 4 ) )
102 				{
103 					m_pConnection->throwGenericSQLException(STR_QUERY_COMPLEX_COUNT,NULL);
104 				}
105 				else
106                 {
107                     if  (   SQL_ISPUNCTUATION( pColumnRef, "*" )
108                         ||  (   SQL_ISRULE( pColumnRef, column_ref )
109                             &&  ( pColumnRef->count() == 3 )
110                             &&  ( pColumnRef->getChild(0)->getNodeType() == SQL_NODE_NAME )
111                             &&  SQL_ISPUNCTUATION( pColumnRef->getChild(1), "." )
112                             &&  SQL_ISRULE( pColumnRef->getChild(2), column_val )
113                             &&  SQL_ISPUNCTUATION( pColumnRef->getChild(2)->getChild(0), "*" )
114                             )
115                         )
116                     {
117                         // push one element for each column of our table
118                         const Reference< XNameAccess > xColumnNames( m_aCompiler->getOrigColumns() );
119                         const Sequence< ::rtl::OUString > aColumnNames( xColumnNames->getElementNames() );
120                         for ( sal_Int32 j=0; j<aColumnNames.getLength(); ++j )
121 					        m_aSelectionEvaluations.push_back( TPredicates() );
122                     }
123                     else
124 					    m_aSelectionEvaluations.push_back( TPredicates() );
125                 }
126 			}
127 		}
128 	}
129 
130 	m_aCompiler->start(pSQLParseNode);
131 }
132 
133 //------------------------------------------------------------------
134 void OSQLAnalyzer::bindRow(OCodeList& rCodeList,const OValueRefRow& _pRow,OEvaluateSetList& _rEvaluateSetList)
135 {
136 	// Zaehlen, wieviele Kriterien
137 	// wenn nur ein Kriterium, und das entsprechende Feld ist indiziert
138 	// dann wird der Index verwendet
139 
140 	OEvaluateSet*		pEvaluateSet = NULL;
141 
142 	for (OCodeList::iterator aIter = rCodeList.begin(); aIter != rCodeList.end(); ++aIter)
143 	{
144 		OOperandAttr* pAttr = PTR_CAST(OOperandAttr,(*aIter));
145 		if (pAttr)
146 		{
147 			if (pAttr->isIndexed() && !m_aCompiler->hasORCondition())
148 			{
149 				OCode* pCode1 = *(aIter + 1);
150 				OCode* pCode2 = *(aIter + 2);
151 
152 				if (PTR_CAST(OOperand,pCode1))
153 					pEvaluateSet = pAttr->preProcess(PTR_CAST(OBoolOperator,pCode2), PTR_CAST(OOperand,pCode1));
154 				else
155 					pEvaluateSet = pAttr->preProcess(PTR_CAST(OBoolOperator,pCode1));
156 			}
157 
158 			if (pEvaluateSet)
159 			{
160 				_rEvaluateSetList.push_back(pEvaluateSet);
161 				pEvaluateSet = NULL;
162 			}
163 			pAttr->bindValue(_pRow);
164 		}
165 	}
166 }
167 //------------------------------------------------------------------
168 void OSQLAnalyzer::bindSelectRow(const OValueRefRow& _pRow)
169 {
170 	// first the select part
171 	OEvaluateSetList	aEvaluateSetList;
172 	for ( ::std::vector< TPredicates >::iterator aIter = m_aSelectionEvaluations.begin(); aIter != m_aSelectionEvaluations.end();++aIter)
173 	{
174 		if ( aIter->first.isValid() )
175 			bindRow( aIter->first->m_aCodeList,_pRow,aEvaluateSetList);
176 	}
177 }
178 //------------------------------------------------------------------
179 ::std::vector<sal_Int32>* OSQLAnalyzer::bindEvaluationRow(OValueRefRow& _pRow)
180 {
181 	OEvaluateSetList	aEvaluateSetList;
182 	bindRow( m_aCompiler->m_aCodeList,_pRow,aEvaluateSetList);
183 
184 	::std::vector<sal_Int32>*	pKeySet		 = NULL;
185 	OEvaluateSet*				pEvaluateSet = NULL;
186 
187 	// Keyset erzeugen mit kleinster Liste
188 	if(!aEvaluateSetList.empty())
189 	{
190 		// welche Liste hat den kleinsten count ?
191 		OEvaluateSetList::iterator i = aEvaluateSetList.begin();
192 		pEvaluateSet = *(i);
193 		for(++i; i != aEvaluateSetList.end();++i)
194 		{
195 			OEvaluateSet*	pEvaluateSetComp = (*i);
196 			for(OEvaluateSet::reverse_iterator j = pEvaluateSet->rbegin(); j != pEvaluateSet->rend(); ++j)
197 			{
198 				if (pEvaluateSetComp->find(j->second) != pEvaluateSetComp->end())
199 					pEvaluateSet->erase(j->second);
200 			}
201 		}
202 		pKeySet = new ::std::vector<sal_Int32>(pEvaluateSet->size());
203 		sal_Int32 k=0;
204 		for(OEvaluateSet::iterator j = pEvaluateSet->begin(); j != pEvaluateSet->end(); ++j,++k)
205 		{
206 			(*pKeySet)[k] = j->second;
207 		}
208 
209 		// alle loeschen
210 		for(i = aEvaluateSetList.begin(); i != aEvaluateSetList.end();++i)
211 			delete (*i);
212 	}
213 
214 	return pKeySet;
215 }
216 
217 //------------------------------------------------------------------
218 void OSQLAnalyzer::describeParam(::vos::ORef<OSQLColumns> rParameterColumns)
219 {
220 	OCodeList& rCodeList	= m_aCompiler->m_aCodeList;
221 	OCodeStack aCodeStack;
222 
223 	if (!rCodeList.size())
224         return;     // kein Praedikat
225 	if (!rParameterColumns->get().size())
226 		return; // keine Parameter
227 
228     // Anlegen von Columns, die eine genauere Beschreibung fuer die enthalten
229 	::vos::ORef<OSQLColumns> aNewParamColumns = new OSQLColumns(*rParameterColumns);
230 
231 
232     // Anlegen einer Testzeile, wird benoetigt um die Parameter zu beschreiben
233 	OValueRefRow aParameterRow  = new OValueRefVector(rParameterColumns->get().size());
234 	bindParameterRow(aParameterRow);
235 
236 	OValueRefRow aTestRow = new OValueRefVector(Reference< XIndexAccess>(m_aCompiler->getOrigColumns(),UNO_QUERY)->getCount());
237 	delete bindEvaluationRow(aTestRow);					// Binden der Attribute an die Values
238 
239 	for(OCodeList::iterator aIter = rCodeList.begin(); aIter != rCodeList.end(); ++aIter)
240 	{
241 		OOperand* pOperand = PTR_CAST(OOperand,(*aIter));
242 		OOperator* pOperator = PTR_CAST(OOperator,(*aIter));
243 		if (pOperand)
244 			aCodeStack.push(pOperand);
245 		else
246 		{
247             if (pOperator->getRequestedOperands() == 2)     // bei zwei Operatoren ist es moeglich
248 			{												// einen Parameter weiter zu spezifizieren
249 				OOperandParam *pParam  = PTR_CAST(OOperandParam,aCodeStack.top());
250 				if (pParam)  // Anpassen des ParameterTyps, wenn der linke Operand ein Attribut ist
251 				{
252 					OOperandAttr *pLeft	 = PTR_CAST(OOperandAttr,*(rCodeList.end() - 2));
253 					if (pLeft)
254 					{
255 						Reference< XPropertySet> xCol;
256 						Reference< XIndexAccess>(m_aCompiler->getOrigColumns(),UNO_QUERY)->getByIndex(pLeft->getRowPos()) >>= xCol;
257                         OSL_ENSURE(xCol.is(), "Ungueltige Struktur");
258 						pParam->describe(xCol, aNewParamColumns);
259 					}
260 				}
261 			}
262 			pOperator->Exec(aCodeStack);
263 		}
264 	}
265 	OOperand* pOperand = aCodeStack.top();
266 	aCodeStack.pop();
267 
268 	OSL_ENSURE(aCodeStack.size() == 0, "StackFehler");
269 	OSL_ENSURE(pOperand, "StackFehler");
270 	if (IS_TYPE(OOperandResult,pOperand))
271 		delete pOperand;
272 	else
273 		OSL_ENSURE(0,"Illegal here!");
274 
275 	rParameterColumns = aNewParamColumns;
276 	//	m_aCompiler->setParameterColumns(rParameterColumns);
277 }
278 
279 // -----------------------------------------------------------------------------
280 OOperandAttr* OSQLAnalyzer::createOperandAttr(sal_Int32 _nPos,
281 											  const Reference< XPropertySet>& _xCol,
282 											  const Reference< XNameAccess>& /*_xIndexes*/)
283 {
284 	return new OOperandAttr(static_cast<sal_uInt16>(_nPos),_xCol);
285 }
286 // -----------------------------------------------------------------------------
287 sal_Bool OSQLAnalyzer::hasRestriction() const
288 {
289 	return m_aCompiler->hasCode();
290 }
291 // -----------------------------------------------------------------------------
292 sal_Bool OSQLAnalyzer::hasFunctions() const
293 {
294 	if ( m_bSelectionFirstTime )
295 	{
296 		m_bSelectionFirstTime = sal_False;
297 		for ( ::std::vector< TPredicates >::const_iterator aIter = m_aSelectionEvaluations.begin(); aIter != m_aSelectionEvaluations.end() && !m_bHasSelectionCode ;++aIter)
298 		{
299 			if ( aIter->first.isValid() )
300 				m_bHasSelectionCode = aIter->first->hasCode();
301 		}
302 	}
303 	return m_bHasSelectionCode;;
304 }
305 // -----------------------------------------------------------------------------
306 void OSQLAnalyzer::setSelectionEvaluationResult(OValueRefRow& _pRow,const ::std::vector<sal_Int32>& _rColumnMapping)
307 {
308 	sal_Int32 nPos = 1;
309 	for ( ::std::vector< TPredicates >::iterator aIter = m_aSelectionEvaluations.begin(); aIter != m_aSelectionEvaluations.end();++aIter,++nPos)
310 	{
311 		if ( aIter->second.isValid() )
312 		{
313 			// the first column (index 0) is for convenience only. The first real select column is no 1.
314 			sal_Int32	map = nPos;
315 			if ( nPos < static_cast< sal_Int32 >( _rColumnMapping.size() ) )
316 				map = _rColumnMapping[nPos];
317             if ( map > 0 )
318 			    aIter->second->startSelection( (_pRow->get())[map] );
319 		}
320 	}
321 }
322 // -----------------------------------------------------------------------------
323 void OSQLAnalyzer::dispose()
324 {
325 	m_aCompiler->dispose();
326 	for ( ::std::vector< TPredicates >::iterator aIter = m_aSelectionEvaluations.begin(); aIter != m_aSelectionEvaluations.end();++aIter)
327 	{
328 		if ( aIter->first.isValid() )
329 			aIter->first->dispose();
330 	}
331 }
332 // -----------------------------------------------------------------------------
333 void OSQLAnalyzer::setOrigColumns(const OFileColumns& rCols)
334 {
335 	m_aCompiler->setOrigColumns(rCols);
336 	for ( ::std::vector< TPredicates >::iterator aIter = m_aSelectionEvaluations.begin(); aIter != m_aSelectionEvaluations.end();++aIter)
337 	{
338 		if ( aIter->first.isValid() )
339 			aIter->first->setOrigColumns(rCols);
340 	}
341 }
342 // -----------------------------------------------------------------------------
343