1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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);
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
:
105 return new MacabConditionConstant(pLeft
->getTokenValue() == pRight
->getTokenValue());
107 case SQLNodeType::NotEqual
:
109 // (might not be correct SQL... don't care, handling anyway)
110 return new MacabConditionConstant(pLeft
->getTokenValue() != pRight
->getTokenValue());
116 else if (SQL_ISRULE(pLeft
, column_ref
))
118 OUString sColumnName
,
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
);
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
,
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
);
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
,
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
);
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
++)
240 (analyseOrderByClause(pParseNode
->getChild(i
)));
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();
262 !SQL_ISTOKEN(pAscendingDescending
, DESC
);
264 return new MacabSimpleOrder(m_pHeader
, sColumnName
, bAscending
);
269 impl_throwError(STR_QUERY_TOO_COMPLEX
);
275 OUString
MacabCommonStatement::getTableName() const
277 const OSQLTables
& xTabs
= m_aSQLIterator
.getTables();
282 // can only deal with one table at a time
283 if(xTabs
.size() > 1 || m_aSQLIterator
.hasErrors() )
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();
297 ::connectivity::SharedResources aResources
;
298 const OUString
sError( aResources
.getResourceString(
299 STR_INVALID_COLUMN_SELECTION
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
))
317 pParseNode
= pParseNode
->getChild(1);
318 MacabCondition
*pCondition
= analyseWhereClause(pParseNode
);
319 if (pCondition
->isAlwaysTrue())
320 pResult
->allMacabRecords();
322 pResult
->someMacabRecords(pCondition
);
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
);
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
);
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
);
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
);
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);
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
);
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
442 // To be continued: UPDATE
445 impl_throwError(STR_QUERY_TOO_COMPLEX
);
448 m_xResultSet
= Reference
<XResultSet
>(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
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();
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(
528 // here we have to try to convert
532 void MacabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
,const Any
&)
534 // set the value to whatever is necessary
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
:
552 void MacabCommonStatement::getFastPropertyValue(Any
&,sal_Int32 nHandle
) const
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
:
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: */