Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / connectivity / source / drivers / kab / KStatement.cxx
blob5bf7d8e6a4271dc761a603f12d5eb3b5f4f6b8ca
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include "KStatement.hxx"
22 #include "KConnection.hxx"
23 #include "KDriver.hxx"
24 #include "KResultSet.hxx"
25 #include "KResultSetMetaData.hxx"
26 #include "kcondition.hxx"
27 #include "korder.hxx"
28 #include "TConnection.hxx"
29 #include <connectivity/dbexception.hxx>
30 #include "resource/kab_res.hrc"
31 #include "resource/sharedresources.hxx"
34 #if OSL_DEBUG_LEVEL > 0
35 # define OUtoCStr( x ) ( OUStringToOString ( (x), RTL_TEXTENCODING_ASCII_US).getStr())
36 #else /* OSL_DEBUG_LEVEL */
37 # define OUtoCStr( x ) ("dummy")
38 #endif /* OSL_DEBUG_LEVEL */
40 using namespace connectivity::kab;
41 using namespace com::sun::star::uno;
42 using namespace com::sun::star::lang;
43 using namespace com::sun::star::beans;
44 using namespace com::sun::star::sdbc;
45 using namespace com::sun::star::sdbcx;
46 using namespace com::sun::star::container;
47 using namespace com::sun::star::io;
48 using namespace com::sun::star::util;
50 namespace
52 void lcl_throwError(sal_uInt16 _nErrorId)
54 ::connectivity::SharedResources aResources;
55 const OUString sError( aResources.getResourceString(_nErrorId) );
56 ::dbtools::throwGenericSQLException(sError,NULL);
60 IMPLEMENT_SERVICE_INFO(KabStatement, "com.sun.star.sdbc.drivers.KabStatement", "com.sun.star.sdbc.Statement");
62 KabCommonStatement::KabCommonStatement(KabConnection* _pConnection )
63 : KabCommonStatement_BASE(m_aMutex),
64 OPropertySetHelper(KabCommonStatement_BASE::rBHelper),
65 m_aParser(_pConnection->getDriver()->getComponentContext()),
66 m_aSQLIterator(_pConnection, _pConnection->createCatalog()->getTables(), m_aParser, NULL ),
67 m_pParseTree(NULL),
68 m_pConnection(_pConnection),
69 rBHelper(KabCommonStatement_BASE::rBHelper)
71 m_pConnection->acquire();
74 KabCommonStatement::~KabCommonStatement()
78 void KabCommonStatement::disposing()
80 KabCommonStatement_BASE::disposing();
83 void KabCommonStatement::resetParameters() const throw(::com::sun::star::sdbc::SQLException)
85 lcl_throwError(STR_PARA_ONLY_PREPARED);
88 void KabCommonStatement::getNextParameter(OUString &) const throw(::com::sun::star::sdbc::SQLException)
90 lcl_throwError(STR_PARA_ONLY_PREPARED);
93 KabCondition *KabCommonStatement::analyseWhereClause(const OSQLParseNode *pParseNode) const throw(SQLException)
95 if (pParseNode->count() == 3)
97 const OSQLParseNode *pLeft = pParseNode->getChild(0),
98 *pMiddle = pParseNode->getChild(1),
99 *pRight = pParseNode->getChild(2);
101 // WHERE ( ... ) ?
102 if (SQL_ISPUNCTUATION(pLeft, "(") && SQL_ISPUNCTUATION(pRight, ")"))
104 return analyseWhereClause(pMiddle);
106 else if (SQL_ISRULE(pParseNode, comparison_predicate))
108 if (pLeft->isToken() && pRight->isToken())
110 switch (pMiddle->getNodeType())
112 case SQL_NODE_EQUAL:
113 // WHERE 0 = 1
114 return new KabConditionConstant(pLeft->getTokenValue() == pRight->getTokenValue());
116 case SQL_NODE_NOTEQUAL:
117 // WHERE 0 <> 1
118 // (might not be correct SQL... don't care, handling anyway)
119 return new KabConditionConstant(pLeft->getTokenValue() != pRight->getTokenValue());
121 default:
122 break;
125 else if (SQL_ISRULE(pLeft, column_ref))
127 OUString sColumnName,
128 sTableRange;
130 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
132 if (pRight->isToken() || SQL_ISRULE(pRight, parameter))
134 OUString sMatchString;
136 if (pRight->isToken()) // WHERE Name = 'Doe'
137 sMatchString = pRight->getTokenValue();
138 else if (SQL_ISRULE(pRight, parameter)) // WHERE Name = ?
139 getNextParameter(sMatchString);
141 switch (pMiddle->getNodeType())
143 case SQL_NODE_EQUAL:
144 // WHERE Name = 'Smith'
145 return new KabConditionEqual(sColumnName, sMatchString);
147 case SQL_NODE_NOTEQUAL:
148 // WHERE Name <> 'Jones'
149 return new KabConditionDifferent(sColumnName, sMatchString);
151 default:
152 break;
157 else if (SQL_ISRULE(pParseNode, search_condition))
159 if (SQL_ISTOKEN(pMiddle, OR))
161 // WHERE Name = 'Smith' OR Name = 'Jones'
162 return new KabConditionOr(
163 analyseWhereClause(pLeft),
164 analyseWhereClause(pRight));
167 else if (SQL_ISRULE(pParseNode, boolean_term))
169 if (SQL_ISTOKEN(pMiddle, AND))
171 // WHERE Name = 'Smith' AND "Given Name" = 'Peter'
172 return new KabConditionAnd(
173 analyseWhereClause(pLeft),
174 analyseWhereClause(pRight));
178 else if (SQL_ISRULE(pParseNode, test_for_null) || SQL_ISRULE(pParseNode, like_predicate))
180 const OSQLParseNode *pLeft = pParseNode->getChild(0);
181 const OSQLParseNode* pPart2 = pParseNode->getChild(1);
182 const OSQLParseNode *pMiddleLeft = pPart2->getChild(0),
183 *pMiddleRight = pPart2->getChild(1),
184 *pRight = pPart2->getChild(2);
186 if (SQL_ISRULE(pParseNode, test_for_null))
188 if (SQL_ISRULE(pLeft, column_ref) &&
189 SQL_ISTOKEN(pMiddleLeft, IS) &&
190 SQL_ISTOKEN(pRight, NULL))
192 OUString sColumnName,
193 sTableRange;
195 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
197 if (SQL_ISTOKEN(pMiddleRight, NOT))
199 // WHERE "Mobile Phone" IS NOT NULL
200 return new KabConditionNotNull(sColumnName);
202 else
204 // WHERE "Mobile Phone" IS NULL
205 return new KabConditionNull(sColumnName);
209 else if (SQL_ISRULE(pParseNode, like_predicate))
211 if (SQL_ISRULE(pLeft, column_ref))
213 OUString sColumnName,
214 sTableRange;
216 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
218 if (pMiddleRight->isToken() || SQL_ISRULE(pMiddleRight, parameter))
220 OUString sMatchString;
222 if (pMiddleRight->isToken()) // WHERE Name LIKE 'Sm%'
223 sMatchString = pMiddleRight->getTokenValue();
224 else if (SQL_ISRULE(pMiddleRight, parameter)) // WHERE Name LIKE ?
225 getNextParameter(sMatchString);
227 return new KabConditionSimilar(sColumnName, sMatchString);
233 lcl_throwError(STR_QUERY_TOO_COMPLEX);
235 // Unreachable:
236 OSL_ASSERT(false);
237 return 0;
240 KabOrder *KabCommonStatement::analyseOrderByClause(const OSQLParseNode *pParseNode) const throw(SQLException)
242 if (SQL_ISRULE(pParseNode, ordering_spec_commalist))
244 KabComplexOrder *list = new KabComplexOrder();
245 sal_uInt32 n = pParseNode->count();
247 // Iterate through the ordering columns
248 for (sal_uInt32 i = 0; i < n; i++)
250 list->addOrder
251 (analyseOrderByClause(pParseNode->getChild(i)));
254 return list;
256 else if (SQL_ISRULE(pParseNode, ordering_spec))
258 if (pParseNode->count() == 2)
260 OSQLParseNode* pColumnRef = pParseNode->getChild(0);
261 OSQLParseNode* pAscendingDescending = pParseNode->getChild(1);
263 if (SQL_ISRULE(pColumnRef, column_ref))
265 if (pColumnRef->count() == 3)
266 pColumnRef = pColumnRef->getChild(2);
268 if (pColumnRef->count() == 1)
270 OUString sColumnName =
271 pColumnRef->getChild(0)->getTokenValue();
272 sal_Bool bAscending =
273 SQL_ISTOKEN(pAscendingDescending, DESC)?
274 sal_False:
275 sal_True;
277 return new KabSimpleOrder(sColumnName, bAscending);
282 lcl_throwError(STR_QUERY_TOO_COMPLEX);
283 // Unreachable:
284 OSL_ASSERT(false);
285 return 0;
288 sal_Bool KabCommonStatement::isTableKnown(KabResultSet *pResult) const
290 // can handle requests like SELECT * FROM addresses addresses
291 // but cannot handle requests like SELECT * FROM addresses persons
292 if (m_aSQLIterator.getTables().size() != 1)
293 return sal_False;
295 if (m_aSQLIterator.getTables().begin()->first != pResult->getMetaData()->getTableName(0))
296 return sal_False;
298 return sal_True;
301 void KabCommonStatement::setKabFields(KabResultSet *pResult) const throw(SQLException)
303 ::rtl::Reference<connectivity::OSQLColumns> xColumns; // selected columns
305 xColumns = m_aSQLIterator.getSelectColumns();
306 if (!xColumns.is())
308 lcl_throwError(STR_INVALID_COLUMN_SELECTION);
310 pResult->getKabMetaData()->setKabFields(xColumns);
313 void KabCommonStatement::selectAddressees(KabResultSet *pResult) const throw(SQLException)
315 const OSQLParseNode *pParseNode;
317 pParseNode = m_aSQLIterator.getWhereTree();
318 if (pParseNode != NULL)
320 if (SQL_ISRULE(pParseNode, where_clause))
322 resetParameters();
323 pParseNode = pParseNode->getChild(1);
324 KabCondition *pCondition = analyseWhereClause(pParseNode);
325 if (pCondition->isAlwaysTrue())
326 pResult->allKabAddressees();
327 else if (!pCondition->isAlwaysFalse())
328 pResult->someKabAddressees(pCondition);
329 delete pCondition;
330 return;
334 // no WHERE clause: get all rows
335 pResult->allKabAddressees();
338 void KabCommonStatement::sortAddressees(KabResultSet *pResult) const throw(SQLException)
340 const OSQLParseNode *pParseNode;
342 pParseNode = m_aSQLIterator.getOrderTree();
343 if (pParseNode != NULL)
345 if (SQL_ISRULE(pParseNode, opt_order_by_clause))
347 pParseNode = pParseNode->getChild(2);
348 KabOrder *pOrder = analyseOrderByClause(pParseNode);
349 pResult->sortKabAddressees(pOrder);
350 delete pOrder;
355 Any SAL_CALL KabCommonStatement::queryInterface( const Type & rType ) throw(RuntimeException, std::exception)
357 Any aRet = KabCommonStatement_BASE::queryInterface(rType);
358 if (!aRet.hasValue())
359 aRet = OPropertySetHelper::queryInterface(rType);
360 return aRet;
363 Sequence< Type > SAL_CALL KabCommonStatement::getTypes( ) throw(RuntimeException, std::exception)
365 ::cppu::OTypeCollection aTypes( ::getCppuType( (const Reference< XMultiPropertySet > *)0 ),
366 ::getCppuType( (const Reference< XFastPropertySet > *)0 ),
367 ::getCppuType( (const Reference< XPropertySet > *)0 ));
369 return comphelper::concatSequences(aTypes.getTypes(),KabCommonStatement_BASE::getTypes());
372 void SAL_CALL KabCommonStatement::cancel( ) throw(RuntimeException, std::exception)
374 ::osl::MutexGuard aGuard( m_aMutex );
376 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
377 // cancel the current sql statement
380 void SAL_CALL KabCommonStatement::close( ) throw(SQLException, RuntimeException, std::exception)
383 ::osl::MutexGuard aGuard( m_aMutex );
384 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
387 dispose();
390 sal_Bool SAL_CALL KabCommonStatement::execute(
391 const OUString& sql ) throw(SQLException, RuntimeException, std::exception)
393 ::osl::MutexGuard aGuard( m_aMutex );
394 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
396 Reference< XResultSet > xRS = executeQuery(sql);
398 return xRS.is();
401 Reference< XResultSet > SAL_CALL KabCommonStatement::executeQuery(
402 const OUString& sql ) throw(SQLException, RuntimeException, std::exception)
404 ::osl::MutexGuard aGuard( m_aMutex );
405 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
407 OSL_TRACE("KDE Address book - SQL Request: %s", OUtoCStr(sql));
409 KabResultSet* pResult = new KabResultSet(this);
410 Reference< XResultSet > xRS = pResult;
411 OUString aErr;
413 m_pParseTree = m_aParser.parseTree(aErr, sql);
414 if (m_pParseTree == NULL)
415 throw SQLException(aErr, *this, aErr, 0, Any());
417 m_aSQLIterator.setParseTree(m_pParseTree);
418 m_aSQLIterator.traverseAll();
419 switch (m_aSQLIterator.getStatementType())
421 case SQL_STATEMENT_SELECT:
422 if (isTableKnown(pResult)) // FROM which table ?
424 setKabFields(pResult); // SELECT which columns ?
425 selectAddressees(pResult); // WHERE which condition ?
426 sortAddressees(pResult); // ORDER BY which columns ?
427 // To be continued: DISTINCT
428 // etc...
430 break;
432 default:
433 // To be continued: UPDATE
434 // DELETE
435 // etc...
436 lcl_throwError(STR_QUERY_TOO_COMPLEX);
439 return xRS;
442 Reference< XConnection > SAL_CALL KabCommonStatement::getConnection( ) throw(SQLException, RuntimeException, std::exception)
444 ::osl::MutexGuard aGuard( m_aMutex );
445 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
447 // just return our connection here
448 return (Reference< XConnection >) m_pConnection;
451 sal_Int32 SAL_CALL KabCommonStatement::executeUpdate( const OUString& ) throw(SQLException, RuntimeException, std::exception)
453 ::osl::MutexGuard aGuard( m_aMutex );
454 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
456 // the return values gives information about how many rows are affected by executing the sql statement
457 return 0;
460 Any SAL_CALL KabCommonStatement::getWarnings( ) throw(SQLException, RuntimeException, std::exception)
462 ::osl::MutexGuard aGuard( m_aMutex );
463 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
465 return makeAny(m_aLastWarning);
468 void SAL_CALL KabCommonStatement::clearWarnings( ) throw(SQLException, RuntimeException, std::exception)
470 ::osl::MutexGuard aGuard( m_aMutex );
471 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
473 m_aLastWarning = SQLWarning();
476 ::cppu::IPropertyArrayHelper* KabCommonStatement::createArrayHelper( ) const
478 // this properties are defined by the service statement
479 // they must be in alphabetic order
480 Sequence< Property > aProps(10);
481 Property* pProperties = aProps.getArray();
482 sal_Int32 nPos = 0;
483 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
484 PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0);
485 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
486 PROPERTY_ID_ESCAPEPROCESSING, ::getBooleanCppuType(), 0);
487 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
488 PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0);
489 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
490 PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0);
491 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
492 PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0);
493 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
494 PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0);
495 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
496 PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0);
497 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
498 PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0);
499 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
500 PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0);
501 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS),
502 PROPERTY_ID_USEBOOKMARKS, ::getBooleanCppuType(), 0);
504 return new ::cppu::OPropertyArrayHelper(aProps);
507 ::cppu::IPropertyArrayHelper & KabCommonStatement::getInfoHelper()
509 return *const_cast<KabCommonStatement*>(this)->getArrayHelper();
512 sal_Bool KabCommonStatement::convertFastPropertyValue(
513 Any &,
514 Any &,
515 sal_Int32,
516 const Any&) throw (::com::sun::star::lang::IllegalArgumentException)
518 sal_Bool bConverted = sal_False;
519 // here we have to try to convert
520 return bConverted;
523 void KabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&) throw (Exception, std::exception)
525 // set the value to whatever is necessary
526 switch (nHandle)
528 case PROPERTY_ID_QUERYTIMEOUT:
529 case PROPERTY_ID_MAXFIELDSIZE:
530 case PROPERTY_ID_MAXROWS:
531 case PROPERTY_ID_CURSORNAME:
532 case PROPERTY_ID_RESULTSETCONCURRENCY:
533 case PROPERTY_ID_RESULTSETTYPE:
534 case PROPERTY_ID_FETCHDIRECTION:
535 case PROPERTY_ID_FETCHSIZE:
536 case PROPERTY_ID_ESCAPEPROCESSING:
537 case PROPERTY_ID_USEBOOKMARKS:
538 default:
543 void KabCommonStatement::getFastPropertyValue(Any&,sal_Int32 nHandle) const
545 switch (nHandle)
547 case PROPERTY_ID_QUERYTIMEOUT:
548 case PROPERTY_ID_MAXFIELDSIZE:
549 case PROPERTY_ID_MAXROWS:
550 case PROPERTY_ID_CURSORNAME:
551 case PROPERTY_ID_RESULTSETCONCURRENCY:
552 case PROPERTY_ID_RESULTSETTYPE:
553 case PROPERTY_ID_FETCHDIRECTION:
554 case PROPERTY_ID_FETCHSIZE:
555 case PROPERTY_ID_ESCAPEPROCESSING:
556 case PROPERTY_ID_USEBOOKMARKS:
557 default:
562 void SAL_CALL KabCommonStatement::acquire() throw()
564 KabCommonStatement_BASE::acquire();
567 void SAL_CALL KabCommonStatement::release() throw()
569 KabCommonStatement_BASE::release();
572 Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL KabCommonStatement::getPropertySetInfo( ) throw(RuntimeException, std::exception)
574 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
577 KabStatement::KabStatement(KabConnection* _pConnection)
578 : KabStatement_BASE(_pConnection)
582 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */