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