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 "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
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
),
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);
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())
117 return new MacabConditionConstant(pLeft
->getTokenValue() == pRight
->getTokenValue());
119 case SQL_NODE_NOTEQUAL
:
121 // (might not be correct SQL... don't care, handling anyway)
122 return new MacabConditionConstant(pLeft
->getTokenValue() != pRight
->getTokenValue());
128 else if (SQL_ISRULE(pLeft
, column_ref
))
130 OUString sColumnName
,
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())
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
);
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
,
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
);
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
,
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
);
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
++)
252 (analyseOrderByClause(pParseNode
->getChild(i
)));
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
)?
278 return new MacabSimpleOrder(m_pHeader
, sColumnName
, bAscending
);
283 impl_throwError(STR_QUERY_TOO_COMPLEX
);
289 OUString
MacabCommonStatement::getTableName() const
291 const OSQLTables
& xTabs
= m_aSQLIterator
.getTables();
296 // can only deal with one table at a time
297 if(xTabs
.size() > 1 || m_aSQLIterator
.hasErrors() )
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();
311 ::connectivity::SharedResources aResources
;
312 const OUString
sError( aResources
.getResourceString(
313 STR_INVALID_COLUMN_SELECTION
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.
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
);
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
);
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
);
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
);
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
);
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
;
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
442 impl_throwError(STR_NO_TABLE
);
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
461 // To be continued: UPDATE
464 impl_throwError(STR_QUERY_TOO_COMPLEX
);
467 m_xResultSet
= Reference
<XResultSet
>(pResult
);
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
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();
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(
545 const Any
&) throw (::com::sun::star::lang::IllegalArgumentException
)
547 sal_Bool bConverted
= sal_False
;
548 // here we have to try to convert
552 void MacabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
,const Any
&) throw (Exception
)
554 // set the value to whatever is necessary
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
:
572 void MacabCommonStatement::getFastPropertyValue(Any
&,sal_Int32 nHandle
) const
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
:
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: */