bump product version to 7.2.5.1
[LibreOffice.git] / connectivity / source / drivers / macab / MacabStatement.cxx
blob1f317150d249357d70f4e007a27067954fffcfad
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 "macabutilities.hxx"
31 #include <TConnection.hxx>
32 #include <cppuhelper/typeprovider.hxx>
33 #include <connectivity/dbexception.hxx>
34 #include <resource/sharedresources.hxx>
35 #include <rtl/ref.hxx>
36 #include <strings.hrc>
38 using namespace connectivity::macab;
39 using namespace com::sun::star::uno;
40 using namespace com::sun::star::lang;
41 using namespace com::sun::star::beans;
42 using namespace com::sun::star::sdbc;
43 using namespace com::sun::star::sdbcx;
44 using namespace com::sun::star::container;
45 using namespace com::sun::star::io;
46 using namespace com::sun::star::util;
48 namespace connectivity::macab
50 void impl_throwError(const char* pErrorId)
52 ::connectivity::SharedResources aResources;
53 const OUString sError( aResources.getResourceString(pErrorId) );
54 ::dbtools::throwGenericSQLException(sError,nullptr);
58 IMPLEMENT_SERVICE_INFO(MacabStatement, "com.sun.star.sdbc.drivers.MacabStatement", "com.sun.star.sdbc.Statement");
60 MacabCommonStatement::MacabCommonStatement(MacabConnection* _pConnection )
61 : MacabCommonStatement_BASE(m_aMutex),
62 OPropertySetHelper(rBHelper),
63 m_aParser(_pConnection->getDriver()->getComponentContext()),
64 m_aSQLIterator(_pConnection, _pConnection->createCatalog()->getTables(), m_aParser ),
65 m_pParseTree(nullptr),
66 m_pConnection(_pConnection)
68 m_pConnection->acquire();
71 MacabCommonStatement::~MacabCommonStatement()
75 void MacabCommonStatement::resetParameters() const
79 void MacabCommonStatement::getNextParameter(OUString &) const
81 impl_throwError(STR_PARA_ONLY_PREPARED);
84 MacabCondition *MacabCommonStatement::analyseWhereClause(const OSQLParseNode *pParseNode) const
86 if (pParseNode->count() == 3)
88 const OSQLParseNode *pLeft = pParseNode->getChild(0),
89 *pMiddle = pParseNode->getChild(1),
90 *pRight = pParseNode->getChild(2);
92 // WHERE ( ... ) ?
93 if (SQL_ISPUNCTUATION(pLeft, "(") && SQL_ISPUNCTUATION(pRight, ")"))
95 return analyseWhereClause(pMiddle);
97 else if (SQL_ISRULE(pParseNode, comparison_predicate))
99 if (pLeft->isToken() && pRight->isToken())
101 switch (pMiddle->getNodeType())
103 case SQLNodeType::Equal:
104 // WHERE 0 = 1
105 return new MacabConditionConstant(pLeft->getTokenValue() == pRight->getTokenValue());
107 case SQLNodeType::NotEqual:
108 // WHERE 0 <> 1
109 // (might not be correct SQL... don't care, handling anyway)
110 return new MacabConditionConstant(pLeft->getTokenValue() != pRight->getTokenValue());
112 default:
113 break;
116 else if (SQL_ISRULE(pLeft, column_ref))
118 OUString sColumnName,
119 sTableRange;
121 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
123 if (pRight->isToken() || SQL_ISRULE(pRight, parameter))
125 OUString sMatchString;
127 if (pRight->isToken()) // WHERE Name = 'Doe'
128 sMatchString = pRight->getTokenValue();
129 else if (SQL_ISRULE(pRight, parameter)) // WHERE Name = ?
130 getNextParameter(sMatchString);
132 switch (pMiddle->getNodeType())
134 case SQLNodeType::Equal:
135 // WHERE Name = 'Smith'
136 return new MacabConditionEqual(m_pHeader, sColumnName, sMatchString);
138 case SQLNodeType::NotEqual:
139 // WHERE Name <> 'Jones'
140 return new MacabConditionDifferent(m_pHeader, sColumnName, sMatchString);
142 default:
143 break;
148 else if (SQL_ISRULE(pParseNode, search_condition))
150 if (SQL_ISTOKEN(pMiddle, OR))
152 // WHERE Name = 'Smith' OR Name = 'Jones'
153 return new MacabConditionOr(
154 analyseWhereClause(pLeft),
155 analyseWhereClause(pRight));
158 else if (SQL_ISRULE(pParseNode, boolean_term))
160 if (SQL_ISTOKEN(pMiddle, AND))
162 // WHERE Name = 'Smith' AND "Given Name" = 'Peter'
163 return new MacabConditionAnd(
164 analyseWhereClause(pLeft),
165 analyseWhereClause(pRight));
169 else if (SQL_ISRULE(pParseNode, test_for_null) || SQL_ISRULE(pParseNode, like_predicate))
171 const OSQLParseNode *pLeft = pParseNode->getChild(0);
172 const OSQLParseNode* pPart2 = pParseNode->getChild(1);
173 const OSQLParseNode *pMiddleLeft = pPart2->getChild(0),
174 *pMiddleRight = pPart2->getChild(1),
175 *pRight = pPart2->getChild(2);
177 if (SQL_ISRULE(pParseNode, test_for_null))
179 if (SQL_ISRULE(pLeft, column_ref) &&
180 SQL_ISTOKEN(pMiddleLeft, IS) &&
181 SQL_ISTOKEN(pRight, NULL))
183 OUString sColumnName,
184 sTableRange;
186 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
188 if (SQL_ISTOKEN(pMiddleRight, NOT))
190 // WHERE "Mobile Phone" IS NOT NULL
191 return new MacabConditionNotNull(m_pHeader, sColumnName);
193 else
195 // WHERE "Mobile Phone" IS NULL
196 return new MacabConditionNull(m_pHeader, sColumnName);
200 else if (SQL_ISRULE(pParseNode, like_predicate))
202 if (SQL_ISRULE(pLeft, column_ref))
204 OUString sColumnName,
205 sTableRange;
207 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
209 if (pMiddleRight->isToken() || SQL_ISRULE(pMiddleRight, parameter))
211 OUString sMatchString;
213 if (pMiddleRight->isToken()) // WHERE Name LIKE 'Sm%'
214 sMatchString = pMiddleRight->getTokenValue();
215 else if (SQL_ISRULE(pMiddleRight, parameter)) // WHERE Name LIKE ?
216 getNextParameter(sMatchString);
218 return new MacabConditionSimilar(m_pHeader, sColumnName, sMatchString);
223 impl_throwError(STR_QUERY_TOO_COMPLEX);
224 // Unreachable:
225 OSL_ASSERT(false);
226 return nullptr;
229 MacabOrder *MacabCommonStatement::analyseOrderByClause(const OSQLParseNode *pParseNode) const
231 if (SQL_ISRULE(pParseNode, ordering_spec_commalist))
233 MacabComplexOrder *list = new MacabComplexOrder();
234 sal_uInt32 n = pParseNode->count();
236 // Iterate through the ordering columns
237 for (sal_uInt32 i = 0; i < n; i++)
239 list->addOrder
240 (analyseOrderByClause(pParseNode->getChild(i)));
243 return list;
245 else if (SQL_ISRULE(pParseNode, ordering_spec))
247 if (pParseNode->count() == 2)
249 OSQLParseNode* pColumnRef = pParseNode->getChild(0);
250 OSQLParseNode* pAscendingDescending = pParseNode->getChild(1);
252 if (SQL_ISRULE(pColumnRef, column_ref))
254 if (pColumnRef->count() == 3)
255 pColumnRef = pColumnRef->getChild(2);
257 if (pColumnRef->count() == 1)
259 OUString sColumnName =
260 pColumnRef->getChild(0)->getTokenValue();
261 bool bAscending =
262 !SQL_ISTOKEN(pAscendingDescending, DESC);
264 return new MacabSimpleOrder(m_pHeader, sColumnName, bAscending);
269 impl_throwError(STR_QUERY_TOO_COMPLEX);
270 // Unreachable:
271 OSL_ASSERT(false);
272 return nullptr;
275 OUString MacabCommonStatement::getTableName() const
277 const OSQLTables& xTabs = m_aSQLIterator.getTables();
279 if( xTabs.empty() )
280 return OUString();
282 // can only deal with one table at a time
283 if(xTabs.size() > 1 || m_aSQLIterator.hasErrors() )
284 return OUString();
286 return xTabs.begin()->first;
289 void MacabCommonStatement::setMacabFields(MacabResultSet *pResult) const
291 ::rtl::Reference<connectivity::OSQLColumns> xColumns; // selected columns
292 rtl::Reference<MacabResultSetMetaData> pMeta; // meta information - holds the list of AddressBook fields
294 xColumns = m_aSQLIterator.getSelectColumns();
295 if (!xColumns.is())
297 ::connectivity::SharedResources aResources;
298 const OUString sError( aResources.getResourceString(
299 STR_INVALID_COLUMN_SELECTION
300 ) );
301 ::dbtools::throwGenericSQLException(sError,nullptr);
303 pMeta = static_cast<MacabResultSetMetaData *>(pResult->getMetaData().get());
304 pMeta->setMacabFields(xColumns);
307 void MacabCommonStatement::selectRecords(MacabResultSet *pResult) const
309 const OSQLParseNode *pParseNode;
311 pParseNode = m_aSQLIterator.getWhereTree();
312 if (pParseNode != nullptr)
314 if (SQL_ISRULE(pParseNode, where_clause))
316 resetParameters();
317 pParseNode = pParseNode->getChild(1);
318 MacabCondition *pCondition = analyseWhereClause(pParseNode);
319 if (pCondition->isAlwaysTrue())
320 pResult->allMacabRecords();
321 else
322 pResult->someMacabRecords(pCondition);
323 delete pCondition;
324 return;
328 // no WHERE clause: get all rows
329 pResult->allMacabRecords();
332 void MacabCommonStatement::sortRecords(MacabResultSet *pResult) const
334 const OSQLParseNode *pParseNode;
336 pParseNode = m_aSQLIterator.getOrderTree();
337 if (pParseNode != nullptr)
339 if (SQL_ISRULE(pParseNode, opt_order_by_clause))
341 pParseNode = pParseNode->getChild(2);
342 MacabOrder *pOrder = analyseOrderByClause(pParseNode);
343 pResult->sortMacabRecords(pOrder);
344 delete pOrder;
349 Any SAL_CALL MacabCommonStatement::queryInterface( const Type & rType )
351 Any aRet = MacabCommonStatement_BASE::queryInterface(rType);
352 if (!aRet.hasValue())
353 aRet = OPropertySetHelper::queryInterface(rType);
354 return aRet;
357 Sequence< Type > SAL_CALL MacabCommonStatement::getTypes( )
359 ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(),
360 cppu::UnoType<XFastPropertySet>::get(),
361 cppu::UnoType<XPropertySet>::get());
363 return comphelper::concatSequences(aTypes.getTypes(),MacabCommonStatement_BASE::getTypes());
366 void SAL_CALL MacabCommonStatement::cancel( )
368 ::osl::MutexGuard aGuard( m_aMutex );
370 checkDisposed(rBHelper.bDisposed);
371 // cancel the current sql statement
374 void SAL_CALL MacabCommonStatement::close( )
377 ::osl::MutexGuard aGuard( m_aMutex );
378 checkDisposed(rBHelper.bDisposed);
381 dispose();
384 sal_Bool SAL_CALL MacabCommonStatement::execute(
385 const OUString& sql )
387 ::osl::MutexGuard aGuard( m_aMutex );
388 checkDisposed(rBHelper.bDisposed);
390 Reference< XResultSet > xRS = executeQuery(sql);
392 return xRS.is();
395 Reference< XResultSet > SAL_CALL MacabCommonStatement::executeQuery(
396 const OUString& sql )
398 ::osl::MutexGuard aGuard( m_aMutex );
399 checkDisposed(rBHelper.bDisposed);
401 rtl::Reference<MacabResultSet> pResult = new MacabResultSet(this);
402 OUString aErr;
404 m_pParseTree = m_aParser.parseTree(aErr, sql).release();
405 if (m_pParseTree == nullptr)
406 throw SQLException(aErr, *this, aErr, 0, Any());
408 m_aSQLIterator.setParseTree(m_pParseTree);
409 m_aSQLIterator.traverseAll();
410 switch (m_aSQLIterator.getStatementType())
412 case OSQLStatementType::Select:
414 OUString sTableName = getTableName(); // FROM which table ?
415 if (sTableName.getLength() != 0) // a match
417 MacabRecords *aRecords;
418 aRecords = m_pConnection->getAddressBook()->getMacabRecords(sTableName);
420 // In case, somehow, we don't have anything with the name m_sTableName
421 if(aRecords == nullptr)
423 impl_throwError(STR_NO_TABLE);
425 else
427 m_pHeader = aRecords->getHeader();
429 pResult->setTableName(sTableName);
431 setMacabFields(pResult.get()); // SELECT which columns ?
432 selectRecords(pResult.get()); // WHERE which condition ?
433 sortRecords(pResult.get()); // ORDER BY which columns ?
435 // To be continued: DISTINCT
436 // etc...
439 break;
441 default:
442 // To be continued: UPDATE
443 // DELETE
444 // etc...
445 impl_throwError(STR_QUERY_TOO_COMPLEX);
448 m_xResultSet = Reference<XResultSet>(pResult);
449 return pResult;
452 Reference< XConnection > SAL_CALL MacabCommonStatement::getConnection( )
454 ::osl::MutexGuard aGuard( m_aMutex );
455 checkDisposed(rBHelper.bDisposed);
457 // just return our connection here
458 return m_pConnection;
461 sal_Int32 SAL_CALL MacabCommonStatement::executeUpdate( const OUString& )
463 ::osl::MutexGuard aGuard( m_aMutex );
464 checkDisposed(rBHelper.bDisposed);
466 // the return values gives information about how many rows are affected by executing the sql statement
467 return 0;
470 Any SAL_CALL MacabCommonStatement::getWarnings( )
472 ::osl::MutexGuard aGuard( m_aMutex );
473 checkDisposed(rBHelper.bDisposed);
475 return makeAny(m_aLastWarning);
478 void SAL_CALL MacabCommonStatement::clearWarnings( )
480 ::osl::MutexGuard aGuard( m_aMutex );
481 checkDisposed(rBHelper.bDisposed);
483 m_aLastWarning = SQLWarning();
486 ::cppu::IPropertyArrayHelper* MacabCommonStatement::createArrayHelper( ) const
488 // this properties are defined by the service statement
489 // they must be in alphabetic order
490 Sequence< Property > aProps(10);
491 Property* pProperties = aProps.getArray();
492 sal_Int32 nPos = 0;
493 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
494 PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0);
495 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
496 PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0);
497 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
498 PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0);
499 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
500 PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0);
501 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
502 PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0);
503 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
504 PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0);
505 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
506 PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0);
507 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
508 PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0);
509 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
510 PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0);
511 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS),
512 PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0);
514 return new ::cppu::OPropertyArrayHelper(aProps);
517 ::cppu::IPropertyArrayHelper & MacabCommonStatement::getInfoHelper()
519 return *getArrayHelper();
522 sal_Bool MacabCommonStatement::convertFastPropertyValue(
523 Any &,
524 Any &,
525 sal_Int32,
526 const Any&)
528 // here we have to try to convert
529 return false;
532 void MacabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&)
534 // set the value to whatever is necessary
535 switch (nHandle)
537 case PROPERTY_ID_QUERYTIMEOUT:
538 case PROPERTY_ID_MAXFIELDSIZE:
539 case PROPERTY_ID_MAXROWS:
540 case PROPERTY_ID_CURSORNAME:
541 case PROPERTY_ID_RESULTSETCONCURRENCY:
542 case PROPERTY_ID_RESULTSETTYPE:
543 case PROPERTY_ID_FETCHDIRECTION:
544 case PROPERTY_ID_FETCHSIZE:
545 case PROPERTY_ID_ESCAPEPROCESSING:
546 case PROPERTY_ID_USEBOOKMARKS:
547 default:
552 void MacabCommonStatement::getFastPropertyValue(Any&,sal_Int32 nHandle) const
554 switch (nHandle)
556 case PROPERTY_ID_QUERYTIMEOUT:
557 case PROPERTY_ID_MAXFIELDSIZE:
558 case PROPERTY_ID_MAXROWS:
559 case PROPERTY_ID_CURSORNAME:
560 case PROPERTY_ID_RESULTSETCONCURRENCY:
561 case PROPERTY_ID_RESULTSETTYPE:
562 case PROPERTY_ID_FETCHDIRECTION:
563 case PROPERTY_ID_FETCHSIZE:
564 case PROPERTY_ID_ESCAPEPROCESSING:
565 case PROPERTY_ID_USEBOOKMARKS:
566 default:
571 void SAL_CALL MacabCommonStatement::acquire() noexcept
573 MacabCommonStatement_BASE::acquire();
576 void SAL_CALL MacabCommonStatement::release() noexcept
578 MacabCommonStatement_BASE::release();
581 Reference< css::beans::XPropertySetInfo > SAL_CALL MacabCommonStatement::getPropertySetInfo( )
583 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
586 MacabStatement::MacabStatement(MacabConnection* _pConnection)
587 : MacabStatement_BASE(_pConnection)
591 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */