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 "KStatement.hxx"
22 #include "KConnection.hxx"
23 #include "KDriver.hxx"
24 #include "KResultSet.hxx"
25 #include "KResultSetMetaData.hxx"
26 #include "kcondition.hxx"
28 #include "TConnection.hxx"
29 #include <connectivity/dbexception.hxx>
30 #include "resource/kab_res.hrc"
31 #include "resource/sharedresources.hxx"
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::kab
;
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
;
52 void lcl_throwError(sal_uInt16 _nErrorId
)
54 ::connectivity::SharedResources aResources
;
55 const OUString
sError( aResources
.getResourceString(_nErrorId
) );
56 ::dbtools::throwGenericSQLException(sError
,NULL
);
60 IMPLEMENT_SERVICE_INFO(KabStatement
, "com.sun.star.sdbc.drivers.KabStatement", "com.sun.star.sdbc.Statement");
62 KabCommonStatement::KabCommonStatement(KabConnection
* _pConnection
)
63 : KabCommonStatement_BASE(m_aMutex
),
64 OPropertySetHelper(KabCommonStatement_BASE::rBHelper
),
65 m_aParser(_pConnection
->getDriver()->getComponentContext()),
66 m_aSQLIterator(_pConnection
, _pConnection
->createCatalog()->getTables(), m_aParser
, NULL
),
68 m_pConnection(_pConnection
),
69 rBHelper(KabCommonStatement_BASE::rBHelper
)
71 m_pConnection
->acquire();
74 KabCommonStatement::~KabCommonStatement()
78 void KabCommonStatement::disposing()
80 KabCommonStatement_BASE::disposing();
83 void KabCommonStatement::resetParameters() const throw(::com::sun::star::sdbc::SQLException
)
85 lcl_throwError(STR_PARA_ONLY_PREPARED
);
88 void KabCommonStatement::getNextParameter(OUString
&) const throw(::com::sun::star::sdbc::SQLException
)
90 lcl_throwError(STR_PARA_ONLY_PREPARED
);
93 KabCondition
*KabCommonStatement::analyseWhereClause(const OSQLParseNode
*pParseNode
) const throw(SQLException
)
95 if (pParseNode
->count() == 3)
97 const OSQLParseNode
*pLeft
= pParseNode
->getChild(0),
98 *pMiddle
= pParseNode
->getChild(1),
99 *pRight
= pParseNode
->getChild(2);
102 if (SQL_ISPUNCTUATION(pLeft
, "(") && SQL_ISPUNCTUATION(pRight
, ")"))
104 return analyseWhereClause(pMiddle
);
106 else if (SQL_ISRULE(pParseNode
, comparison_predicate
))
108 if (pLeft
->isToken() && pRight
->isToken())
110 switch (pMiddle
->getNodeType())
114 return new KabConditionConstant(pLeft
->getTokenValue() == pRight
->getTokenValue());
116 case SQL_NODE_NOTEQUAL
:
118 // (might not be correct SQL... don't care, handling anyway)
119 return new KabConditionConstant(pLeft
->getTokenValue() != pRight
->getTokenValue());
125 else if (SQL_ISRULE(pLeft
, column_ref
))
127 OUString sColumnName
,
130 m_aSQLIterator
.getColumnRange(pLeft
, sColumnName
, sTableRange
);
132 if (pRight
->isToken() || SQL_ISRULE(pRight
, parameter
))
134 OUString sMatchString
;
136 if (pRight
->isToken()) // WHERE Name = 'Doe'
137 sMatchString
= pRight
->getTokenValue();
138 else if (SQL_ISRULE(pRight
, parameter
)) // WHERE Name = ?
139 getNextParameter(sMatchString
);
141 switch (pMiddle
->getNodeType())
144 // WHERE Name = 'Smith'
145 return new KabConditionEqual(sColumnName
, sMatchString
);
147 case SQL_NODE_NOTEQUAL
:
148 // WHERE Name <> 'Jones'
149 return new KabConditionDifferent(sColumnName
, sMatchString
);
157 else if (SQL_ISRULE(pParseNode
, search_condition
))
159 if (SQL_ISTOKEN(pMiddle
, OR
))
161 // WHERE Name = 'Smith' OR Name = 'Jones'
162 return new KabConditionOr(
163 analyseWhereClause(pLeft
),
164 analyseWhereClause(pRight
));
167 else if (SQL_ISRULE(pParseNode
, boolean_term
))
169 if (SQL_ISTOKEN(pMiddle
, AND
))
171 // WHERE Name = 'Smith' AND "Given Name" = 'Peter'
172 return new KabConditionAnd(
173 analyseWhereClause(pLeft
),
174 analyseWhereClause(pRight
));
178 else if (SQL_ISRULE(pParseNode
, test_for_null
) || SQL_ISRULE(pParseNode
, like_predicate
))
180 const OSQLParseNode
*pLeft
= pParseNode
->getChild(0);
181 const OSQLParseNode
* pPart2
= pParseNode
->getChild(1);
182 const OSQLParseNode
*pMiddleLeft
= pPart2
->getChild(0),
183 *pMiddleRight
= pPart2
->getChild(1),
184 *pRight
= pPart2
->getChild(2);
186 if (SQL_ISRULE(pParseNode
, test_for_null
))
188 if (SQL_ISRULE(pLeft
, column_ref
) &&
189 SQL_ISTOKEN(pMiddleLeft
, IS
) &&
190 SQL_ISTOKEN(pRight
, NULL
))
192 OUString sColumnName
,
195 m_aSQLIterator
.getColumnRange(pLeft
, sColumnName
, sTableRange
);
197 if (SQL_ISTOKEN(pMiddleRight
, NOT
))
199 // WHERE "Mobile Phone" IS NOT NULL
200 return new KabConditionNotNull(sColumnName
);
204 // WHERE "Mobile Phone" IS NULL
205 return new KabConditionNull(sColumnName
);
209 else if (SQL_ISRULE(pParseNode
, like_predicate
))
211 if (SQL_ISRULE(pLeft
, column_ref
))
213 OUString sColumnName
,
216 m_aSQLIterator
.getColumnRange(pLeft
, sColumnName
, sTableRange
);
218 if (pMiddleRight
->isToken() || SQL_ISRULE(pMiddleRight
, parameter
))
220 OUString sMatchString
;
222 if (pMiddleRight
->isToken()) // WHERE Name LIKE 'Sm%'
223 sMatchString
= pMiddleRight
->getTokenValue();
224 else if (SQL_ISRULE(pMiddleRight
, parameter
)) // WHERE Name LIKE ?
225 getNextParameter(sMatchString
);
227 return new KabConditionSimilar(sColumnName
, sMatchString
);
233 lcl_throwError(STR_QUERY_TOO_COMPLEX
);
240 KabOrder
*KabCommonStatement::analyseOrderByClause(const OSQLParseNode
*pParseNode
) const throw(SQLException
)
242 if (SQL_ISRULE(pParseNode
, ordering_spec_commalist
))
244 KabComplexOrder
*list
= new KabComplexOrder();
245 sal_uInt32 n
= pParseNode
->count();
247 // Iterate through the ordering columns
248 for (sal_uInt32 i
= 0; i
< n
; i
++)
251 (analyseOrderByClause(pParseNode
->getChild(i
)));
256 else if (SQL_ISRULE(pParseNode
, ordering_spec
))
258 if (pParseNode
->count() == 2)
260 OSQLParseNode
* pColumnRef
= pParseNode
->getChild(0);
261 OSQLParseNode
* pAscendingDescending
= pParseNode
->getChild(1);
263 if (SQL_ISRULE(pColumnRef
, column_ref
))
265 if (pColumnRef
->count() == 3)
266 pColumnRef
= pColumnRef
->getChild(2);
268 if (pColumnRef
->count() == 1)
270 OUString sColumnName
=
271 pColumnRef
->getChild(0)->getTokenValue();
272 sal_Bool bAscending
=
273 SQL_ISTOKEN(pAscendingDescending
, DESC
)?
277 return new KabSimpleOrder(sColumnName
, bAscending
);
282 lcl_throwError(STR_QUERY_TOO_COMPLEX
);
288 sal_Bool
KabCommonStatement::isTableKnown(KabResultSet
*pResult
) const
290 // can handle requests like SELECT * FROM addresses addresses
291 // but cannot handle requests like SELECT * FROM addresses persons
292 if (m_aSQLIterator
.getTables().size() != 1)
295 if (m_aSQLIterator
.getTables().begin()->first
!= pResult
->getMetaData()->getTableName(0))
301 void KabCommonStatement::setKabFields(KabResultSet
*pResult
) const throw(SQLException
)
303 ::rtl::Reference
<connectivity::OSQLColumns
> xColumns
; // selected columns
305 xColumns
= m_aSQLIterator
.getSelectColumns();
308 lcl_throwError(STR_INVALID_COLUMN_SELECTION
);
310 pResult
->getKabMetaData()->setKabFields(xColumns
);
313 void KabCommonStatement::selectAddressees(KabResultSet
*pResult
) const throw(SQLException
)
315 const OSQLParseNode
*pParseNode
;
317 pParseNode
= m_aSQLIterator
.getWhereTree();
318 if (pParseNode
!= NULL
)
320 if (SQL_ISRULE(pParseNode
, where_clause
))
323 pParseNode
= pParseNode
->getChild(1);
324 KabCondition
*pCondition
= analyseWhereClause(pParseNode
);
325 if (pCondition
->isAlwaysTrue())
326 pResult
->allKabAddressees();
327 else if (!pCondition
->isAlwaysFalse())
328 pResult
->someKabAddressees(pCondition
);
334 // no WHERE clause: get all rows
335 pResult
->allKabAddressees();
338 void KabCommonStatement::sortAddressees(KabResultSet
*pResult
) const throw(SQLException
)
340 const OSQLParseNode
*pParseNode
;
342 pParseNode
= m_aSQLIterator
.getOrderTree();
343 if (pParseNode
!= NULL
)
345 if (SQL_ISRULE(pParseNode
, opt_order_by_clause
))
347 pParseNode
= pParseNode
->getChild(2);
348 KabOrder
*pOrder
= analyseOrderByClause(pParseNode
);
349 pResult
->sortKabAddressees(pOrder
);
355 Any SAL_CALL
KabCommonStatement::queryInterface( const Type
& rType
) throw(RuntimeException
, std::exception
)
357 Any aRet
= KabCommonStatement_BASE::queryInterface(rType
);
358 if (!aRet
.hasValue())
359 aRet
= OPropertySetHelper::queryInterface(rType
);
363 Sequence
< Type
> SAL_CALL
KabCommonStatement::getTypes( ) throw(RuntimeException
, std::exception
)
365 ::cppu::OTypeCollection
aTypes( ::getCppuType( (const Reference
< XMultiPropertySet
> *)0 ),
366 ::getCppuType( (const Reference
< XFastPropertySet
> *)0 ),
367 ::getCppuType( (const Reference
< XPropertySet
> *)0 ));
369 return comphelper::concatSequences(aTypes
.getTypes(),KabCommonStatement_BASE::getTypes());
372 void SAL_CALL
KabCommonStatement::cancel( ) throw(RuntimeException
, std::exception
)
374 ::osl::MutexGuard
aGuard( m_aMutex
);
376 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
377 // cancel the current sql statement
380 void SAL_CALL
KabCommonStatement::close( ) throw(SQLException
, RuntimeException
, std::exception
)
383 ::osl::MutexGuard
aGuard( m_aMutex
);
384 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
390 sal_Bool SAL_CALL
KabCommonStatement::execute(
391 const OUString
& sql
) throw(SQLException
, RuntimeException
, std::exception
)
393 ::osl::MutexGuard
aGuard( m_aMutex
);
394 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
396 Reference
< XResultSet
> xRS
= executeQuery(sql
);
401 Reference
< XResultSet
> SAL_CALL
KabCommonStatement::executeQuery(
402 const OUString
& sql
) throw(SQLException
, RuntimeException
, std::exception
)
404 ::osl::MutexGuard
aGuard( m_aMutex
);
405 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
407 OSL_TRACE("KDE Address book - SQL Request: %s", OUtoCStr(sql
));
409 KabResultSet
* pResult
= new KabResultSet(this);
410 Reference
< XResultSet
> xRS
= pResult
;
413 m_pParseTree
= m_aParser
.parseTree(aErr
, sql
);
414 if (m_pParseTree
== NULL
)
415 throw SQLException(aErr
, *this, aErr
, 0, Any());
417 m_aSQLIterator
.setParseTree(m_pParseTree
);
418 m_aSQLIterator
.traverseAll();
419 switch (m_aSQLIterator
.getStatementType())
421 case SQL_STATEMENT_SELECT
:
422 if (isTableKnown(pResult
)) // FROM which table ?
424 setKabFields(pResult
); // SELECT which columns ?
425 selectAddressees(pResult
); // WHERE which condition ?
426 sortAddressees(pResult
); // ORDER BY which columns ?
427 // To be continued: DISTINCT
433 // To be continued: UPDATE
436 lcl_throwError(STR_QUERY_TOO_COMPLEX
);
442 Reference
< XConnection
> SAL_CALL
KabCommonStatement::getConnection( ) throw(SQLException
, RuntimeException
, std::exception
)
444 ::osl::MutexGuard
aGuard( m_aMutex
);
445 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
447 // just return our connection here
448 return (Reference
< XConnection
>) m_pConnection
;
451 sal_Int32 SAL_CALL
KabCommonStatement::executeUpdate( const OUString
& ) throw(SQLException
, RuntimeException
, std::exception
)
453 ::osl::MutexGuard
aGuard( m_aMutex
);
454 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
456 // the return values gives information about how many rows are affected by executing the sql statement
460 Any SAL_CALL
KabCommonStatement::getWarnings( ) throw(SQLException
, RuntimeException
, std::exception
)
462 ::osl::MutexGuard
aGuard( m_aMutex
);
463 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
465 return makeAny(m_aLastWarning
);
468 void SAL_CALL
KabCommonStatement::clearWarnings( ) throw(SQLException
, RuntimeException
, std::exception
)
470 ::osl::MutexGuard
aGuard( m_aMutex
);
471 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
473 m_aLastWarning
= SQLWarning();
476 ::cppu::IPropertyArrayHelper
* KabCommonStatement::createArrayHelper( ) const
478 // this properties are defined by the service statement
479 // they must be in alphabetic order
480 Sequence
< Property
> aProps(10);
481 Property
* pProperties
= aProps
.getArray();
483 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME
),
484 PROPERTY_ID_CURSORNAME
, cppu::UnoType
<OUString
>::get(), 0);
485 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING
),
486 PROPERTY_ID_ESCAPEPROCESSING
, ::getBooleanCppuType(), 0);
487 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION
),
488 PROPERTY_ID_FETCHDIRECTION
, cppu::UnoType
<sal_Int32
>::get(), 0);
489 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE
),
490 PROPERTY_ID_FETCHSIZE
, cppu::UnoType
<sal_Int32
>::get(), 0);
491 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE
),
492 PROPERTY_ID_MAXFIELDSIZE
, cppu::UnoType
<sal_Int32
>::get(), 0);
493 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS
),
494 PROPERTY_ID_MAXROWS
, cppu::UnoType
<sal_Int32
>::get(), 0);
495 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT
),
496 PROPERTY_ID_QUERYTIMEOUT
, cppu::UnoType
<sal_Int32
>::get(), 0);
497 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY
),
498 PROPERTY_ID_RESULTSETCONCURRENCY
, cppu::UnoType
<sal_Int32
>::get(), 0);
499 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE
),
500 PROPERTY_ID_RESULTSETTYPE
, cppu::UnoType
<sal_Int32
>::get(), 0);
501 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS
),
502 PROPERTY_ID_USEBOOKMARKS
, ::getBooleanCppuType(), 0);
504 return new ::cppu::OPropertyArrayHelper(aProps
);
507 ::cppu::IPropertyArrayHelper
& KabCommonStatement::getInfoHelper()
509 return *const_cast<KabCommonStatement
*>(this)->getArrayHelper();
512 sal_Bool
KabCommonStatement::convertFastPropertyValue(
516 const Any
&) throw (::com::sun::star::lang::IllegalArgumentException
)
518 sal_Bool bConverted
= sal_False
;
519 // here we have to try to convert
523 void KabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
,const Any
&) throw (Exception
, std::exception
)
525 // set the value to whatever is necessary
528 case PROPERTY_ID_QUERYTIMEOUT
:
529 case PROPERTY_ID_MAXFIELDSIZE
:
530 case PROPERTY_ID_MAXROWS
:
531 case PROPERTY_ID_CURSORNAME
:
532 case PROPERTY_ID_RESULTSETCONCURRENCY
:
533 case PROPERTY_ID_RESULTSETTYPE
:
534 case PROPERTY_ID_FETCHDIRECTION
:
535 case PROPERTY_ID_FETCHSIZE
:
536 case PROPERTY_ID_ESCAPEPROCESSING
:
537 case PROPERTY_ID_USEBOOKMARKS
:
543 void KabCommonStatement::getFastPropertyValue(Any
&,sal_Int32 nHandle
) const
547 case PROPERTY_ID_QUERYTIMEOUT
:
548 case PROPERTY_ID_MAXFIELDSIZE
:
549 case PROPERTY_ID_MAXROWS
:
550 case PROPERTY_ID_CURSORNAME
:
551 case PROPERTY_ID_RESULTSETCONCURRENCY
:
552 case PROPERTY_ID_RESULTSETTYPE
:
553 case PROPERTY_ID_FETCHDIRECTION
:
554 case PROPERTY_ID_FETCHSIZE
:
555 case PROPERTY_ID_ESCAPEPROCESSING
:
556 case PROPERTY_ID_USEBOOKMARKS
:
562 void SAL_CALL
KabCommonStatement::acquire() throw()
564 KabCommonStatement_BASE::acquire();
567 void SAL_CALL
KabCommonStatement::release() throw()
569 KabCommonStatement_BASE::release();
572 Reference
< ::com::sun::star::beans::XPropertySetInfo
> SAL_CALL
KabCommonStatement::getPropertySetInfo( ) throw(RuntimeException
, std::exception
)
574 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
577 KabStatement::KabStatement(KabConnection
* _pConnection
)
578 : KabStatement_BASE(_pConnection
)
582 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */