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"
32 #include "sqlbison.hxx"
35 #if OSL_DEBUG_LEVEL > 0
36 # define OUtoCStr( x ) ( OUStringToOString ( (x), RTL_TEXTENCODING_ASCII_US).getStr())
37 #else /* OSL_DEBUG_LEVEL */
38 # define OUtoCStr( x ) ("dummy")
39 #endif /* OSL_DEBUG_LEVEL */
41 using namespace connectivity::kab
;
42 using namespace com::sun::star::uno
;
43 using namespace com::sun::star::lang
;
44 using namespace com::sun::star::beans
;
45 using namespace com::sun::star::sdbc
;
46 using namespace com::sun::star::sdbcx
;
47 using namespace com::sun::star::container
;
48 using namespace com::sun::star::io
;
49 using namespace com::sun::star::util
;
53 void lcl_throwError(sal_uInt16 _nErrorId
)
55 ::connectivity::SharedResources aResources
;
56 const OUString
sError( aResources
.getResourceString(_nErrorId
) );
57 ::dbtools::throwGenericSQLException(sError
,NULL
);
61 IMPLEMENT_SERVICE_INFO(KabStatement
, "com.sun.star.sdbc.drivers.KabStatement", "com.sun.star.sdbc.Statement");
63 KabCommonStatement::KabCommonStatement(KabConnection
* _pConnection
)
64 : KabCommonStatement_BASE(m_aMutex
),
65 OPropertySetHelper(KabCommonStatement_BASE::rBHelper
),
66 m_aParser(_pConnection
->getComponentContext()),
67 m_aSQLIterator(_pConnection
, _pConnection
->createCatalog()->getTables(), m_aParser
, NULL
),
69 m_pConnection(_pConnection
),
70 rBHelper(KabCommonStatement_BASE::rBHelper
)
72 m_pConnection
->acquire();
75 KabCommonStatement::~KabCommonStatement()
79 void KabCommonStatement::disposing()
81 KabCommonStatement_BASE::disposing();
84 void KabCommonStatement::resetParameters() const throw(::com::sun::star::sdbc::SQLException
)
86 lcl_throwError(STR_PARA_ONLY_PREPARED
);
89 void KabCommonStatement::getNextParameter(OUString
&) const throw(::com::sun::star::sdbc::SQLException
)
91 lcl_throwError(STR_PARA_ONLY_PREPARED
);
94 KabCondition
*KabCommonStatement::analyseWhereClause(const OSQLParseNode
*pParseNode
) const throw(SQLException
)
96 if (pParseNode
->count() == 3)
98 const OSQLParseNode
*pLeft
= pParseNode
->getChild(0),
99 *pMiddle
= pParseNode
->getChild(1),
100 *pRight
= pParseNode
->getChild(2);
103 if (SQL_ISPUNCTUATION(pLeft
, "(") && SQL_ISPUNCTUATION(pRight
, ")"))
105 return analyseWhereClause(pMiddle
);
107 else if (SQL_ISRULE(pParseNode
, comparison_predicate
))
109 if (pLeft
->isToken() && pRight
->isToken())
111 switch (pMiddle
->getNodeType())
115 return new KabConditionConstant(pLeft
->getTokenValue() == pRight
->getTokenValue());
117 case SQL_NODE_NOTEQUAL
:
119 // (might not be correct SQL... don't care, handling anyway)
120 return new KabConditionConstant(pLeft
->getTokenValue() != pRight
->getTokenValue());
126 else if (SQL_ISRULE(pLeft
, column_ref
))
128 OUString sColumnName
,
131 m_aSQLIterator
.getColumnRange(pLeft
, sColumnName
, sTableRange
);
133 if (pRight
->isToken() || SQL_ISRULE(pRight
, parameter
))
135 OUString sMatchString
;
137 if (pRight
->isToken()) // WHERE Name = 'Doe'
138 sMatchString
= pRight
->getTokenValue();
139 else if (SQL_ISRULE(pRight
, parameter
)) // WHERE Name = ?
140 getNextParameter(sMatchString
);
142 switch (pMiddle
->getNodeType())
145 // WHERE Name = 'Smith'
146 return new KabConditionEqual(sColumnName
, sMatchString
);
148 case SQL_NODE_NOTEQUAL
:
149 // WHERE Name <> 'Jones'
150 return new KabConditionDifferent(sColumnName
, sMatchString
);
158 else if (SQL_ISRULE(pParseNode
, search_condition
))
160 if (SQL_ISTOKEN(pMiddle
, OR
))
162 // WHERE Name = 'Smith' OR Name = 'Jones'
163 return new KabConditionOr(
164 analyseWhereClause(pLeft
),
165 analyseWhereClause(pRight
));
168 else if (SQL_ISRULE(pParseNode
, boolean_term
))
170 if (SQL_ISTOKEN(pMiddle
, AND
))
172 // WHERE Name = 'Smith' AND "Given Name" = 'Peter'
173 return new KabConditionAnd(
174 analyseWhereClause(pLeft
),
175 analyseWhereClause(pRight
));
179 else if (SQL_ISRULE(pParseNode
, test_for_null
) || SQL_ISRULE(pParseNode
, like_predicate
))
181 const OSQLParseNode
*pLeft
= pParseNode
->getChild(0);
182 const OSQLParseNode
* pPart2
= pParseNode
->getChild(1);
183 const OSQLParseNode
*pMiddleLeft
= pPart2
->getChild(0),
184 *pMiddleRight
= pPart2
->getChild(1),
185 *pRight
= pPart2
->getChild(2);
187 if (SQL_ISRULE(pParseNode
, test_for_null
))
189 if (SQL_ISRULE(pLeft
, column_ref
) &&
190 SQL_ISTOKEN(pMiddleLeft
, IS
) &&
191 SQL_ISTOKEN(pRight
, NULL
))
193 OUString sColumnName
,
196 m_aSQLIterator
.getColumnRange(pLeft
, sColumnName
, sTableRange
);
198 if (SQL_ISTOKEN(pMiddleRight
, NOT
))
200 // WHERE "Mobile Phone" IS NOT NULL
201 return new KabConditionNotNull(sColumnName
);
205 // WHERE "Mobile Phone" IS NULL
206 return new KabConditionNull(sColumnName
);
210 else if (SQL_ISRULE(pParseNode
, like_predicate
))
212 if (SQL_ISRULE(pLeft
, column_ref
))
214 OUString sColumnName
,
217 m_aSQLIterator
.getColumnRange(pLeft
, sColumnName
, sTableRange
);
219 if (pMiddleRight
->isToken() || SQL_ISRULE(pMiddleRight
, parameter
))
221 OUString sMatchString
;
223 if (pMiddleRight
->isToken()) // WHERE Name LIKE 'Sm%'
224 sMatchString
= pMiddleRight
->getTokenValue();
225 else if (SQL_ISRULE(pMiddleRight
, parameter
)) // WHERE Name LIKE ?
226 getNextParameter(sMatchString
);
228 return new KabConditionSimilar(sColumnName
, sMatchString
);
234 lcl_throwError(STR_QUERY_TOO_COMPLEX
);
241 KabOrder
*KabCommonStatement::analyseOrderByClause(const OSQLParseNode
*pParseNode
) const throw(SQLException
)
243 if (SQL_ISRULE(pParseNode
, ordering_spec_commalist
))
245 KabComplexOrder
*list
= new KabComplexOrder();
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();
274 !SQL_ISTOKEN(pAscendingDescending
, DESC
);
276 return new KabSimpleOrder(sColumnName
, bAscending
);
281 lcl_throwError(STR_QUERY_TOO_COMPLEX
);
287 bool KabCommonStatement::isTableKnown(KabResultSet
*pResult
) const
289 // can handle requests like SELECT * FROM addresses addresses
290 // but cannot handle requests like SELECT * FROM addresses persons
291 if (m_aSQLIterator
.getTables().size() != 1)
294 if (m_aSQLIterator
.getTables().begin()->first
!= pResult
->getMetaData()->getTableName(0))
300 void KabCommonStatement::setKabFields(KabResultSet
*pResult
) const throw(SQLException
)
302 ::rtl::Reference
<connectivity::OSQLColumns
> xColumns
; // selected columns
304 xColumns
= m_aSQLIterator
.getSelectColumns();
307 lcl_throwError(STR_INVALID_COLUMN_SELECTION
);
309 pResult
->getKabMetaData()->setKabFields(xColumns
);
312 void KabCommonStatement::selectAddressees(KabResultSet
*pResult
) const throw(SQLException
)
314 const OSQLParseNode
*pParseNode
;
316 pParseNode
= m_aSQLIterator
.getWhereTree();
317 if (pParseNode
!= NULL
)
319 if (SQL_ISRULE(pParseNode
, where_clause
))
322 pParseNode
= pParseNode
->getChild(1);
323 KabCondition
*pCondition
= analyseWhereClause(pParseNode
);
324 if (pCondition
->isAlwaysTrue())
325 pResult
->allKabAddressees();
326 else if (!pCondition
->isAlwaysFalse())
327 pResult
->someKabAddressees(pCondition
);
333 // no WHERE clause: get all rows
334 pResult
->allKabAddressees();
337 void KabCommonStatement::sortAddressees(KabResultSet
*pResult
) const throw(SQLException
)
339 const OSQLParseNode
*pParseNode
;
341 pParseNode
= m_aSQLIterator
.getOrderTree();
342 if (pParseNode
!= NULL
)
344 if (SQL_ISRULE(pParseNode
, opt_order_by_clause
))
346 pParseNode
= pParseNode
->getChild(2);
347 KabOrder
*pOrder
= analyseOrderByClause(pParseNode
);
348 pResult
->sortKabAddressees(pOrder
);
354 Any SAL_CALL
KabCommonStatement::queryInterface( const Type
& rType
) throw(RuntimeException
, std::exception
)
356 Any aRet
= KabCommonStatement_BASE::queryInterface(rType
);
357 if (!aRet
.hasValue())
358 aRet
= OPropertySetHelper::queryInterface(rType
);
362 Sequence
< Type
> SAL_CALL
KabCommonStatement::getTypes( ) throw(RuntimeException
, std::exception
)
364 ::cppu::OTypeCollection
aTypes( cppu::UnoType
<XMultiPropertySet
>::get(),
365 cppu::UnoType
<XFastPropertySet
>::get(),
366 cppu::UnoType
<XPropertySet
>::get());
368 return comphelper::concatSequences(aTypes
.getTypes(),KabCommonStatement_BASE::getTypes());
371 void SAL_CALL
KabCommonStatement::cancel( ) throw(RuntimeException
, std::exception
)
373 ::osl::MutexGuard
aGuard( m_aMutex
);
375 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
376 // cancel the current sql statement
379 void SAL_CALL
KabCommonStatement::close( ) throw(SQLException
, RuntimeException
, std::exception
)
382 ::osl::MutexGuard
aGuard( m_aMutex
);
383 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
389 sal_Bool SAL_CALL
KabCommonStatement::execute(
390 const OUString
& sql
) throw(SQLException
, RuntimeException
, std::exception
)
392 ::osl::MutexGuard
aGuard( m_aMutex
);
393 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
395 Reference
< XResultSet
> xRS
= executeQuery(sql
);
400 Reference
< XResultSet
> SAL_CALL
KabCommonStatement::executeQuery(
401 const OUString
& sql
) throw(SQLException
, RuntimeException
, std::exception
)
403 ::osl::MutexGuard
aGuard( m_aMutex
);
404 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
406 OSL_TRACE("KDE Address book - SQL Request: %s", OUtoCStr(sql
));
408 KabResultSet
* pResult
= new KabResultSet(this);
409 Reference
< XResultSet
> xRS
= pResult
;
412 m_pParseTree
= m_aParser
.parseTree(aErr
, sql
);
413 if (m_pParseTree
== NULL
)
414 throw SQLException(aErr
, *this, aErr
, 0, Any());
416 m_aSQLIterator
.setParseTree(m_pParseTree
);
417 m_aSQLIterator
.traverseAll();
418 switch (m_aSQLIterator
.getStatementType())
420 case SQL_STATEMENT_SELECT
:
421 if (isTableKnown(pResult
)) // FROM which table ?
423 setKabFields(pResult
); // SELECT which columns ?
424 selectAddressees(pResult
); // WHERE which condition ?
425 sortAddressees(pResult
); // ORDER BY which columns ?
426 // To be continued: DISTINCT
432 // To be continued: UPDATE
435 lcl_throwError(STR_QUERY_TOO_COMPLEX
);
441 Reference
< XConnection
> SAL_CALL
KabCommonStatement::getConnection( ) throw(SQLException
, RuntimeException
, std::exception
)
443 ::osl::MutexGuard
aGuard( m_aMutex
);
444 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
446 // just return our connection here
447 return m_pConnection
;
450 sal_Int32 SAL_CALL
KabCommonStatement::executeUpdate( const OUString
& ) throw(SQLException
, RuntimeException
, std::exception
)
452 ::osl::MutexGuard
aGuard( m_aMutex
);
453 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
455 // the return values gives information about how many rows are affected by executing the sql statement
459 Any SAL_CALL
KabCommonStatement::getWarnings( ) throw(SQLException
, RuntimeException
, std::exception
)
461 ::osl::MutexGuard
aGuard( m_aMutex
);
462 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
464 return makeAny(m_aLastWarning
);
467 void SAL_CALL
KabCommonStatement::clearWarnings( ) throw(SQLException
, RuntimeException
, std::exception
)
469 ::osl::MutexGuard
aGuard( m_aMutex
);
470 checkDisposed(KabCommonStatement_BASE::rBHelper
.bDisposed
);
472 m_aLastWarning
= SQLWarning();
475 ::cppu::IPropertyArrayHelper
* KabCommonStatement::createArrayHelper( ) const
477 // this properties are defined by the service statement
478 // they must be in alphabetic order
479 Sequence
< Property
> aProps(10);
480 Property
* pProperties
= aProps
.getArray();
482 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME
),
483 PROPERTY_ID_CURSORNAME
, cppu::UnoType
<OUString
>::get(), 0);
484 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING
),
485 PROPERTY_ID_ESCAPEPROCESSING
, cppu::UnoType
<bool>::get(), 0);
486 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION
),
487 PROPERTY_ID_FETCHDIRECTION
, cppu::UnoType
<sal_Int32
>::get(), 0);
488 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE
),
489 PROPERTY_ID_FETCHSIZE
, cppu::UnoType
<sal_Int32
>::get(), 0);
490 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE
),
491 PROPERTY_ID_MAXFIELDSIZE
, cppu::UnoType
<sal_Int32
>::get(), 0);
492 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS
),
493 PROPERTY_ID_MAXROWS
, cppu::UnoType
<sal_Int32
>::get(), 0);
494 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT
),
495 PROPERTY_ID_QUERYTIMEOUT
, cppu::UnoType
<sal_Int32
>::get(), 0);
496 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY
),
497 PROPERTY_ID_RESULTSETCONCURRENCY
, cppu::UnoType
<sal_Int32
>::get(), 0);
498 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE
),
499 PROPERTY_ID_RESULTSETTYPE
, cppu::UnoType
<sal_Int32
>::get(), 0);
500 pProperties
[nPos
++] = ::com::sun::star::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS
),
501 PROPERTY_ID_USEBOOKMARKS
, cppu::UnoType
<bool>::get(), 0);
503 return new ::cppu::OPropertyArrayHelper(aProps
);
506 ::cppu::IPropertyArrayHelper
& KabCommonStatement::getInfoHelper()
508 return *getArrayHelper();
511 sal_Bool
KabCommonStatement::convertFastPropertyValue(
515 const Any
&) throw (::com::sun::star::lang::IllegalArgumentException
)
517 bool bConverted
= false;
518 // here we have to try to convert
522 void KabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
,const Any
&) throw (Exception
, std::exception
)
524 // set the value to whatever is necessary
527 case PROPERTY_ID_QUERYTIMEOUT
:
528 case PROPERTY_ID_MAXFIELDSIZE
:
529 case PROPERTY_ID_MAXROWS
:
530 case PROPERTY_ID_CURSORNAME
:
531 case PROPERTY_ID_RESULTSETCONCURRENCY
:
532 case PROPERTY_ID_RESULTSETTYPE
:
533 case PROPERTY_ID_FETCHDIRECTION
:
534 case PROPERTY_ID_FETCHSIZE
:
535 case PROPERTY_ID_ESCAPEPROCESSING
:
536 case PROPERTY_ID_USEBOOKMARKS
:
542 void KabCommonStatement::getFastPropertyValue(Any
&,sal_Int32 nHandle
) const
546 case PROPERTY_ID_QUERYTIMEOUT
:
547 case PROPERTY_ID_MAXFIELDSIZE
:
548 case PROPERTY_ID_MAXROWS
:
549 case PROPERTY_ID_CURSORNAME
:
550 case PROPERTY_ID_RESULTSETCONCURRENCY
:
551 case PROPERTY_ID_RESULTSETTYPE
:
552 case PROPERTY_ID_FETCHDIRECTION
:
553 case PROPERTY_ID_FETCHSIZE
:
554 case PROPERTY_ID_ESCAPEPROCESSING
:
555 case PROPERTY_ID_USEBOOKMARKS
:
561 void SAL_CALL
KabCommonStatement::acquire() throw()
563 KabCommonStatement_BASE::acquire();
566 void SAL_CALL
KabCommonStatement::release() throw()
568 KabCommonStatement_BASE::release();
571 Reference
< ::com::sun::star::beans::XPropertySetInfo
> SAL_CALL
KabCommonStatement::getPropertySetInfo( ) throw(RuntimeException
, std::exception
)
573 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
576 KabStatement::KabStatement(KabConnection
* _pConnection
)
577 : KabStatement_BASE(_pConnection
)
581 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */