build fix
[LibreOffice.git] / connectivity / source / drivers / macab / MacabStatement.cxx
blob7140c41dba3392d7bc4213143edb972d01f4ea08
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 "sqlbison.hxx"
23 #include "MacabConnection.hxx"
24 #include "MacabAddressBook.hxx"
25 #include "MacabDriver.hxx"
26 #include "MacabResultSet.hxx"
27 #include "MacabResultSetMetaData.hxx"
28 #include "macabcondition.hxx"
29 #include "macaborder.hxx"
30 #include "TConnection.hxx"
31 #include <connectivity/dbexception.hxx>
32 #include "resource/sharedresources.hxx"
33 #include "resource/macab_res.hrc"
35 #if OSL_DEBUG_LEVEL > 0
36 # define OUtoCStr( x ) ( OUStringToOString ( (x), RTL_TEXTENCODING_ASCII_US).getStr())
37 #else /* OSL_DEBUG_LEVEL */
38 # define OUtoCStr( x ) ("dummy")
39 #endif /* OSL_DEBUG_LEVEL */
41 using namespace connectivity::macab;
42 using namespace com::sun::star::uno;
43 using namespace com::sun::star::lang;
44 using namespace com::sun::star::beans;
45 using namespace com::sun::star::sdbc;
46 using namespace com::sun::star::sdbcx;
47 using namespace com::sun::star::container;
48 using namespace com::sun::star::io;
49 using namespace com::sun::star::util;
51 namespace connectivity
53 namespace macab
55 void impl_throwError(sal_uInt16 _nErrorId)
57 ::connectivity::SharedResources aResources;
58 const OUString sError( aResources.getResourceString(_nErrorId) );
59 ::dbtools::throwGenericSQLException(sError,nullptr);
64 IMPLEMENT_SERVICE_INFO(MacabStatement, "com.sun.star.sdbc.drivers.MacabStatement", "com.sun.star.sdbc.Statement");
66 MacabCommonStatement::MacabCommonStatement(MacabConnection* _pConnection )
67 : MacabCommonStatement_BASE(m_aMutex),
68 OPropertySetHelper(rBHelper),
69 m_aParser(_pConnection->getDriver()->getComponentContext()),
70 m_aSQLIterator(_pConnection, _pConnection->createCatalog()->getTables(), m_aParser ),
71 m_pParseTree(nullptr),
72 m_pConnection(_pConnection)
74 m_pConnection->acquire();
77 MacabCommonStatement::~MacabCommonStatement()
81 void MacabCommonStatement::resetParameters() const throw(css::sdbc::SQLException)
85 void MacabCommonStatement::getNextParameter(OUString &) const throw(css::sdbc::SQLException)
87 impl_throwError(STR_PARA_ONLY_PREPARED);
90 MacabCondition *MacabCommonStatement::analyseWhereClause(const OSQLParseNode *pParseNode) const throw(SQLException)
92 if (pParseNode->count() == 3)
94 const OSQLParseNode *pLeft = pParseNode->getChild(0),
95 *pMiddle = pParseNode->getChild(1),
96 *pRight = pParseNode->getChild(2);
98 // WHERE ( ... ) ?
99 if (SQL_ISPUNCTUATION(pLeft, "(") && SQL_ISPUNCTUATION(pRight, ")"))
101 return analyseWhereClause(pMiddle);
103 else if (SQL_ISRULE(pParseNode, comparison_predicate))
105 if (pLeft->isToken() && pRight->isToken())
107 switch (pMiddle->getNodeType())
109 case SQLNodeType::Equal:
110 // WHERE 0 = 1
111 return new MacabConditionConstant(pLeft->getTokenValue() == pRight->getTokenValue());
113 case SQLNodeType::NotEqual:
114 // WHERE 0 <> 1
115 // (might not be correct SQL... don't care, handling anyway)
116 return new MacabConditionConstant(pLeft->getTokenValue() != pRight->getTokenValue());
118 default:
119 break;
122 else if (SQL_ISRULE(pLeft, column_ref))
124 OUString sColumnName,
125 sTableRange;
127 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
129 if (pRight->isToken() || SQL_ISRULE(pRight, parameter))
131 OUString sMatchString;
133 if (pRight->isToken()) // WHERE Name = 'Doe'
134 sMatchString = pRight->getTokenValue();
135 else if (SQL_ISRULE(pRight, parameter)) // WHERE Name = ?
136 getNextParameter(sMatchString);
138 switch (pMiddle->getNodeType())
140 case SQLNodeType::Equal:
141 // WHERE Name = 'Smith'
142 return new MacabConditionEqual(m_pHeader, sColumnName, sMatchString);
144 case SQLNodeType::NotEqual:
145 // WHERE Name <> 'Jones'
146 return new MacabConditionDifferent(m_pHeader, sColumnName, sMatchString);
148 default:
149 break;
154 else if (SQL_ISRULE(pParseNode, search_condition))
156 if (SQL_ISTOKEN(pMiddle, OR))
158 // WHERE Name = 'Smith' OR Name = 'Jones'
159 return new MacabConditionOr(
160 analyseWhereClause(pLeft),
161 analyseWhereClause(pRight));
164 else if (SQL_ISRULE(pParseNode, boolean_term))
166 if (SQL_ISTOKEN(pMiddle, AND))
168 // WHERE Name = 'Smith' AND "Given Name" = 'Peter'
169 return new MacabConditionAnd(
170 analyseWhereClause(pLeft),
171 analyseWhereClause(pRight));
175 else if (SQL_ISRULE(pParseNode, test_for_null) || SQL_ISRULE(pParseNode, like_predicate))
177 const OSQLParseNode *pLeft = pParseNode->getChild(0);
178 const OSQLParseNode* pPart2 = pParseNode->getChild(1);
179 const OSQLParseNode *pMiddleLeft = pPart2->getChild(0),
180 *pMiddleRight = pPart2->getChild(1),
181 *pRight = pPart2->getChild(2);
183 if (SQL_ISRULE(pParseNode, test_for_null))
185 if (SQL_ISRULE(pLeft, column_ref) &&
186 SQL_ISTOKEN(pMiddleLeft, IS) &&
187 SQL_ISTOKEN(pRight, NULL))
189 OUString sColumnName,
190 sTableRange;
192 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
194 if (SQL_ISTOKEN(pMiddleRight, NOT))
196 // WHERE "Mobile Phone" IS NOT NULL
197 return new MacabConditionNotNull(m_pHeader, sColumnName);
199 else
201 // WHERE "Mobile Phone" IS NULL
202 return new MacabConditionNull(m_pHeader, sColumnName);
206 else if (SQL_ISRULE(pParseNode, like_predicate))
208 if (SQL_ISRULE(pLeft, column_ref))
210 OUString sColumnName,
211 sTableRange;
213 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
215 if (pMiddleRight->isToken() || SQL_ISRULE(pMiddleRight, parameter))
217 OUString sMatchString;
219 if (pMiddleRight->isToken()) // WHERE Name LIKE 'Sm%'
220 sMatchString = pMiddleRight->getTokenValue();
221 else if (SQL_ISRULE(pMiddleRight, parameter)) // WHERE Name LIKE ?
222 getNextParameter(sMatchString);
224 return new MacabConditionSimilar(m_pHeader, sColumnName, sMatchString);
229 impl_throwError(STR_QUERY_TOO_COMPLEX);
230 // Unreachable:
231 OSL_ASSERT(false);
232 return nullptr;
235 MacabOrder *MacabCommonStatement::analyseOrderByClause(const OSQLParseNode *pParseNode) const throw(SQLException)
237 if (SQL_ISRULE(pParseNode, ordering_spec_commalist))
239 MacabComplexOrder *list = new MacabComplexOrder();
240 sal_uInt32 n = pParseNode->count();
242 // Iterate through the ordering columns
243 for (sal_uInt32 i = 0; i < n; i++)
245 list->addOrder
246 (analyseOrderByClause(pParseNode->getChild(i)));
249 return list;
251 else if (SQL_ISRULE(pParseNode, ordering_spec))
253 if (pParseNode->count() == 2)
255 OSQLParseNode* pColumnRef = pParseNode->getChild(0);
256 OSQLParseNode* pAscendingDescending = pParseNode->getChild(1);
258 if (SQL_ISRULE(pColumnRef, column_ref))
260 if (pColumnRef->count() == 3)
261 pColumnRef = pColumnRef->getChild(2);
263 if (pColumnRef->count() == 1)
265 OUString sColumnName =
266 pColumnRef->getChild(0)->getTokenValue();
267 bool bAscending =
268 !SQL_ISTOKEN(pAscendingDescending, DESC);
270 return new MacabSimpleOrder(m_pHeader, sColumnName, bAscending);
275 impl_throwError(STR_QUERY_TOO_COMPLEX);
276 // Unreachable:
277 OSL_ASSERT(false);
278 return nullptr;
281 OUString MacabCommonStatement::getTableName() const
283 const OSQLTables& xTabs = m_aSQLIterator.getTables();
285 if( xTabs.empty() )
286 return OUString();
288 // can only deal with one table at a time
289 if(xTabs.size() > 1 || m_aSQLIterator.hasErrors() )
290 return OUString();
292 return xTabs.begin()->first;
295 void MacabCommonStatement::setMacabFields(MacabResultSet *pResult) const throw(SQLException)
297 ::rtl::Reference<connectivity::OSQLColumns> xColumns; // selected columns
298 MacabResultSetMetaData *pMeta; // meta information - holds the list of AddressBook fields
300 xColumns = m_aSQLIterator.getSelectColumns();
301 if (!xColumns.is())
303 ::connectivity::SharedResources aResources;
304 const OUString sError( aResources.getResourceString(
305 STR_INVALID_COLUMN_SELECTION
306 ) );
307 ::dbtools::throwGenericSQLException(sError,nullptr);
309 pMeta = static_cast<MacabResultSetMetaData *>(pResult->getMetaData().get());
310 pMeta->setMacabFields(xColumns);
313 void MacabCommonStatement::selectRecords(MacabResultSet *pResult) const throw(SQLException)
315 const OSQLParseNode *pParseNode;
317 pParseNode = m_aSQLIterator.getWhereTree();
318 if (pParseNode != nullptr)
320 if (SQL_ISRULE(pParseNode, where_clause))
322 resetParameters();
323 pParseNode = pParseNode->getChild(1);
324 MacabCondition *pCondition = analyseWhereClause(pParseNode);
325 if (pCondition->isAlwaysTrue())
326 pResult->allMacabRecords();
327 else
328 pResult->someMacabRecords(pCondition);
329 delete pCondition;
330 return;
334 // no WHERE clause: get all rows
335 pResult->allMacabRecords();
338 void MacabCommonStatement::sortRecords(MacabResultSet *pResult) const throw(SQLException)
340 const OSQLParseNode *pParseNode;
342 pParseNode = m_aSQLIterator.getOrderTree();
343 if (pParseNode != nullptr)
345 if (SQL_ISRULE(pParseNode, opt_order_by_clause))
347 pParseNode = pParseNode->getChild(2);
348 MacabOrder *pOrder = analyseOrderByClause(pParseNode);
349 pResult->sortMacabRecords(pOrder);
350 delete pOrder;
355 Any SAL_CALL MacabCommonStatement::queryInterface( const Type & rType ) throw(RuntimeException, std::exception)
357 Any aRet = MacabCommonStatement_BASE::queryInterface(rType);
358 if (!aRet.hasValue())
359 aRet = OPropertySetHelper::queryInterface(rType);
360 return aRet;
363 Sequence< Type > SAL_CALL MacabCommonStatement::getTypes( ) throw(RuntimeException, std::exception)
365 ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(),
366 cppu::UnoType<XFastPropertySet>::get(),
367 cppu::UnoType<XPropertySet>::get());
369 return comphelper::concatSequences(aTypes.getTypes(),MacabCommonStatement_BASE::getTypes());
372 void SAL_CALL MacabCommonStatement::cancel( ) throw(RuntimeException)
374 ::osl::MutexGuard aGuard( m_aMutex );
376 checkDisposed(rBHelper.bDisposed);
377 // cancel the current sql statement
380 void SAL_CALL MacabCommonStatement::close( ) throw(SQLException, RuntimeException)
383 ::osl::MutexGuard aGuard( m_aMutex );
384 checkDisposed(rBHelper.bDisposed);
387 dispose();
390 sal_Bool SAL_CALL MacabCommonStatement::execute(
391 const OUString& sql ) throw(SQLException, RuntimeException)
393 ::osl::MutexGuard aGuard( m_aMutex );
394 checkDisposed(rBHelper.bDisposed);
396 Reference< XResultSet > xRS = executeQuery(sql);
398 return xRS.is();
401 Reference< XResultSet > SAL_CALL MacabCommonStatement::executeQuery(
402 const OUString& sql ) throw(SQLException, RuntimeException)
404 ::osl::MutexGuard aGuard( m_aMutex );
405 checkDisposed(rBHelper.bDisposed);
407 OSL_TRACE("Mac OS Address book - SQL Request: %s", OUtoCStr(sql));
409 MacabResultSet* pResult = new MacabResultSet(this);
410 Reference< XResultSet > xRS = pResult;
411 OUString aErr;
413 m_pParseTree = m_aParser.parseTree(aErr, sql);
414 if (m_pParseTree == nullptr)
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 OSQLStatementType::Select:
423 OUString sTableName = getTableName(); // FROM which table ?
424 if (sTableName.getLength() != 0) // a match
426 MacabRecords *aRecords;
427 aRecords = m_pConnection->getAddressBook()->getMacabRecords(sTableName);
429 // In case, somehow, we don't have anything with the name m_sTableName
430 if(aRecords == nullptr)
432 impl_throwError(STR_NO_TABLE);
434 else
436 m_pHeader = aRecords->getHeader();
438 pResult->setTableName(sTableName);
440 setMacabFields(pResult); // SELECT which columns ?
441 selectRecords(pResult); // WHERE which condition ?
442 sortRecords(pResult); // ORDER BY which columns ?
444 // To be continued: DISTINCT
445 // etc...
448 break;
450 default:
451 // To be continued: UPDATE
452 // DELETE
453 // etc...
454 impl_throwError(STR_QUERY_TOO_COMPLEX);
457 m_xResultSet = Reference<XResultSet>(pResult);
458 return xRS;
461 Reference< XConnection > SAL_CALL MacabCommonStatement::getConnection( ) throw(SQLException, RuntimeException)
463 ::osl::MutexGuard aGuard( m_aMutex );
464 checkDisposed(rBHelper.bDisposed);
466 // just return our connection here
467 return m_pConnection;
470 sal_Int32 SAL_CALL MacabCommonStatement::executeUpdate( const OUString& ) throw(SQLException, RuntimeException)
472 ::osl::MutexGuard aGuard( m_aMutex );
473 checkDisposed(rBHelper.bDisposed);
475 // the return values gives information about how many rows are affected by executing the sql statement
476 return 0;
479 Any SAL_CALL MacabCommonStatement::getWarnings( ) throw(SQLException, RuntimeException)
481 ::osl::MutexGuard aGuard( m_aMutex );
482 checkDisposed(rBHelper.bDisposed);
484 return makeAny(m_aLastWarning);
487 void SAL_CALL MacabCommonStatement::clearWarnings( ) throw(SQLException, RuntimeException)
489 ::osl::MutexGuard aGuard( m_aMutex );
490 checkDisposed(rBHelper.bDisposed);
492 m_aLastWarning = SQLWarning();
495 ::cppu::IPropertyArrayHelper* MacabCommonStatement::createArrayHelper( ) const
497 // this properties are defined by the service statement
498 // they must be in alphabetic order
499 Sequence< Property > aProps(10);
500 Property* pProperties = aProps.getArray();
501 sal_Int32 nPos = 0;
502 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
503 PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0);
504 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
505 PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0);
506 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
507 PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0);
508 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
509 PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0);
510 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
511 PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0);
512 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
513 PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0);
514 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
515 PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0);
516 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
517 PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0);
518 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
519 PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0);
520 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS),
521 PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0);
523 return new ::cppu::OPropertyArrayHelper(aProps);
526 ::cppu::IPropertyArrayHelper & MacabCommonStatement::getInfoHelper()
528 return *getArrayHelper();
531 sal_Bool MacabCommonStatement::convertFastPropertyValue(
532 Any &,
533 Any &,
534 sal_Int32,
535 const Any&) throw (css::lang::IllegalArgumentException)
537 bool bConverted = false;
538 // here we have to try to convert
539 return bConverted;
542 void MacabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&) throw (Exception)
544 // set the value to whatever is necessary
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 MacabCommonStatement::getFastPropertyValue(Any&,sal_Int32 nHandle) const
564 switch (nHandle)
566 case PROPERTY_ID_QUERYTIMEOUT:
567 case PROPERTY_ID_MAXFIELDSIZE:
568 case PROPERTY_ID_MAXROWS:
569 case PROPERTY_ID_CURSORNAME:
570 case PROPERTY_ID_RESULTSETCONCURRENCY:
571 case PROPERTY_ID_RESULTSETTYPE:
572 case PROPERTY_ID_FETCHDIRECTION:
573 case PROPERTY_ID_FETCHSIZE:
574 case PROPERTY_ID_ESCAPEPROCESSING:
575 case PROPERTY_ID_USEBOOKMARKS:
576 default:
581 void SAL_CALL MacabCommonStatement::acquire() throw()
583 MacabCommonStatement_BASE::acquire();
586 void SAL_CALL MacabCommonStatement::release() throw()
588 MacabCommonStatement_BASE::release();
591 Reference< css::beans::XPropertySetInfo > SAL_CALL MacabCommonStatement::getPropertySetInfo( ) throw(RuntimeException)
593 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
596 MacabStatement::MacabStatement(MacabConnection* _pConnection)
597 : MacabStatement_BASE(_pConnection)
601 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */