1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: MacabStatement.cxx,v $
10 * $Revision: 1.3.56.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
34 #include "MacabStatement.hxx"
35 #include "MacabConnection.hxx"
36 #include "MacabAddressBook.hxx"
37 #include "MacabDriver.hxx"
38 #include "MacabResultSet.hxx"
39 #include "MacabResultSetMetaData.hxx"
40 #include "macabcondition.hxx"
41 #include "macaborder.hxx"
42 #include "TConnection.hxx"
43 #include <connectivity/dbexception.hxx>
44 #include "resource/sharedresources.hxx"
45 #include "resource/macab_res.hrc"
47 #if OSL_DEBUG_LEVEL > 0
48 # define OUtoCStr( x ) ( ::rtl::OUStringToOString ( (x), RTL_TEXTENCODING_ASCII_US).getStr())
49 #else /* OSL_DEBUG_LEVEL */
50 # define OUtoCStr( x ) ("dummy")
51 #endif /* OSL_DEBUG_LEVEL */
53 using namespace connectivity::macab
;
54 using namespace com::sun::star::uno
;
55 using namespace com::sun::star::lang
;
56 using namespace com::sun::star::beans
;
57 using namespace com::sun::star::sdbc
;
58 using namespace com::sun::star::sdbcx
;
59 using namespace com::sun::star::container
;
60 using namespace com::sun::star::io
;
61 using namespace com::sun::star::util
;
63 namespace connectivity
67 void impl_throwError(sal_uInt16 _nErrorId
)
69 ::connectivity::SharedResources aResources
;
70 const ::rtl::OUString
sError( aResources
.getResourceString(_nErrorId
) );
71 ::dbtools::throwGenericSQLException(sError
,NULL
);
76 IMPLEMENT_SERVICE_INFO(MacabStatement
, "com.sun.star.sdbc.drivers.MacabStatement", "com.sun.star.sdbc.Statement");
77 //------------------------------------------------------------------------------
78 MacabCommonStatement::MacabCommonStatement(MacabConnection
* _pConnection
)
79 : MacabCommonStatement_BASE(m_aMutex
),
80 OPropertySetHelper(MacabCommonStatement_BASE::rBHelper
),
81 m_aParser(_pConnection
->getDriver()->getMSFactory()),
82 m_aSQLIterator(_pConnection
, _pConnection
->createCatalog()->getTables(), m_aParser
, NULL
),
84 m_pConnection(_pConnection
),
85 rBHelper(MacabCommonStatement_BASE::rBHelper
)
87 m_pConnection
->acquire();
89 // -----------------------------------------------------------------------------
90 MacabCommonStatement::~MacabCommonStatement()
93 // -----------------------------------------------------------------------------
94 void MacabCommonStatement::disposing()
96 MacabCommonStatement_BASE::disposing();
98 // -----------------------------------------------------------------------------
99 void MacabCommonStatement::resetParameters() const throw(::com::sun::star::sdbc::SQLException
)
101 impl_throwError(STR_PARA_ONLY_PREPARED
);
103 // -----------------------------------------------------------------------------
104 void MacabCommonStatement::getNextParameter(::rtl::OUString
&) const throw(::com::sun::star::sdbc::SQLException
)
106 impl_throwError(STR_PARA_ONLY_PREPARED
);
108 // -----------------------------------------------------------------------------
109 MacabCondition
*MacabCommonStatement::analyseWhereClause(const OSQLParseNode
*pParseNode
) const throw(SQLException
)
111 if (pParseNode
->count() == 3)
113 const OSQLParseNode
*pLeft
= pParseNode
->getChild(0),
114 *pMiddle
= pParseNode
->getChild(1),
115 *pRight
= pParseNode
->getChild(2);
118 if (SQL_ISPUNCTUATION(pLeft
, "(") && SQL_ISPUNCTUATION(pRight
, ")"))
120 return analyseWhereClause(pMiddle
);
122 else if (SQL_ISRULE(pParseNode
, comparison_predicate
))
124 if (pLeft
->isToken() && pRight
->isToken())
126 switch (pMiddle
->getNodeType())
130 return new MacabConditionConstant(pLeft
->getTokenValue() == pRight
->getTokenValue());
132 case SQL_NODE_NOTEQUAL
:
134 // (might not be correct SQL... don't care, handling anyway)
135 return new MacabConditionConstant(pLeft
->getTokenValue() != pRight
->getTokenValue());
141 else if (SQL_ISRULE(pLeft
, column_ref
))
143 ::rtl::OUString sColumnName
,
146 m_aSQLIterator
.getColumnRange(pLeft
, sColumnName
, sTableRange
);
148 if (pRight
->isToken() || SQL_ISRULE(pRight
, parameter
))
150 ::rtl::OUString sMatchString
;
152 if (pRight
->isToken()) // WHERE Name = 'Doe'
153 sMatchString
= pRight
->getTokenValue();
154 else if (SQL_ISRULE(pRight
, parameter
)) // WHERE Name = ?
155 getNextParameter(sMatchString
);
157 switch (pMiddle
->getNodeType())
160 // WHERE Name = 'Smith'
161 return new MacabConditionEqual(m_pHeader
, sColumnName
, sMatchString
);
163 case SQL_NODE_NOTEQUAL
:
164 // WHERE Name <> 'Jones'
165 return new MacabConditionDifferent(m_pHeader
, sColumnName
, sMatchString
);
173 else if (SQL_ISRULE(pParseNode
, search_condition
))
175 if (SQL_ISTOKEN(pMiddle
, OR
))
177 // WHERE Name = 'Smith' OR Name = 'Jones'
178 return new MacabConditionOr(
179 analyseWhereClause(pLeft
),
180 analyseWhereClause(pRight
));
183 else if (SQL_ISRULE(pParseNode
, boolean_term
))
185 if (SQL_ISTOKEN(pMiddle
, AND
))
187 // WHERE Name = 'Smith' AND "Given Name" = 'Peter'
188 return new MacabConditionAnd(
189 analyseWhereClause(pLeft
),
190 analyseWhereClause(pRight
));
194 else if (pParseNode
->count() == 4)
196 const OSQLParseNode
*pLeft
= pParseNode
->getChild(0),
197 *pMiddleLeft
= pParseNode
->getChild(1),
198 *pMiddleRight
= pParseNode
->getChild(2),
199 *pRight
= pParseNode
->getChild(3);
201 if (SQL_ISRULE(pParseNode
, test_for_null
))
203 if (SQL_ISRULE(pLeft
, column_ref
) &&
204 SQL_ISTOKEN(pMiddleLeft
, IS
) &&
205 SQL_ISTOKEN(pRight
, NULL
))
207 ::rtl::OUString sColumnName
,
210 m_aSQLIterator
.getColumnRange(pLeft
, sColumnName
, sTableRange
);
212 if (SQL_ISTOKEN(pMiddleRight
, NOT
))
214 // WHERE "Mobile Phone" IS NOT NULL
215 return new MacabConditionNotNull(m_pHeader
, sColumnName
);
219 // WHERE "Mobile Phone" IS NULL
220 return new MacabConditionNull(m_pHeader
, sColumnName
);
224 else if (SQL_ISRULE(pParseNode
, like_predicate
))
226 if (SQL_ISRULE(pLeft
, column_ref
))
228 ::rtl::OUString sColumnName
,
231 m_aSQLIterator
.getColumnRange(pLeft
, sColumnName
, sTableRange
);
233 if (pMiddleRight
->isToken() || SQL_ISRULE(pMiddleRight
, parameter
))
235 ::rtl::OUString sMatchString
;
237 if (pMiddleRight
->isToken()) // WHERE Name LIKE 'Sm%'
238 sMatchString
= pMiddleRight
->getTokenValue();
239 else if (SQL_ISRULE(pMiddleRight
, parameter
)) // WHERE Name LIKE ?
240 getNextParameter(sMatchString
);
242 return new MacabConditionSimilar(m_pHeader
, sColumnName
, sMatchString
);
247 impl_throwError(STR_QUERY_TOO_COMPLEX
);
252 // -----------------------------------------------------------------------------
253 MacabOrder
*MacabCommonStatement::analyseOrderByClause(const OSQLParseNode
*pParseNode
) const throw(SQLException
)
255 if (SQL_ISRULE(pParseNode
, ordering_spec_commalist
))
257 MacabComplexOrder
*list
= new MacabComplexOrder();
258 sal_uInt32 n
= pParseNode
->count();
260 // Iterate through the ordering columns
261 for (sal_uInt32 i
= 0; i
< n
; i
++)
264 (analyseOrderByClause(pParseNode
->getChild(i
)));
269 else if (SQL_ISRULE(pParseNode
, ordering_spec
))
271 if (pParseNode
->count() == 2)
273 OSQLParseNode
* pColumnRef
= pParseNode
->getChild(0);
274 OSQLParseNode
* pAscendingDescending
= pParseNode
->getChild(1);
276 if (SQL_ISRULE(pColumnRef
, column_ref
))
278 if (pColumnRef
->count() == 3)
279 pColumnRef
= pColumnRef
->getChild(2);
281 if (pColumnRef
->count() == 1)
283 ::rtl::OUString sColumnName
=
284 pColumnRef
->getChild(0)->getTokenValue();
285 sal_Bool bAscending
=
286 SQL_ISTOKEN(pAscendingDescending
, DESC
)?
290 return new MacabSimpleOrder(m_pHeader
, sColumnName
, bAscending
);
295 impl_throwError(STR_QUERY_TOO_COMPLEX
);
300 //------------------------------------------------------------------------------
301 ::rtl::OUString
MacabCommonStatement::getTableName() const
303 const OSQLTables
& xTabs
= m_aSQLIterator
.getTables();
306 return ::rtl::OUString();
308 // can only deal with one table at a time
309 if(xTabs
.size() > 1 || m_aSQLIterator
.hasErrors() )
310 return ::rtl::OUString();
312 return xTabs
.begin()->first
;
314 //------------------------------------------------------------------------------
315 void MacabCommonStatement::setMacabFields(MacabResultSet
*pResult
) const throw(SQLException
)
317 ::vos::ORef
<connectivity::OSQLColumns
> xColumns
; // selected columns
318 MacabResultSetMetaData
*pMeta
; // meta information - holds the list of AddressBook fields
320 xColumns
= m_aSQLIterator
.getSelectColumns();
321 if (!xColumns
.isValid())
323 ::connectivity::SharedResources aResources
;
324 const ::rtl::OUString
sError( aResources
.getResourceString(
325 STR_INVALID_COLUMN_SELECTION
327 ::dbtools::throwGenericSQLException(sError
,NULL
);
329 pMeta
= static_cast<MacabResultSetMetaData
*>(pResult
->getMetaData().get());
330 pMeta
->setMacabFields(xColumns
);
332 // -------------------------------------------------------------------------
333 void MacabCommonStatement::selectRecords(MacabResultSet
*pResult
) const throw(SQLException
)
335 const OSQLParseNode
*pParseNode
;
336 MacabCondition
*pCondition
;
338 pParseNode
= m_aSQLIterator
.getWhereTree();
339 if (pParseNode
!= NULL
)
341 if (SQL_ISRULE(pParseNode
, where_clause
))
343 // Since we don't support parameters, don't reset them. If we ever
344 // support them, uncomment this line and fix resetParameters.
346 pParseNode
= pParseNode
->getChild(1);
347 pCondition
= analyseWhereClause(pParseNode
);
348 if (pCondition
->isAlwaysTrue())
349 pResult
->allMacabRecords();
350 else if (!pCondition
->isAlwaysFalse())
351 pResult
->someMacabRecords(pCondition
);
357 // no WHERE clause: get all rows
358 pResult
->allMacabRecords();
360 // -------------------------------------------------------------------------
361 void MacabCommonStatement::sortRecords(MacabResultSet
*pResult
) const throw(SQLException
)
363 const OSQLParseNode
*pParseNode
;
366 pParseNode
= m_aSQLIterator
.getOrderTree();
367 if (pParseNode
!= NULL
)
369 if (SQL_ISRULE(pParseNode
, opt_order_by_clause
))
371 pParseNode
= pParseNode
->getChild(2);
372 pOrder
= analyseOrderByClause(pParseNode
);
373 pResult
->sortMacabRecords(pOrder
);
378 //-----------------------------------------------------------------------------
379 Any SAL_CALL
MacabCommonStatement::queryInterface( const Type
& rType
) throw(RuntimeException
)
381 Any aRet
= MacabCommonStatement_BASE::queryInterface(rType
);
382 if (!aRet
.hasValue())
383 aRet
= OPropertySetHelper::queryInterface(rType
);
386 // -------------------------------------------------------------------------
387 Sequence
< Type
> SAL_CALL
MacabCommonStatement::getTypes( ) throw(RuntimeException
)
389 ::cppu::OTypeCollection
aTypes( ::getCppuType( (const Reference
< XMultiPropertySet
> *)0 ),
390 ::getCppuType( (const Reference
< XFastPropertySet
> *)0 ),
391 ::getCppuType( (const Reference
< XPropertySet
> *)0 ));
393 return comphelper::concatSequences(aTypes
.getTypes(),MacabCommonStatement_BASE::getTypes());
395 // -------------------------------------------------------------------------
396 void SAL_CALL
MacabCommonStatement::cancel( ) throw(RuntimeException
)
398 ::osl::MutexGuard
aGuard( m_aMutex
);
400 checkDisposed(MacabCommonStatement_BASE::rBHelper
.bDisposed
);
401 // cancel the current sql statement
403 // -------------------------------------------------------------------------
404 void SAL_CALL
MacabCommonStatement::close( ) throw(SQLException
, RuntimeException
)
407 ::osl::MutexGuard
aGuard( m_aMutex
);
408 checkDisposed(MacabCommonStatement_BASE::rBHelper
.bDisposed
);
413 // -------------------------------------------------------------------------
414 sal_Bool SAL_CALL
MacabCommonStatement::execute(
415 const ::rtl::OUString
& sql
) throw(SQLException
, RuntimeException
)
417 ::osl::MutexGuard
aGuard( m_aMutex
);
418 checkDisposed(MacabCommonStatement_BASE::rBHelper
.bDisposed
);
420 Reference
< XResultSet
> xRS
= executeQuery(sql
);
424 // -------------------------------------------------------------------------
425 Reference
< XResultSet
> SAL_CALL
MacabCommonStatement::executeQuery(
426 const ::rtl::OUString
& sql
) throw(SQLException
, RuntimeException
)
428 ::osl::MutexGuard
aGuard( m_aMutex
);
429 checkDisposed(MacabCommonStatement_BASE::rBHelper
.bDisposed
);
431 OSL_TRACE("Mac OS Address book - SQL Request: %s", OUtoCStr(sql
));
433 MacabResultSet
* pResult
= new MacabResultSet(this);
434 Reference
< XResultSet
> xRS
= pResult
;
435 ::rtl::OUString aErr
;
437 m_pParseTree
= m_aParser
.parseTree(aErr
, sql
);
438 if (m_pParseTree
== NULL
)
439 throw SQLException(aErr
, *this, aErr
, 0, Any());
441 m_aSQLIterator
.setParseTree(m_pParseTree
);
442 m_aSQLIterator
.traverseAll();
443 switch (m_aSQLIterator
.getStatementType())
445 case SQL_STATEMENT_SELECT
:
447 ::rtl::OUString sTableName
= getTableName(); // FROM which table ?
448 if (sTableName
.getLength() != 0) // a match
450 MacabRecords
*aRecords
;
451 aRecords
= m_pConnection
->getAddressBook()->getMacabRecords(sTableName
);
453 // In case, somehow, we don't have anything with the name m_sTableName
456 impl_throwError(STR_NO_TABLE
);
460 m_pHeader
= aRecords
->getHeader();
462 pResult
->setTableName(sTableName
);
464 setMacabFields(pResult
); // SELECT which columns ?
465 selectRecords(pResult
); // WHERE which condition ?
466 sortRecords(pResult
); // ORDER BY which columns ?
468 // To be continued: DISTINCT
475 // To be continued: UPDATE
478 impl_throwError(STR_QUERY_TOO_COMPLEX
);
481 m_xResultSet
= Reference
<XResultSet
>(pResult
);
484 // -------------------------------------------------------------------------
485 Reference
< XConnection
> SAL_CALL
MacabCommonStatement::getConnection( ) throw(SQLException
, RuntimeException
)
487 ::osl::MutexGuard
aGuard( m_aMutex
);
488 checkDisposed(MacabCommonStatement_BASE::rBHelper
.bDisposed
);
490 // just return our connection here
491 return (Reference
< XConnection
>) m_pConnection
;
493 // -------------------------------------------------------------------------
494 sal_Int32 SAL_CALL
MacabCommonStatement::executeUpdate( const ::rtl::OUString
& ) throw(SQLException
, RuntimeException
)
496 ::osl::MutexGuard
aGuard( m_aMutex
);
497 checkDisposed(MacabCommonStatement_BASE::rBHelper
.bDisposed
);
499 // the return values gives information about how many rows are affected by executing the sql statement
502 // -------------------------------------------------------------------------
503 Any SAL_CALL
MacabCommonStatement::getWarnings( ) throw(SQLException
, RuntimeException
)
505 ::osl::MutexGuard
aGuard( m_aMutex
);
506 checkDisposed(MacabCommonStatement_BASE::rBHelper
.bDisposed
);
508 return makeAny(m_aLastWarning
);
510 // -------------------------------------------------------------------------
511 void SAL_CALL
MacabCommonStatement::clearWarnings( ) throw(SQLException
, RuntimeException
)
513 ::osl::MutexGuard
aGuard( m_aMutex
);
514 checkDisposed(MacabCommonStatement_BASE::rBHelper
.bDisposed
);
516 m_aLastWarning
= SQLWarning();
518 // -------------------------------------------------------------------------
519 ::cppu::IPropertyArrayHelper
* MacabCommonStatement::createArrayHelper( ) const
521 // this properties are defined by the service statement
522 // they must be in alphabetic order
523 Sequence
< Property
> aProps(10);
524 Property
* pProperties
= aProps
.getArray();
526 DECL_PROP0(CURSORNAME
, ::rtl::OUString
);
527 DECL_BOOL_PROP0(ESCAPEPROCESSING
);
528 DECL_PROP0(FETCHDIRECTION
,sal_Int32
);
529 DECL_PROP0(FETCHSIZE
, sal_Int32
);
530 DECL_PROP0(MAXFIELDSIZE
,sal_Int32
);
531 DECL_PROP0(MAXROWS
, sal_Int32
);
532 DECL_PROP0(QUERYTIMEOUT
,sal_Int32
);
533 DECL_PROP0(RESULTSETCONCURRENCY
,sal_Int32
);
534 DECL_PROP0(RESULTSETTYPE
,sal_Int32
);
535 DECL_BOOL_PROP0(USEBOOKMARKS
);
537 return new ::cppu::OPropertyArrayHelper(aProps
);
539 // -------------------------------------------------------------------------
540 ::cppu::IPropertyArrayHelper
& MacabCommonStatement::getInfoHelper()
542 return *const_cast<MacabCommonStatement
*>(this)->getArrayHelper();
544 // -------------------------------------------------------------------------
545 sal_Bool
MacabCommonStatement::convertFastPropertyValue(
549 const Any
&) throw (::com::sun::star::lang::IllegalArgumentException
)
551 sal_Bool bConverted
= sal_False
;
552 // here we have to try to convert
555 // -------------------------------------------------------------------------
556 void MacabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
,const Any
&) throw (Exception
)
558 // set the value to whatever is nescessary
561 case PROPERTY_ID_QUERYTIMEOUT
:
562 case PROPERTY_ID_MAXFIELDSIZE
:
563 case PROPERTY_ID_MAXROWS
:
564 case PROPERTY_ID_CURSORNAME
:
565 case PROPERTY_ID_RESULTSETCONCURRENCY
:
566 case PROPERTY_ID_RESULTSETTYPE
:
567 case PROPERTY_ID_FETCHDIRECTION
:
568 case PROPERTY_ID_FETCHSIZE
:
569 case PROPERTY_ID_ESCAPEPROCESSING
:
570 case PROPERTY_ID_USEBOOKMARKS
:
575 // -------------------------------------------------------------------------
576 void MacabCommonStatement::getFastPropertyValue(Any
&,sal_Int32 nHandle
) const
580 case PROPERTY_ID_QUERYTIMEOUT
:
581 case PROPERTY_ID_MAXFIELDSIZE
:
582 case PROPERTY_ID_MAXROWS
:
583 case PROPERTY_ID_CURSORNAME
:
584 case PROPERTY_ID_RESULTSETCONCURRENCY
:
585 case PROPERTY_ID_RESULTSETTYPE
:
586 case PROPERTY_ID_FETCHDIRECTION
:
587 case PROPERTY_ID_FETCHSIZE
:
588 case PROPERTY_ID_ESCAPEPROCESSING
:
589 case PROPERTY_ID_USEBOOKMARKS
:
594 // -----------------------------------------------------------------------------
595 void SAL_CALL
MacabCommonStatement::acquire() throw()
597 MacabCommonStatement_BASE::acquire();
599 // -----------------------------------------------------------------------------
600 void SAL_CALL
MacabCommonStatement::release() throw()
602 MacabCommonStatement_BASE::release();
604 // -----------------------------------------------------------------------------
605 Reference
< ::com::sun::star::beans::XPropertySetInfo
> SAL_CALL
MacabCommonStatement::getPropertySetInfo( ) throw(RuntimeException
)
607 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
609 // -----------------------------------------------------------------------------
610 MacabStatement::MacabStatement(MacabConnection
* _pConnection
)
611 : MacabStatement_BASE(_pConnection
)