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 
31 #include "KStatement.hxx"
32 #include "KConnection.hxx"
33 #include "KDriver.hxx"
34 #include "KResultSet.hxx"
35 #include "KResultSetMetaData.hxx"
36 #include "kcondition.hxx"
37 #include "korder.hxx"
38 #include "TConnection.hxx"
39 #include <connectivity/dbexception.hxx>
40 #include "resource/kab_res.hrc"
41 #include "resource/sharedresources.hxx"
42 
43 
44 #if OSL_DEBUG_LEVEL > 0
45 # define OUtoCStr( x ) ( ::rtl::OUStringToOString ( (x), RTL_TEXTENCODING_ASCII_US).getStr())
46 #else /* OSL_DEBUG_LEVEL */
47 # define OUtoCStr( x ) ("dummy")
48 #endif /* OSL_DEBUG_LEVEL */
49 
50 using namespace connectivity::kab;
51 using namespace com::sun::star::uno;
52 using namespace com::sun::star::lang;
53 using namespace com::sun::star::beans;
54 using namespace com::sun::star::sdbc;
55 using namespace com::sun::star::sdbcx;
56 using namespace com::sun::star::container;
57 using namespace com::sun::star::io;
58 using namespace com::sun::star::util;
59 
60 namespace
61 {
62     void lcl_throwError(sal_uInt16 _nErrorId)
63     {
64         ::connectivity::SharedResources aResources;
65         const ::rtl::OUString sError( aResources.getResourceString(_nErrorId) );
66         ::dbtools::throwGenericSQLException(sError,NULL);
67     }
68 }
69 
70 IMPLEMENT_SERVICE_INFO(KabStatement, "com.sun.star.sdbc.drivers.KabStatement", "com.sun.star.sdbc.Statement");
71 //------------------------------------------------------------------------------
72 KabCommonStatement::KabCommonStatement(KabConnection* _pConnection )
73 	: KabCommonStatement_BASE(m_aMutex),
74 	OPropertySetHelper(KabCommonStatement_BASE::rBHelper),
75     m_aParser(_pConnection->getDriver()->getMSFactory()),
76     m_aSQLIterator(_pConnection, _pConnection->createCatalog()->getTables(), m_aParser, NULL ),
77 	m_pParseTree(NULL),
78 	m_pConnection(_pConnection),
79     rBHelper(KabCommonStatement_BASE::rBHelper)
80 {
81 	m_pConnection->acquire();
82 }
83 // -----------------------------------------------------------------------------
84 KabCommonStatement::~KabCommonStatement()
85 {
86 }
87 // -----------------------------------------------------------------------------
88 void KabCommonStatement::disposing()
89 {
90 	KabCommonStatement_BASE::disposing();
91 }
92 // -----------------------------------------------------------------------------
93 void KabCommonStatement::resetParameters() const throw(::com::sun::star::sdbc::SQLException)
94 {
95     lcl_throwError(STR_PARA_ONLY_PREPARED);
96 }
97 // -----------------------------------------------------------------------------
98 void KabCommonStatement::getNextParameter(::rtl::OUString &) const throw(::com::sun::star::sdbc::SQLException)
99 {
100 	lcl_throwError(STR_PARA_ONLY_PREPARED);
101 }
102 // -----------------------------------------------------------------------------
103 KabCondition *KabCommonStatement::analyseWhereClause(const OSQLParseNode *pParseNode) const throw(SQLException)
104 {
105 	if (pParseNode->count() == 3)
106 	{
107 		const OSQLParseNode *pLeft = pParseNode->getChild(0),
108 		                    *pMiddle = pParseNode->getChild(1),
109 		                    *pRight = pParseNode->getChild(2);
110 
111 		// WHERE ( ... ) ?
112 		if (SQL_ISPUNCTUATION(pLeft, "(") && SQL_ISPUNCTUATION(pRight, ")"))
113 		{
114 		  	return analyseWhereClause(pMiddle);
115 		}
116 		else if (SQL_ISRULE(pParseNode, comparison_predicate))
117 		{
118 			if (pLeft->isToken() && pRight->isToken())
119 			{
120 				switch (pMiddle->getNodeType())
121 				{
122 					case SQL_NODE_EQUAL:
123 						// WHERE 0 = 1
124 						return new KabConditionConstant(pLeft->getTokenValue() == pRight->getTokenValue());
125 
126 					case SQL_NODE_NOTEQUAL:
127 						// WHERE 0 <> 1
128 						// (might not be correct SQL... don't care, handling anyway)
129 						return new KabConditionConstant(pLeft->getTokenValue() != pRight->getTokenValue());
130 
131 					default:
132                         break;
133 				}
134 			}
135 			else if (SQL_ISRULE(pLeft, column_ref))
136 			{
137 				::rtl::OUString sColumnName,
138 				                sTableRange;
139 
140 				m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
141 
142 				if (pRight->isToken() || SQL_ISRULE(pRight, parameter))
143 				{
144 					::rtl::OUString sMatchString;
145 
146 					if (pRight->isToken())						// WHERE Name = 'Doe'
147 						sMatchString = pRight->getTokenValue();
148 					else if (SQL_ISRULE(pRight, parameter))		// WHERE Name = ?
149 						getNextParameter(sMatchString);
150 
151 					switch (pMiddle->getNodeType())
152 					{
153 						case SQL_NODE_EQUAL:
154 							// WHERE Name = 'Smith'
155 							return new KabConditionEqual(sColumnName, sMatchString);
156 
157 			 			case SQL_NODE_NOTEQUAL:
158 							// WHERE Name <> 'Jones'
159 							return new KabConditionDifferent(sColumnName, sMatchString);
160 
161 						default:
162 							break;
163 					}
164 				}
165 			}
166 		}
167 		else if (SQL_ISRULE(pParseNode, search_condition))
168 		{
169 			if (SQL_ISTOKEN(pMiddle, OR))
170 			{
171 				// WHERE Name = 'Smith' OR Name = 'Jones'
172 				return new KabConditionOr(
173 					analyseWhereClause(pLeft),
174 					analyseWhereClause(pRight));
175 			}
176 		}
177 		else if (SQL_ISRULE(pParseNode, boolean_term))
178 		{
179 			if (SQL_ISTOKEN(pMiddle, AND))
180 			{
181 				// WHERE Name = 'Smith' AND "Given Name" = 'Peter'
182 				return new KabConditionAnd(
183 					analyseWhereClause(pLeft),
184 					analyseWhereClause(pRight));
185 			}
186 		}
187 	}
188 	else if (SQL_ISRULE(pParseNode, test_for_null) || SQL_ISRULE(pParseNode, like_predicate))
189 	{
190         const OSQLParseNode *pLeft = pParseNode->getChild(0);
191         const OSQLParseNode* pPart2 = pParseNode->getChild(1);
192         const OSQLParseNode *pMiddleLeft = pPart2->getChild(0),
193 	                        *pMiddleRight = pPart2->getChild(1),
194 	                        *pRight = pPart2->getChild(2);
195 
196 		if (SQL_ISRULE(pParseNode, test_for_null))
197 		{
198 			if (SQL_ISRULE(pLeft, column_ref) &&
199                             SQL_ISTOKEN(pMiddleLeft, IS) &&
200                             SQL_ISTOKEN(pRight, NULL))
201 			{
202 				::rtl::OUString sColumnName,
203 				                sTableRange;
204 
205 				m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
206 
207 				if (SQL_ISTOKEN(pMiddleRight, NOT))
208 				{
209 					// WHERE "Mobile Phone" IS NOT NULL
210 					return new KabConditionNotNull(sColumnName);
211 				}
212 				else
213 				{
214 					// WHERE "Mobile Phone" IS NULL
215 					return new KabConditionNull(sColumnName);
216 				}
217 			}
218 		}
219 		else if (SQL_ISRULE(pParseNode, like_predicate))
220 		{
221 			if (SQL_ISRULE(pLeft, column_ref))
222 			{
223 				::rtl::OUString sColumnName,
224 				                sTableRange;
225 
226 				m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
227 
228 				if (pMiddleRight->isToken() || SQL_ISRULE(pMiddleRight, parameter))
229 				{
230 					::rtl::OUString sMatchString;
231 
232 					if (pMiddleRight->isToken())					// WHERE Name LIKE 'Sm%'
233 						sMatchString = pMiddleRight->getTokenValue();
234 					else if (SQL_ISRULE(pMiddleRight, parameter))	// WHERE Name LIKE ?
235 						getNextParameter(sMatchString);
236 
237 					return new KabConditionSimilar(sColumnName, sMatchString);
238 				}
239 			}
240 		}
241 	}
242 
243     lcl_throwError(STR_QUERY_TOO_COMPLEX);
244 
245     // Unreachable:
246     OSL_ASSERT(false);
247     return 0;
248 }
249 // -----------------------------------------------------------------------------
250 KabOrder *KabCommonStatement::analyseOrderByClause(const OSQLParseNode *pParseNode) const throw(SQLException)
251 {
252 	if (SQL_ISRULE(pParseNode, ordering_spec_commalist))
253 	{
254 		KabComplexOrder *list = new KabComplexOrder();
255 		sal_uInt32 n = pParseNode->count();
256 
257 		// Iterate through the ordering columns
258 		for (sal_uInt32 i = 0; i < n; i++)
259 		{
260 			list->addOrder
261 				(analyseOrderByClause(pParseNode->getChild(i)));
262 		}
263 
264 		return list;
265 	}
266 	else if (SQL_ISRULE(pParseNode, ordering_spec))
267 	{
268 		if (pParseNode->count() == 2)
269 		{
270 			OSQLParseNode* pColumnRef = pParseNode->getChild(0);
271 			OSQLParseNode* pAscendingDescending = pParseNode->getChild(1);
272 
273 			if (SQL_ISRULE(pColumnRef, column_ref))
274 			{
275 				if (pColumnRef->count() == 3)
276 					pColumnRef = pColumnRef->getChild(2);
277 
278 				if (pColumnRef->count() == 1)
279 				{
280 					::rtl::OUString sColumnName =
281 						pColumnRef->getChild(0)->getTokenValue();
282 					sal_Bool bAscending =
283 						SQL_ISTOKEN(pAscendingDescending, DESC)?
284 						sal_False:
285 						sal_True;
286 
287 					return new KabSimpleOrder(sColumnName, bAscending);
288 				}
289 			}
290 		}
291 	}
292     lcl_throwError(STR_QUERY_TOO_COMPLEX);
293     // Unreachable:
294     OSL_ASSERT(false);
295     return 0;
296 }
297 //------------------------------------------------------------------------------
298 sal_Bool KabCommonStatement::isTableKnown(KabResultSet *pResult) const
299 {
300 	// can handle requests like        SELECT * FROM addresses addresses
301 	// but cannot handle requests like SELECT * FROM addresses persons
302 	if (m_aSQLIterator.getTables().size() != 1)
303 		return sal_False;
304 
305 	if (m_aSQLIterator.getTables().begin()->first != pResult->getMetaData()->getTableName(0))
306 		return sal_False;
307 
308 	return sal_True;
309 }
310 //------------------------------------------------------------------------------
311 void KabCommonStatement::setKabFields(KabResultSet *pResult) const throw(SQLException)
312 {
313 	::vos::ORef<connectivity::OSQLColumns> xColumns;	// selected columns
314 	KabResultSetMetaData *pMeta;				// meta information - holds the list of KAddressBook fields
315 
316 	xColumns = m_aSQLIterator.getSelectColumns();
317 	if (!xColumns.isValid())
318 	{
319         lcl_throwError(STR_INVALID_COLUMN_SELECTION);
320 	}
321 	pMeta = static_cast<KabResultSetMetaData *>(pResult->getMetaData().get());
322 	pMeta->setKabFields(xColumns);
323 }
324 // -------------------------------------------------------------------------
325 void KabCommonStatement::selectAddressees(KabResultSet *pResult) const throw(SQLException)
326 {
327 	const OSQLParseNode *pParseNode;
328 	KabCondition *pCondition;
329 
330 	pParseNode = m_aSQLIterator.getWhereTree();
331 	if (pParseNode != NULL)
332 	{
333 		if (SQL_ISRULE(pParseNode, where_clause))
334 		{
335 			resetParameters();
336 			pParseNode = pParseNode->getChild(1);
337 			pCondition = analyseWhereClause(pParseNode);
338 			if (pCondition->isAlwaysTrue())
339 				pResult->allKabAddressees();
340 			else if (!pCondition->isAlwaysFalse())
341 				pResult->someKabAddressees(pCondition);
342 			delete pCondition;
343 			return;
344 		}
345 	}
346 
347 	// no WHERE clause: get all rows
348 	pResult->allKabAddressees();
349 }
350 // -------------------------------------------------------------------------
351 void KabCommonStatement::sortAddressees(KabResultSet *pResult) const throw(SQLException)
352 {
353 	const OSQLParseNode *pParseNode;
354 	KabOrder *pOrder;
355 
356 	pParseNode = m_aSQLIterator.getOrderTree();
357 	if (pParseNode != NULL)
358 	{
359 		if (SQL_ISRULE(pParseNode, opt_order_by_clause))
360 		{
361 			pParseNode = pParseNode->getChild(2);
362 			pOrder = analyseOrderByClause(pParseNode);
363 			pResult->sortKabAddressees(pOrder);
364 			delete pOrder;
365 		}
366 	}
367 }
368 //-----------------------------------------------------------------------------
369 Any SAL_CALL KabCommonStatement::queryInterface( const Type & rType ) throw(RuntimeException)
370 {
371 	Any aRet = KabCommonStatement_BASE::queryInterface(rType);
372 	if (!aRet.hasValue())
373 		aRet = OPropertySetHelper::queryInterface(rType);
374 	return aRet;
375 }
376 // -------------------------------------------------------------------------
377 Sequence< Type > SAL_CALL KabCommonStatement::getTypes(  ) throw(RuntimeException)
378 {
379 	::cppu::OTypeCollection aTypes(	::getCppuType( (const Reference< XMultiPropertySet > *)0 ),
380 									::getCppuType( (const Reference< XFastPropertySet > *)0 ),
381 									::getCppuType( (const Reference< XPropertySet > *)0 ));
382 
383 	return comphelper::concatSequences(aTypes.getTypes(),KabCommonStatement_BASE::getTypes());
384 }
385 // -------------------------------------------------------------------------
386 void SAL_CALL KabCommonStatement::cancel(  ) throw(RuntimeException)
387 {
388 	::osl::MutexGuard aGuard( m_aMutex );
389 
390 	checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
391 	// cancel the current sql statement
392 }
393 // -------------------------------------------------------------------------
394 void SAL_CALL KabCommonStatement::close(  ) throw(SQLException, RuntimeException)
395 {
396 	{
397 		::osl::MutexGuard aGuard( m_aMutex );
398 		checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
399 
400 	}
401 	dispose();
402 }
403 // -------------------------------------------------------------------------
404 sal_Bool SAL_CALL KabCommonStatement::execute(
405 		const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
406 {
407 	::osl::MutexGuard aGuard( m_aMutex );
408 	checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
409 
410 	Reference< XResultSet > xRS = executeQuery(sql);
411 
412 	return xRS.is();
413 }
414 // -------------------------------------------------------------------------
415 Reference< XResultSet > SAL_CALL KabCommonStatement::executeQuery(
416 		const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
417 {
418 	::osl::MutexGuard aGuard( m_aMutex );
419 	checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
420 
421 OSL_TRACE("KDE Address book - SQL Request: %s", OUtoCStr(sql));
422 
423 	KabResultSet* pResult = new KabResultSet(this);
424 	Reference< XResultSet > xRS = pResult;
425 	::rtl::OUString aErr;
426 
427 	m_pParseTree = m_aParser.parseTree(aErr, sql);
428 	if (m_pParseTree == NULL)
429 		throw SQLException(aErr, *this, aErr, 0, Any());
430 
431 	m_aSQLIterator.setParseTree(m_pParseTree);
432 	m_aSQLIterator.traverseAll();
433 	switch (m_aSQLIterator.getStatementType())
434 	{
435 		case SQL_STATEMENT_SELECT:
436 			if (isTableKnown(pResult))		// FROM which table ?
437 			{
438 				setKabFields(pResult);		// SELECT which columns ?
439 				selectAddressees(pResult);	// WHERE which condition ?
440 				sortAddressees(pResult);	// ORDER BY which columns ?
441 // To be continued: DISTINCT
442 //				    etc...
443 			}
444 			break;
445 
446 		default:
447 // To be continued: UPDATE
448 //				    DELETE
449 //				    etc...
450             lcl_throwError(STR_QUERY_TOO_COMPLEX);
451 	}
452 
453 	return xRS;
454 }
455 // -------------------------------------------------------------------------
456 Reference< XConnection > SAL_CALL KabCommonStatement::getConnection(  ) throw(SQLException, RuntimeException)
457 {
458 	::osl::MutexGuard aGuard( m_aMutex );
459 	checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
460 
461 	// just return our connection here
462 	return (Reference< XConnection >) m_pConnection;
463 }
464 // -------------------------------------------------------------------------
465 sal_Int32 SAL_CALL KabCommonStatement::executeUpdate( const ::rtl::OUString& ) throw(SQLException, RuntimeException)
466 {
467 	::osl::MutexGuard aGuard( m_aMutex );
468 	checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
469 
470 	// the return values gives information about how many rows are affected by executing the sql statement
471 	return 0;
472 }
473 // -------------------------------------------------------------------------
474 Any SAL_CALL KabCommonStatement::getWarnings(  ) throw(SQLException, RuntimeException)
475 {
476 	::osl::MutexGuard aGuard( m_aMutex );
477 	checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
478 
479 	return makeAny(m_aLastWarning);
480 }
481 // -------------------------------------------------------------------------
482 void SAL_CALL KabCommonStatement::clearWarnings(  ) throw(SQLException, RuntimeException)
483 {
484 	::osl::MutexGuard aGuard( m_aMutex );
485 	checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
486 
487 	m_aLastWarning = SQLWarning();
488 }
489 // -------------------------------------------------------------------------
490 ::cppu::IPropertyArrayHelper* KabCommonStatement::createArrayHelper( ) const
491 {
492 	// this properties are defined by the service statement
493 	// they must be in alphabetic order
494 	Sequence< Property > aProps(10);
495 	Property* pProperties = aProps.getArray();
496 	sal_Int32 nPos = 0;
497 	DECL_PROP0(CURSORNAME,	::rtl::OUString);
498 	DECL_BOOL_PROP0(ESCAPEPROCESSING);
499 	DECL_PROP0(FETCHDIRECTION,sal_Int32);
500 	DECL_PROP0(FETCHSIZE,	sal_Int32);
501 	DECL_PROP0(MAXFIELDSIZE,sal_Int32);
502 	DECL_PROP0(MAXROWS,		sal_Int32);
503 	DECL_PROP0(QUERYTIMEOUT,sal_Int32);
504 	DECL_PROP0(RESULTSETCONCURRENCY,sal_Int32);
505 	DECL_PROP0(RESULTSETTYPE,sal_Int32);
506 	DECL_BOOL_PROP0(USEBOOKMARKS);
507 
508 	return new ::cppu::OPropertyArrayHelper(aProps);
509 }
510 // -------------------------------------------------------------------------
511 ::cppu::IPropertyArrayHelper & KabCommonStatement::getInfoHelper()
512 {
513 	return *const_cast<KabCommonStatement*>(this)->getArrayHelper();
514 }
515 // -------------------------------------------------------------------------
516 sal_Bool KabCommonStatement::convertFastPropertyValue(
517 		Any &,
518 		Any &,
519 		sal_Int32,
520 		const Any&) throw (::com::sun::star::lang::IllegalArgumentException)
521 {
522 	sal_Bool bConverted = sal_False;
523 	// here we have to try to convert
524 	return bConverted;
525 }
526 // -------------------------------------------------------------------------
527 void KabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&) throw (Exception)
528 {
529 	// set the value to whatever is nescessary
530 	switch (nHandle)
531 	{
532 		case PROPERTY_ID_QUERYTIMEOUT:
533 		case PROPERTY_ID_MAXFIELDSIZE:
534 		case PROPERTY_ID_MAXROWS:
535 		case PROPERTY_ID_CURSORNAME:
536 		case PROPERTY_ID_RESULTSETCONCURRENCY:
537 		case PROPERTY_ID_RESULTSETTYPE:
538 		case PROPERTY_ID_FETCHDIRECTION:
539 		case PROPERTY_ID_FETCHSIZE:
540 		case PROPERTY_ID_ESCAPEPROCESSING:
541 		case PROPERTY_ID_USEBOOKMARKS:
542 		default:
543 			;
544 	}
545 }
546 // -------------------------------------------------------------------------
547 void KabCommonStatement::getFastPropertyValue(Any&,sal_Int32 nHandle) const
548 {
549 	switch (nHandle)
550 	{
551 		case PROPERTY_ID_QUERYTIMEOUT:
552 		case PROPERTY_ID_MAXFIELDSIZE:
553 		case PROPERTY_ID_MAXROWS:
554 		case PROPERTY_ID_CURSORNAME:
555 		case PROPERTY_ID_RESULTSETCONCURRENCY:
556 		case PROPERTY_ID_RESULTSETTYPE:
557 		case PROPERTY_ID_FETCHDIRECTION:
558 		case PROPERTY_ID_FETCHSIZE:
559 		case PROPERTY_ID_ESCAPEPROCESSING:
560 		case PROPERTY_ID_USEBOOKMARKS:
561 		default:
562 			;
563 	}
564 }
565 // -----------------------------------------------------------------------------
566 void SAL_CALL KabCommonStatement::acquire() throw()
567 {
568 	KabCommonStatement_BASE::acquire();
569 }
570 // -----------------------------------------------------------------------------
571 void SAL_CALL KabCommonStatement::release() throw()
572 {
573 	KabCommonStatement_BASE::release();
574 }
575 // -----------------------------------------------------------------------------
576 Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL KabCommonStatement::getPropertySetInfo(  ) throw(RuntimeException)
577 {
578 	return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
579 }
580 // -----------------------------------------------------------------------------
581 KabStatement::KabStatement(KabConnection* _pConnection)
582 	: KabStatement_BASE(_pConnection)
583 {
584 }
585