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: KStatement.cxx,v $
10 * $Revision: 1.8.56.1 $
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 "KStatement.hxx"
35 #include "KConnection.hxx"
36 #include "KDriver.hxx"
37 #include "KResultSet.hxx"
38 #include "KResultSetMetaData.hxx"
39 #include "kcondition.hxx"
41 #include "TConnection.hxx"
42 #include <connectivity/dbexception.hxx>
43 #include "resource/kab_res.hrc"
44 #include "resource/sharedresources.hxx"
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::kab
;
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
;
65 void lcl_throwError(sal_uInt16 _nErrorId
)
67 ::connectivity::SharedResources aResources
;
68 const ::rtl::OUString
sError( aResources
.getResourceString(_nErrorId
) );
69 ::dbtools::throwGenericSQLException(sError
,NULL
);
73 IMPLEMENT_SERVICE_INFO(KabStatement
, "com.sun.star.sdbc.drivers.KabStatement", "com.sun.star.sdbc.Statement");
74 //------------------------------------------------------------------------------
75 KabCommonStatement::KabCommonStatement(KabConnection
* _pConnection
)
76 : KabCommonStatement_BASE(m_aMutex
),
77 OPropertySetHelper(KabCommonStatement_BASE::rBHelper
),
78 m_aParser(_pConnection
->getDriver()->getMSFactory()),
79 m_aSQLIterator(_pConnection
, _pConnection
->createCatalog()->getTables(), m_aParser
, NULL
),
81 m_pConnection(_pConnection
),
82 rBHelper(KabCommonStatement_BASE::rBHelper
)
84 m_pConnection
->acquire();
86 // -----------------------------------------------------------------------------
87 KabCommonStatement::~KabCommonStatement()
90 // -----------------------------------------------------------------------------
91 void KabCommonStatement::disposing()
93 KabCommonStatement_BASE::disposing();
95 // -----------------------------------------------------------------------------
96 void KabCommonStatement::resetParameters() const throw(::com::sun::star::sdbc::SQLException
)
98 lcl_throwError(STR_PARA_ONLY_PREPARED
);
100 // -----------------------------------------------------------------------------
101 void KabCommonStatement::getNextParameter(::rtl::OUString
&) const throw(::com::sun::star::sdbc::SQLException
)
103 lcl_throwError(STR_PARA_ONLY_PREPARED
);
105 // -----------------------------------------------------------------------------
106 KabCondition
*KabCommonStatement::analyseWhereClause(const OSQLParseNode
*pParseNode
) const throw(SQLException
)
108 if (pParseNode
->count() == 3)
110 const OSQLParseNode
*pLeft
= pParseNode
->getChild(0),
111 *pMiddle
= pParseNode
->getChild(1),
112 *pRight
= pParseNode
->getChild(2);
115 if (SQL_ISPUNCTUATION(pLeft
, "(") && SQL_ISPUNCTUATION(pRight
, ")"))
117 return analyseWhereClause(pMiddle
);
119 else if (SQL_ISRULE(pParseNode
, comparison_predicate
))
121 if (pLeft
->isToken() && pRight
->isToken())
123 switch (pMiddle
->getNodeType())
127 return new KabConditionConstant(pLeft
->getTokenValue() == pRight
->getTokenValue());
129 case SQL_NODE_NOTEQUAL
:
131 // (might not be correct SQL... don't care, handling anyway)
132 return new KabConditionConstant(pLeft
->getTokenValue() != pRight
->getTokenValue());
138 else if (SQL_ISRULE(pLeft
, column_ref
))
140 ::rtl::OUString sColumnName
,
143 m_aSQLIterator
.getColumnRange(pLeft
, sColumnName
, sTableRange
);
145 if (pRight
->isToken() || SQL_ISRULE(pRight
, parameter
))
147 ::rtl::OUString sMatchString
;
149 if (pRight
->isToken()) // WHERE Name = 'Doe'
150 sMatchString
= pRight
->getTokenValue();
151 else if (SQL_ISRULE(pRight
, parameter
)) // WHERE Name = ?
152 getNextParameter(sMatchString
);
154 switch (pMiddle
->getNodeType())
157 // WHERE Name = 'Smith'
158 return new KabConditionEqual(sColumnName
, sMatchString
);
160 case SQL_NODE_NOTEQUAL
:
161 // WHERE Name <> 'Jones'
162 return new KabConditionDifferent(sColumnName
, sMatchString
);
170 else if (SQL_ISRULE(pParseNode
, search_condition
))
172 if (SQL_ISTOKEN(pMiddle
, OR
))
174 // WHERE Name = 'Smith' OR Name = 'Jones'
175 return new KabConditionOr(
176 analyseWhereClause(pLeft
),
177 analyseWhereClause(pRight
));
180 else if (SQL_ISRULE(pParseNode
, boolean_term
))
182 if (SQL_ISTOKEN(pMiddle
, AND
))
184 // WHERE Name = 'Smith' AND "Given Name" = 'Peter'
185 return new KabConditionAnd(
186 analyseWhereClause(pLeft
),
187 analyseWhereClause(pRight
));
191 else if (pParseNode
->count() == 4)
193 const OSQLParseNode
*pLeft
= pParseNode
->getChild(0),
194 *pMiddleLeft
= pParseNode
->getChild(1),
195 *pMiddleRight
= pParseNode
->getChild(2),
196 *pRight
= pParseNode
->getChild(3);
198 if (SQL_ISRULE(pParseNode
, test_for_null
))
200 if (SQL_ISRULE(pLeft
, column_ref
) &&
201 SQL_ISTOKEN(pMiddleLeft
, IS
) &&
202 SQL_ISTOKEN(pRight
, NULL
))
204 ::rtl::OUString sColumnName
,
207 m_aSQLIterator
.getColumnRange(pLeft
, sColumnName
, sTableRange
);
209 if (SQL_ISTOKEN(pMiddleRight
, NOT
))
211 // WHERE "Mobile Phone" IS NOT NULL
212 return new KabConditionNotNull(sColumnName
);
216 // WHERE "Mobile Phone" IS NULL
217 return new KabConditionNull(sColumnName
);
221 else if (SQL_ISRULE(pParseNode
, like_predicate
))
223 if (SQL_ISRULE(pLeft
, column_ref
))
225 ::rtl::OUString sColumnName
,
228 m_aSQLIterator
.getColumnRange(pLeft
, sColumnName
, sTableRange
);
230 if (pMiddleRight
->isToken() || SQL_ISRULE(pMiddleRight
, parameter
))
232 ::rtl::OUString sMatchString
;
234 if (pMiddleRight
->isToken()) // WHERE Name LIKE 'Sm%'
235 sMatchString
= pMiddleRight
->getTokenValue();
236 else if (SQL_ISRULE(pMiddleRight
, parameter
)) // WHERE Name LIKE ?
237 getNextParameter(sMatchString
);
239 return new KabConditionSimilar(sColumnName
, sMatchString
);
245 lcl_throwError(STR_QUERY_TOO_COMPLEX
);
251 // -----------------------------------------------------------------------------
252 KabOrder
*KabCommonStatement::analyseOrderByClause(const OSQLParseNode
*pParseNode
) const throw(SQLException
)
254 if (SQL_ISRULE(pParseNode
, ordering_spec_commalist
))
256 KabComplexOrder
*list
= new KabComplexOrder();
257 sal_uInt32 n
= pParseNode
->count();
259 // Iterate through the ordering columns
260 for (sal_uInt32 i
= 0; i
< n
; i
++)
263 (analyseOrderByClause(pParseNode
->getChild(i
)));
268 else if (SQL_ISRULE(pParseNode
, ordering_spec
))
270 if (pParseNode
->count() == 2)
272 OSQLParseNode
* pColumnRef
= pParseNode
->getChild(0);
273 OSQLParseNode
* pAscendingDescending
= pParseNode
->getChild(1);
275 if (SQL_ISRULE(pColumnRef
, column_ref
))
277 if (pColumnRef
->count() == 3)
278 pColumnRef
= pColumnRef
->getChild(2);
280 if (pColumnRef
->count() == 1)
282 ::rtl::OUString sColumnName
=
283 pColumnRef
->getChild(0)->getTokenValue();
284 sal_Bool bAscending
=
285 SQL_ISTOKEN(pAscendingDescending
, DESC
)?
289 return new KabSimpleOrder(sColumnName
, bAscending
);
294 lcl_throwError(STR_QUERY_TOO_COMPLEX
);
299 //------------------------------------------------------------------------------
300 sal_Bool
KabCommonStatement::isTableKnown(KabResultSet
*pResult
) const
302 // can handle requests like SELECT * FROM addresses addresses
303 // but cannot handle requests like SELECT * FROM addresses persons
304 if (m_aSQLIterator
.getTables().size() != 1)
307 if (m_aSQLIterator
.getTables().begin()->first
!= pResult
->getMetaData()->getTableName(0))
312 //------------------------------------------------------------------------------
313 void KabCommonStatement::setKabFields(KabResultSet
*pResult
) const throw(SQLException
)
315 ::vos::ORef
<connectivity::OSQLColumns
> xColumns
; // selected columns
316 KabResultSetMetaData
*pMeta
; // meta information - holds the list of KAddressBook fields
318 xColumns
= m_aSQLIterator
.getSelectColumns();
319 if (!xColumns
.isValid())
321 lcl_throwError(STR_INVALID_COLUMN_SELECTION
);
323 pMeta
= static_cast<KabResultSetMetaData
*>(pResult
->getMetaData().get());
324 pMeta
->setKabFields(xColumns
);
326 // -------------------------------------------------------------------------
327 void KabCommonStatement::selectAddressees(KabResultSet
*pResult
) const throw(SQLException
)
329 const OSQLParseNode
*pParseNode
;
330 KabCondition
*pCondition
;
332 pParseNode
= m_aSQLIterator
.getWhereTree();
333 if (pParseNode
!= NULL
)
335 if (SQL_ISRULE(pParseNode
, where_clause
))
338 pParseNode
= pParseNode
->getChild(1);
339 pCondition
= analyseWhereClause(pParseNode
);
340 if (pCondition
->isAlwaysTrue())
341 pResult
->allKabAddressees();
342 else if (!pCondition
->isAlwaysFalse())
343 pResult
->someKabAddressees(pCondition
);
349 // no WHERE clause: get all rows
350 pResult
->allKabAddressees();
352 // -------------------------------------------------------------------------
353 void KabCommonStatement::sortAddressees(KabResultSet
*pResult
) const throw(SQLException
)
355 const OSQLParseNode
*pParseNode
;
358 pParseNode
= m_aSQLIterator
.getOrderTree();
359 if (pParseNode
!= NULL
)
361 if (SQL_ISRULE(pParseNode
, opt_order_by_clause
))
363 pParseNode
= pParseNode
->getChild(2);
364 pOrder
= analyseOrderByClause(pParseNode
);
365 pResult
->sortKabAddressees(pOrder
);
370 //-----------------------------------------------------------------------------
371 Any SAL_CALL
KabCommonStatement::queryInterface( const Type
& rType
) throw(RuntimeException
)
373 Any aRet
= KabCommonStatement_BASE::queryInterface(rType
);
374 if (!aRet
.hasValue())
375 aRet
= OPropertySetHelper::queryInterface(rType
);
378 // -------------------------------------------------------------------------
379 Sequence
< Type
> SAL_CALL
KabCommonStatement::getTypes( ) throw(RuntimeException
)
381 ::cppu::OTypeCollection
aTypes( ::getCppuType( (const Reference
< XMultiPropertySet
> *)0 ),
382 ::getCppuType( (const Reference
< XFastPropertySet
> *)0 ),
383 ::getCppuType( (const Reference
< XPropertySet
> *)0 ));
385 return comphelper::concatSequences(aTypes
.getTypes(),KabCommonStatement_BASE::getTypes());
387 // -------------------------------------------------------------------------
388 void SAL_CALL
KabCommonStatement::cancel( ) throw(RuntimeException
)
390 ::osl::MutexGuard
aGuard( m_aMutex
);
392 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
393 // cancel the current sql statement
395 // -------------------------------------------------------------------------
396 void SAL_CALL
KabCommonStatement::close( ) throw(SQLException
, RuntimeException
)
399 ::osl::MutexGuard
aGuard( m_aMutex
);
400 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
405 // -------------------------------------------------------------------------
406 sal_Bool SAL_CALL
KabCommonStatement::execute(
407 const ::rtl::OUString
& sql
) throw(SQLException
, RuntimeException
)
409 ::osl::MutexGuard
aGuard( m_aMutex
);
410 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
412 Reference
< XResultSet
> xRS
= executeQuery(sql
);
416 // -------------------------------------------------------------------------
417 Reference
< XResultSet
> SAL_CALL
KabCommonStatement::executeQuery(
418 const ::rtl::OUString
& sql
) throw(SQLException
, RuntimeException
)
420 ::osl::MutexGuard
aGuard( m_aMutex
);
421 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
423 OSL_TRACE("KDE Address book - SQL Request: %s", OUtoCStr(sql
));
425 KabResultSet
* pResult
= new KabResultSet(this);
426 Reference
< XResultSet
> xRS
= pResult
;
427 ::rtl::OUString aErr
;
429 m_pParseTree
= m_aParser
.parseTree(aErr
, sql
);
430 if (m_pParseTree
== NULL
)
431 throw SQLException(aErr
, *this, aErr
, 0, Any());
433 m_aSQLIterator
.setParseTree(m_pParseTree
);
434 m_aSQLIterator
.traverseAll();
435 switch (m_aSQLIterator
.getStatementType())
437 case SQL_STATEMENT_SELECT
:
438 if (isTableKnown(pResult
)) // FROM which table ?
440 setKabFields(pResult
); // SELECT which columns ?
441 selectAddressees(pResult
); // WHERE which condition ?
442 sortAddressees(pResult
); // ORDER BY which columns ?
443 // To be continued: DISTINCT
449 // To be continued: UPDATE
452 lcl_throwError(STR_QUERY_TOO_COMPLEX
);
457 // -------------------------------------------------------------------------
458 Reference
< XConnection
> SAL_CALL
KabCommonStatement::getConnection( ) throw(SQLException
, RuntimeException
)
460 ::osl::MutexGuard
aGuard( m_aMutex
);
461 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
463 // just return our connection here
464 return (Reference
< XConnection
>) m_pConnection
;
466 // -------------------------------------------------------------------------
467 sal_Int32 SAL_CALL
KabCommonStatement::executeUpdate( const ::rtl::OUString
& ) throw(SQLException
, RuntimeException
)
469 ::osl::MutexGuard
aGuard( m_aMutex
);
470 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
472 // the return values gives information about how many rows are affected by executing the sql statement
475 // -------------------------------------------------------------------------
476 Any SAL_CALL
KabCommonStatement::getWarnings( ) throw(SQLException
, RuntimeException
)
478 ::osl::MutexGuard
aGuard( m_aMutex
);
479 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
481 return makeAny(m_aLastWarning
);
483 // -------------------------------------------------------------------------
484 void SAL_CALL
KabCommonStatement::clearWarnings( ) throw(SQLException
, RuntimeException
)
486 ::osl::MutexGuard
aGuard( m_aMutex
);
487 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
489 m_aLastWarning
= SQLWarning();
491 // -------------------------------------------------------------------------
492 ::cppu::IPropertyArrayHelper
* KabCommonStatement::createArrayHelper( ) const
494 // this properties are defined by the service statement
495 // they must be in alphabetic order
496 Sequence
< Property
> aProps(10);
497 Property
* pProperties
= aProps
.getArray();
499 DECL_PROP0(CURSORNAME
, ::rtl::OUString
);
500 DECL_BOOL_PROP0(ESCAPEPROCESSING
);
501 DECL_PROP0(FETCHDIRECTION
,sal_Int32
);
502 DECL_PROP0(FETCHSIZE
, sal_Int32
);
503 DECL_PROP0(MAXFIELDSIZE
,sal_Int32
);
504 DECL_PROP0(MAXROWS
, sal_Int32
);
505 DECL_PROP0(QUERYTIMEOUT
,sal_Int32
);
506 DECL_PROP0(RESULTSETCONCURRENCY
,sal_Int32
);
507 DECL_PROP0(RESULTSETTYPE
,sal_Int32
);
508 DECL_BOOL_PROP0(USEBOOKMARKS
);
510 return new ::cppu::OPropertyArrayHelper(aProps
);
512 // -------------------------------------------------------------------------
513 ::cppu::IPropertyArrayHelper
& KabCommonStatement::getInfoHelper()
515 return *const_cast<KabCommonStatement
*>(this)->getArrayHelper();
517 // -------------------------------------------------------------------------
518 sal_Bool
KabCommonStatement::convertFastPropertyValue(
522 const Any
&) throw (::com::sun::star::lang::IllegalArgumentException
)
524 sal_Bool bConverted
= sal_False
;
525 // here we have to try to convert
528 // -------------------------------------------------------------------------
529 void KabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
,const Any
&) throw (Exception
)
531 // set the value to whatever is nescessary
534 case PROPERTY_ID_QUERYTIMEOUT
:
535 case PROPERTY_ID_MAXFIELDSIZE
:
536 case PROPERTY_ID_MAXROWS
:
537 case PROPERTY_ID_CURSORNAME
:
538 case PROPERTY_ID_RESULTSETCONCURRENCY
:
539 case PROPERTY_ID_RESULTSETTYPE
:
540 case PROPERTY_ID_FETCHDIRECTION
:
541 case PROPERTY_ID_FETCHSIZE
:
542 case PROPERTY_ID_ESCAPEPROCESSING
:
543 case PROPERTY_ID_USEBOOKMARKS
:
548 // -------------------------------------------------------------------------
549 void KabCommonStatement::getFastPropertyValue(Any
&,sal_Int32 nHandle
) const
553 case PROPERTY_ID_QUERYTIMEOUT
:
554 case PROPERTY_ID_MAXFIELDSIZE
:
555 case PROPERTY_ID_MAXROWS
:
556 case PROPERTY_ID_CURSORNAME
:
557 case PROPERTY_ID_RESULTSETCONCURRENCY
:
558 case PROPERTY_ID_RESULTSETTYPE
:
559 case PROPERTY_ID_FETCHDIRECTION
:
560 case PROPERTY_ID_FETCHSIZE
:
561 case PROPERTY_ID_ESCAPEPROCESSING
:
562 case PROPERTY_ID_USEBOOKMARKS
:
567 // -----------------------------------------------------------------------------
568 void SAL_CALL
KabCommonStatement::acquire() throw()
570 KabCommonStatement_BASE::acquire();
572 // -----------------------------------------------------------------------------
573 void SAL_CALL
KabCommonStatement::release() throw()
575 KabCommonStatement_BASE::release();
577 // -----------------------------------------------------------------------------
578 Reference
< ::com::sun::star::beans::XPropertySetInfo
> SAL_CALL
KabCommonStatement::getPropertySetInfo( ) throw(RuntimeException
)
580 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
582 // -----------------------------------------------------------------------------
583 KabStatement::KabStatement(KabConnection
* _pConnection
)
584 : KabStatement_BASE(_pConnection
)