Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / connectivity / source / drivers / macab / MacabStatement.cxx
blob87b2799333230961ab3bed1e400f11b69933537c
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 "MacabStatement.hxx"
22 #include "MacabConnection.hxx"
23 #include "MacabAddressBook.hxx"
24 #include "MacabDriver.hxx"
25 #include "MacabResultSet.hxx"
26 #include "MacabResultSetMetaData.hxx"
27 #include "macabcondition.hxx"
28 #include "macaborder.hxx"
29 #include "TConnection.hxx"
30 #include <connectivity/dbexception.hxx>
31 #include "resource/sharedresources.hxx"
32 #include "resource/macab_res.hrc"
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::macab;
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 connectivity
52 namespace macab
54 void impl_throwError(sal_uInt16 _nErrorId)
56 ::connectivity::SharedResources aResources;
57 const OUString sError( aResources.getResourceString(_nErrorId) );
58 ::dbtools::throwGenericSQLException(sError,NULL);
63 IMPLEMENT_SERVICE_INFO(MacabStatement, "com.sun.star.sdbc.drivers.MacabStatement", "com.sun.star.sdbc.Statement");
65 MacabCommonStatement::MacabCommonStatement(MacabConnection* _pConnection )
66 : MacabCommonStatement_BASE(m_aMutex),
67 OPropertySetHelper(MacabCommonStatement_BASE::rBHelper),
68 m_aParser(_pConnection->getDriver()->getComponentContext()),
69 m_aSQLIterator(_pConnection, _pConnection->createCatalog()->getTables(), m_aParser, NULL ),
70 m_pParseTree(NULL),
71 m_pConnection(_pConnection),
72 rBHelper(MacabCommonStatement_BASE::rBHelper)
74 m_pConnection->acquire();
77 MacabCommonStatement::~MacabCommonStatement()
81 void MacabCommonStatement::disposing()
83 MacabCommonStatement_BASE::disposing();
86 void MacabCommonStatement::resetParameters() const throw(::com::sun::star::sdbc::SQLException)
88 impl_throwError(STR_PARA_ONLY_PREPARED);
91 void MacabCommonStatement::getNextParameter(OUString &) const throw(::com::sun::star::sdbc::SQLException)
93 impl_throwError(STR_PARA_ONLY_PREPARED);
96 MacabCondition *MacabCommonStatement::analyseWhereClause(const OSQLParseNode *pParseNode) const throw(SQLException)
98 if (pParseNode->count() == 3)
100 const OSQLParseNode *pLeft = pParseNode->getChild(0),
101 *pMiddle = pParseNode->getChild(1),
102 *pRight = pParseNode->getChild(2);
104 // WHERE ( ... ) ?
105 if (SQL_ISPUNCTUATION(pLeft, "(") && SQL_ISPUNCTUATION(pRight, ")"))
107 return analyseWhereClause(pMiddle);
109 else if (SQL_ISRULE(pParseNode, comparison_predicate))
111 if (pLeft->isToken() && pRight->isToken())
113 switch (pMiddle->getNodeType())
115 case SQL_NODE_EQUAL:
116 // WHERE 0 = 1
117 return new MacabConditionConstant(pLeft->getTokenValue() == pRight->getTokenValue());
119 case SQL_NODE_NOTEQUAL:
120 // WHERE 0 <> 1
121 // (might not be correct SQL... don't care, handling anyway)
122 return new MacabConditionConstant(pLeft->getTokenValue() != pRight->getTokenValue());
124 default:
125 break;
128 else if (SQL_ISRULE(pLeft, column_ref))
130 OUString sColumnName,
131 sTableRange;
133 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
135 if (pRight->isToken() || SQL_ISRULE(pRight, parameter))
137 OUString sMatchString;
139 if (pRight->isToken()) // WHERE Name = 'Doe'
140 sMatchString = pRight->getTokenValue();
141 else if (SQL_ISRULE(pRight, parameter)) // WHERE Name = ?
142 getNextParameter(sMatchString);
144 switch (pMiddle->getNodeType())
146 case SQL_NODE_EQUAL:
147 // WHERE Name = 'Smith'
148 return new MacabConditionEqual(m_pHeader, sColumnName, sMatchString);
150 case SQL_NODE_NOTEQUAL:
151 // WHERE Name <> 'Jones'
152 return new MacabConditionDifferent(m_pHeader, sColumnName, sMatchString);
154 default:
155 break;
160 else if (SQL_ISRULE(pParseNode, search_condition))
162 if (SQL_ISTOKEN(pMiddle, OR))
164 // WHERE Name = 'Smith' OR Name = 'Jones'
165 return new MacabConditionOr(
166 analyseWhereClause(pLeft),
167 analyseWhereClause(pRight));
170 else if (SQL_ISRULE(pParseNode, boolean_term))
172 if (SQL_ISTOKEN(pMiddle, AND))
174 // WHERE Name = 'Smith' AND "Given Name" = 'Peter'
175 return new MacabConditionAnd(
176 analyseWhereClause(pLeft),
177 analyseWhereClause(pRight));
181 else if (SQL_ISRULE(pParseNode, test_for_null) || SQL_ISRULE(pParseNode, like_predicate))
183 const OSQLParseNode *pLeft = pParseNode->getChild(0);
184 const OSQLParseNode* pPart2 = pParseNode->getChild(1);
185 const OSQLParseNode *pMiddleLeft = pPart2->getChild(0),
186 *pMiddleRight = pPart2->getChild(1),
187 *pRight = pPart2->getChild(2);
189 if (SQL_ISRULE(pParseNode, test_for_null))
191 if (SQL_ISRULE(pLeft, column_ref) &&
192 SQL_ISTOKEN(pMiddleLeft, IS) &&
193 SQL_ISTOKEN(pRight, NULL))
195 OUString sColumnName,
196 sTableRange;
198 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
200 if (SQL_ISTOKEN(pMiddleRight, NOT))
202 // WHERE "Mobile Phone" IS NOT NULL
203 return new MacabConditionNotNull(m_pHeader, sColumnName);
205 else
207 // WHERE "Mobile Phone" IS NULL
208 return new MacabConditionNull(m_pHeader, sColumnName);
212 else if (SQL_ISRULE(pParseNode, like_predicate))
214 if (SQL_ISRULE(pLeft, column_ref))
216 OUString sColumnName,
217 sTableRange;
219 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
221 if (pMiddleRight->isToken() || SQL_ISRULE(pMiddleRight, parameter))
223 OUString sMatchString;
225 if (pMiddleRight->isToken()) // WHERE Name LIKE 'Sm%'
226 sMatchString = pMiddleRight->getTokenValue();
227 else if (SQL_ISRULE(pMiddleRight, parameter)) // WHERE Name LIKE ?
228 getNextParameter(sMatchString);
230 return new MacabConditionSimilar(m_pHeader, sColumnName, sMatchString);
235 impl_throwError(STR_QUERY_TOO_COMPLEX);
236 // Unreachable:
237 OSL_ASSERT(false);
238 return 0;
241 MacabOrder *MacabCommonStatement::analyseOrderByClause(const OSQLParseNode *pParseNode) const throw(SQLException)
243 if (SQL_ISRULE(pParseNode, ordering_spec_commalist))
245 MacabComplexOrder *list = new MacabComplexOrder();
246 sal_uInt32 n = pParseNode->count();
248 // Iterate through the ordering columns
249 for (sal_uInt32 i = 0; i < n; i++)
251 list->addOrder
252 (analyseOrderByClause(pParseNode->getChild(i)));
255 return list;
257 else if (SQL_ISRULE(pParseNode, ordering_spec))
259 if (pParseNode->count() == 2)
261 OSQLParseNode* pColumnRef = pParseNode->getChild(0);
262 OSQLParseNode* pAscendingDescending = pParseNode->getChild(1);
264 if (SQL_ISRULE(pColumnRef, column_ref))
266 if (pColumnRef->count() == 3)
267 pColumnRef = pColumnRef->getChild(2);
269 if (pColumnRef->count() == 1)
271 OUString sColumnName =
272 pColumnRef->getChild(0)->getTokenValue();
273 sal_Bool bAscending =
274 SQL_ISTOKEN(pAscendingDescending, DESC)?
275 sal_False:
276 sal_True;
278 return new MacabSimpleOrder(m_pHeader, sColumnName, bAscending);
283 impl_throwError(STR_QUERY_TOO_COMPLEX);
284 // Unreachable:
285 OSL_ASSERT(false);
286 return 0;
289 OUString MacabCommonStatement::getTableName() const
291 const OSQLTables& xTabs = m_aSQLIterator.getTables();
293 if( xTabs.empty() )
294 return OUString();
296 // can only deal with one table at a time
297 if(xTabs.size() > 1 || m_aSQLIterator.hasErrors() )
298 return OUString();
300 return xTabs.begin()->first;
303 void MacabCommonStatement::setMacabFields(MacabResultSet *pResult) const throw(SQLException)
305 ::rtl::Reference<connectivity::OSQLColumns> xColumns; // selected columns
306 MacabResultSetMetaData *pMeta; // meta information - holds the list of AddressBook fields
308 xColumns = m_aSQLIterator.getSelectColumns();
309 if (!xColumns.is())
311 ::connectivity::SharedResources aResources;
312 const OUString sError( aResources.getResourceString(
313 STR_INVALID_COLUMN_SELECTION
314 ) );
315 ::dbtools::throwGenericSQLException(sError,NULL);
317 pMeta = static_cast<MacabResultSetMetaData *>(pResult->getMetaData().get());
318 pMeta->setMacabFields(xColumns);
321 void MacabCommonStatement::selectRecords(MacabResultSet *pResult) const throw(SQLException)
323 const OSQLParseNode *pParseNode;
325 pParseNode = m_aSQLIterator.getWhereTree();
326 if (pParseNode != NULL)
328 if (SQL_ISRULE(pParseNode, where_clause))
330 // Since we don't support parameters, don't reset them. If we ever
331 // support them, uncomment this line and fix resetParameters.
332 //resetParameters();
333 pParseNode = pParseNode->getChild(1);
334 MacabCondition *pCondition = analyseWhereClause(pParseNode);
335 if (pCondition->isAlwaysTrue())
336 pResult->allMacabRecords();
337 else if (!pCondition->isAlwaysFalse())
338 pResult->someMacabRecords(pCondition);
339 delete pCondition;
340 return;
344 // no WHERE clause: get all rows
345 pResult->allMacabRecords();
348 void MacabCommonStatement::sortRecords(MacabResultSet *pResult) const throw(SQLException)
350 const OSQLParseNode *pParseNode;
352 pParseNode = m_aSQLIterator.getOrderTree();
353 if (pParseNode != NULL)
355 if (SQL_ISRULE(pParseNode, opt_order_by_clause))
357 pParseNode = pParseNode->getChild(2);
358 MacabOrder *pOrder = analyseOrderByClause(pParseNode);
359 pResult->sortMacabRecords(pOrder);
360 delete pOrder;
365 Any SAL_CALL MacabCommonStatement::queryInterface( const Type & rType ) throw(RuntimeException, std::exception)
367 Any aRet = MacabCommonStatement_BASE::queryInterface(rType);
368 if (!aRet.hasValue())
369 aRet = OPropertySetHelper::queryInterface(rType);
370 return aRet;
373 Sequence< Type > SAL_CALL MacabCommonStatement::getTypes( ) throw(RuntimeException, std::exception)
375 ::cppu::OTypeCollection aTypes( ::getCppuType( (const Reference< XMultiPropertySet > *)0 ),
376 ::getCppuType( (const Reference< XFastPropertySet > *)0 ),
377 ::getCppuType( (const Reference< XPropertySet > *)0 ));
379 return comphelper::concatSequences(aTypes.getTypes(),MacabCommonStatement_BASE::getTypes());
382 void SAL_CALL MacabCommonStatement::cancel( ) throw(RuntimeException)
384 ::osl::MutexGuard aGuard( m_aMutex );
386 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
387 // cancel the current sql statement
390 void SAL_CALL MacabCommonStatement::close( ) throw(SQLException, RuntimeException)
393 ::osl::MutexGuard aGuard( m_aMutex );
394 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
397 dispose();
400 sal_Bool SAL_CALL MacabCommonStatement::execute(
401 const OUString& sql ) throw(SQLException, RuntimeException)
403 ::osl::MutexGuard aGuard( m_aMutex );
404 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
406 Reference< XResultSet > xRS = executeQuery(sql);
408 return xRS.is();
411 Reference< XResultSet > SAL_CALL MacabCommonStatement::executeQuery(
412 const OUString& sql ) throw(SQLException, RuntimeException)
414 ::osl::MutexGuard aGuard( m_aMutex );
415 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
417 OSL_TRACE("Mac OS Address book - SQL Request: %s", OUtoCStr(sql));
419 MacabResultSet* pResult = new MacabResultSet(this);
420 Reference< XResultSet > xRS = pResult;
421 OUString aErr;
423 m_pParseTree = m_aParser.parseTree(aErr, sql);
424 if (m_pParseTree == NULL)
425 throw SQLException(aErr, *this, aErr, 0, Any());
427 m_aSQLIterator.setParseTree(m_pParseTree);
428 m_aSQLIterator.traverseAll();
429 switch (m_aSQLIterator.getStatementType())
431 case SQL_STATEMENT_SELECT:
433 OUString sTableName = getTableName(); // FROM which table ?
434 if (sTableName.getLength() != 0) // a match
436 MacabRecords *aRecords;
437 aRecords = m_pConnection->getAddressBook()->getMacabRecords(sTableName);
439 // In case, somehow, we don't have anything with the name m_sTableName
440 if(aRecords == NULL)
442 impl_throwError(STR_NO_TABLE);
444 else
446 m_pHeader = aRecords->getHeader();
448 pResult->setTableName(sTableName);
450 setMacabFields(pResult); // SELECT which columns ?
451 selectRecords(pResult); // WHERE which condition ?
452 sortRecords(pResult); // ORDER BY which columns ?
454 // To be continued: DISTINCT
455 // etc...
458 break;
460 default:
461 // To be continued: UPDATE
462 // DELETE
463 // etc...
464 impl_throwError(STR_QUERY_TOO_COMPLEX);
467 m_xResultSet = Reference<XResultSet>(pResult);
468 return xRS;
471 Reference< XConnection > SAL_CALL MacabCommonStatement::getConnection( ) throw(SQLException, RuntimeException)
473 ::osl::MutexGuard aGuard( m_aMutex );
474 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
476 // just return our connection here
477 return (Reference< XConnection >) m_pConnection;
480 sal_Int32 SAL_CALL MacabCommonStatement::executeUpdate( const OUString& ) throw(SQLException, RuntimeException)
482 ::osl::MutexGuard aGuard( m_aMutex );
483 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
485 // the return values gives information about how many rows are affected by executing the sql statement
486 return 0;
489 Any SAL_CALL MacabCommonStatement::getWarnings( ) throw(SQLException, RuntimeException)
491 ::osl::MutexGuard aGuard( m_aMutex );
492 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
494 return makeAny(m_aLastWarning);
497 void SAL_CALL MacabCommonStatement::clearWarnings( ) throw(SQLException, RuntimeException)
499 ::osl::MutexGuard aGuard( m_aMutex );
500 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed);
502 m_aLastWarning = SQLWarning();
505 ::cppu::IPropertyArrayHelper* MacabCommonStatement::createArrayHelper( ) const
507 // this properties are defined by the service statement
508 // they must be in alphabetic order
509 Sequence< Property > aProps(10);
510 Property* pProperties = aProps.getArray();
511 sal_Int32 nPos = 0;
512 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
513 PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0);
514 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
515 PROPERTY_ID_ESCAPEPROCESSING, ::getBooleanCppuType(), 0);
516 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
517 PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0);
518 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
519 PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0);
520 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
521 PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0);
522 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
523 PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0);
524 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
525 PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0);
526 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
527 PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0);
528 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
529 PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0);
530 pProperties[nPos++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS),
531 PROPERTY_ID_USEBOOKMARKS, ::getBooleanCppuType(), 0);
533 return new ::cppu::OPropertyArrayHelper(aProps);
536 ::cppu::IPropertyArrayHelper & MacabCommonStatement::getInfoHelper()
538 return *const_cast<MacabCommonStatement*>(this)->getArrayHelper();
541 sal_Bool MacabCommonStatement::convertFastPropertyValue(
542 Any &,
543 Any &,
544 sal_Int32,
545 const Any&) throw (::com::sun::star::lang::IllegalArgumentException)
547 sal_Bool bConverted = sal_False;
548 // here we have to try to convert
549 return bConverted;
552 void MacabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&) throw (Exception)
554 // set the value to whatever is necessary
555 switch (nHandle)
557 case PROPERTY_ID_QUERYTIMEOUT:
558 case PROPERTY_ID_MAXFIELDSIZE:
559 case PROPERTY_ID_MAXROWS:
560 case PROPERTY_ID_CURSORNAME:
561 case PROPERTY_ID_RESULTSETCONCURRENCY:
562 case PROPERTY_ID_RESULTSETTYPE:
563 case PROPERTY_ID_FETCHDIRECTION:
564 case PROPERTY_ID_FETCHSIZE:
565 case PROPERTY_ID_ESCAPEPROCESSING:
566 case PROPERTY_ID_USEBOOKMARKS:
567 default:
572 void MacabCommonStatement::getFastPropertyValue(Any&,sal_Int32 nHandle) const
574 switch (nHandle)
576 case PROPERTY_ID_QUERYTIMEOUT:
577 case PROPERTY_ID_MAXFIELDSIZE:
578 case PROPERTY_ID_MAXROWS:
579 case PROPERTY_ID_CURSORNAME:
580 case PROPERTY_ID_RESULTSETCONCURRENCY:
581 case PROPERTY_ID_RESULTSETTYPE:
582 case PROPERTY_ID_FETCHDIRECTION:
583 case PROPERTY_ID_FETCHSIZE:
584 case PROPERTY_ID_ESCAPEPROCESSING:
585 case PROPERTY_ID_USEBOOKMARKS:
586 default:
591 void SAL_CALL MacabCommonStatement::acquire() throw()
593 MacabCommonStatement_BASE::acquire();
596 void SAL_CALL MacabCommonStatement::release() throw()
598 MacabCommonStatement_BASE::release();
601 Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL MacabCommonStatement::getPropertySetInfo( ) throw(RuntimeException)
603 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
606 MacabStatement::MacabStatement(MacabConnection* _pConnection)
607 : MacabStatement_BASE(_pConnection)
611 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */