1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_connectivity.hxx"
26
27 #include "KStatement.hxx"
28 #include "KConnection.hxx"
29 #include "KDriver.hxx"
30 #include "KResultSet.hxx"
31 #include "KResultSetMetaData.hxx"
32 #include "kcondition.hxx"
33 #include "korder.hxx"
34 #include "TConnection.hxx"
35 #include <connectivity/dbexception.hxx>
36 #include "resource/kab_res.hrc"
37 #include "resource/sharedresources.hxx"
38
39
40 #if OSL_DEBUG_LEVEL > 0
41 # define OUtoCStr( x ) ( ::rtl::OUStringToOString ( (x), RTL_TEXTENCODING_ASCII_US).getStr())
42 #else /* OSL_DEBUG_LEVEL */
43 # define OUtoCStr( x ) ("dummy")
44 #endif /* OSL_DEBUG_LEVEL */
45
46 using namespace connectivity::kab;
47 using namespace com::sun::star::uno;
48 using namespace com::sun::star::lang;
49 using namespace com::sun::star::beans;
50 using namespace com::sun::star::sdbc;
51 using namespace com::sun::star::sdbcx;
52 using namespace com::sun::star::container;
53 using namespace com::sun::star::io;
54 using namespace com::sun::star::util;
55
56 namespace
57 {
lcl_throwError(sal_uInt16 _nErrorId)58 void lcl_throwError(sal_uInt16 _nErrorId)
59 {
60 ::connectivity::SharedResources aResources;
61 const ::rtl::OUString sError( aResources.getResourceString(_nErrorId) );
62 ::dbtools::throwGenericSQLException(sError,NULL);
63 }
64 }
65
66 IMPLEMENT_SERVICE_INFO(KabStatement, "com.sun.star.sdbc.drivers.KabStatement", "com.sun.star.sdbc.Statement");
67 //------------------------------------------------------------------------------
KabCommonStatement(KabConnection * _pConnection)68 KabCommonStatement::KabCommonStatement(KabConnection* _pConnection )
69 : KabCommonStatement_BASE(m_aMutex),
70 OPropertySetHelper(KabCommonStatement_BASE::rBHelper),
71 m_aParser(_pConnection->getDriver()->getMSFactory()),
72 m_aSQLIterator(_pConnection, _pConnection->createCatalog()->getTables(), m_aParser, NULL ),
73 m_pParseTree(NULL),
74 m_pConnection(_pConnection),
75 rBHelper(KabCommonStatement_BASE::rBHelper)
76 {
77 m_pConnection->acquire();
78 }
79 // -----------------------------------------------------------------------------
~KabCommonStatement()80 KabCommonStatement::~KabCommonStatement()
81 {
82 }
83 // -----------------------------------------------------------------------------
disposing()84 void KabCommonStatement::disposing()
85 {
86 KabCommonStatement_BASE::disposing();
87 }
88 // -----------------------------------------------------------------------------
resetParameters() const89 void KabCommonStatement::resetParameters() const throw(::com::sun::star::sdbc::SQLException)
90 {
91 lcl_throwError(STR_PARA_ONLY_PREPARED);
92 }
93 // -----------------------------------------------------------------------------
getNextParameter(::rtl::OUString &) const94 void KabCommonStatement::getNextParameter(::rtl::OUString &) const throw(::com::sun::star::sdbc::SQLException)
95 {
96 lcl_throwError(STR_PARA_ONLY_PREPARED);
97 }
98 // -----------------------------------------------------------------------------
analyseWhereClause(const OSQLParseNode * pParseNode) const99 KabCondition *KabCommonStatement::analyseWhereClause(const OSQLParseNode *pParseNode) const throw(SQLException)
100 {
101 if (pParseNode->count() == 3)
102 {
103 const OSQLParseNode *pLeft = pParseNode->getChild(0),
104 *pMiddle = pParseNode->getChild(1),
105 *pRight = pParseNode->getChild(2);
106
107 // WHERE ( ... ) ?
108 if (SQL_ISPUNCTUATION(pLeft, "(") && SQL_ISPUNCTUATION(pRight, ")"))
109 {
110 return analyseWhereClause(pMiddle);
111 }
112 else if (SQL_ISRULE(pParseNode, comparison_predicate))
113 {
114 if (pLeft->isToken() && pRight->isToken())
115 {
116 switch (pMiddle->getNodeType())
117 {
118 case SQL_NODE_EQUAL:
119 // WHERE 0 = 1
120 return new KabConditionConstant(pLeft->getTokenValue() == pRight->getTokenValue());
121
122 case SQL_NODE_NOTEQUAL:
123 // WHERE 0 <> 1
124 // (might not be correct SQL... don't care, handling anyway)
125 return new KabConditionConstant(pLeft->getTokenValue() != pRight->getTokenValue());
126
127 default:
128 break;
129 }
130 }
131 else if (SQL_ISRULE(pLeft, column_ref))
132 {
133 ::rtl::OUString sColumnName,
134 sTableRange;
135
136 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
137
138 if (pRight->isToken() || SQL_ISRULE(pRight, parameter))
139 {
140 ::rtl::OUString sMatchString;
141
142 if (pRight->isToken()) // WHERE Name = 'Doe'
143 sMatchString = pRight->getTokenValue();
144 else if (SQL_ISRULE(pRight, parameter)) // WHERE Name = ?
145 getNextParameter(sMatchString);
146
147 switch (pMiddle->getNodeType())
148 {
149 case SQL_NODE_EQUAL:
150 // WHERE Name = 'Smith'
151 return new KabConditionEqual(sColumnName, sMatchString);
152
153 case SQL_NODE_NOTEQUAL:
154 // WHERE Name <> 'Jones'
155 return new KabConditionDifferent(sColumnName, sMatchString);
156
157 default:
158 break;
159 }
160 }
161 }
162 }
163 else if (SQL_ISRULE(pParseNode, search_condition))
164 {
165 if (SQL_ISTOKEN(pMiddle, OR))
166 {
167 // WHERE Name = 'Smith' OR Name = 'Jones'
168 return new KabConditionOr(
169 analyseWhereClause(pLeft),
170 analyseWhereClause(pRight));
171 }
172 }
173 else if (SQL_ISRULE(pParseNode, boolean_term))
174 {
175 if (SQL_ISTOKEN(pMiddle, AND))
176 {
177 // WHERE Name = 'Smith' AND "Given Name" = 'Peter'
178 return new KabConditionAnd(
179 analyseWhereClause(pLeft),
180 analyseWhereClause(pRight));
181 }
182 }
183 }
184 else if (SQL_ISRULE(pParseNode, test_for_null) || SQL_ISRULE(pParseNode, like_predicate))
185 {
186 const OSQLParseNode *pLeft = pParseNode->getChild(0);
187 const OSQLParseNode* pPart2 = pParseNode->getChild(1);
188 const OSQLParseNode *pMiddleLeft = pPart2->getChild(0),
189 *pMiddleRight = pPart2->getChild(1),
190 *pRight = pPart2->getChild(2);
191
192 if (SQL_ISRULE(pParseNode, test_for_null))
193 {
194 if (SQL_ISRULE(pLeft, column_ref) &&
195 SQL_ISTOKEN(pMiddleLeft, IS) &&
196 SQL_ISTOKEN(pRight, NULL))
197 {
198 ::rtl::OUString sColumnName,
199 sTableRange;
200
201 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
202
203 if (SQL_ISTOKEN(pMiddleRight, NOT))
204 {
205 // WHERE "Mobile Phone" IS NOT NULL
206 return new KabConditionNotNull(sColumnName);
207 }
208 else
209 {
210 // WHERE "Mobile Phone" IS NULL
211 return new KabConditionNull(sColumnName);
212 }
213 }
214 }
215 else if (SQL_ISRULE(pParseNode, like_predicate))
216 {
217 if (SQL_ISRULE(pLeft, column_ref))
218 {
219 ::rtl::OUString sColumnName,
220 sTableRange;
221
222 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
223
224 if (pMiddleRight->isToken() || SQL_ISRULE(pMiddleRight, parameter))
225 {
226 ::rtl::OUString sMatchString;
227
228 if (pMiddleRight->isToken()) // WHERE Name LIKE 'Sm%'
229 sMatchString = pMiddleRight->getTokenValue();
230 else if (SQL_ISRULE(pMiddleRight, parameter)) // WHERE Name LIKE ?
231 getNextParameter(sMatchString);
232
233 return new KabConditionSimilar(sColumnName, sMatchString);
234 }
235 }
236 }
237 }
238
239 lcl_throwError(STR_QUERY_TOO_COMPLEX);
240
241 // Unreachable:
242 OSL_ASSERT(false);
243 return 0;
244 }
245 // -----------------------------------------------------------------------------
analyseOrderByClause(const OSQLParseNode * pParseNode) const246 KabOrder *KabCommonStatement::analyseOrderByClause(const OSQLParseNode *pParseNode) const throw(SQLException)
247 {
248 if (SQL_ISRULE(pParseNode, ordering_spec_commalist))
249 {
250 KabComplexOrder *list = new KabComplexOrder();
251 sal_uInt32 n = pParseNode->count();
252
253 // Iterate through the ordering columns
254 for (sal_uInt32 i = 0; i < n; i++)
255 {
256 list->addOrder
257 (analyseOrderByClause(pParseNode->getChild(i)));
258 }
259
260 return list;
261 }
262 else if (SQL_ISRULE(pParseNode, ordering_spec))
263 {
264 if (pParseNode->count() == 2)
265 {
266 OSQLParseNode* pColumnRef = pParseNode->getChild(0);
267 OSQLParseNode* pAscendingDescending = pParseNode->getChild(1);
268
269 if (SQL_ISRULE(pColumnRef, column_ref))
270 {
271 if (pColumnRef->count() == 3)
272 pColumnRef = pColumnRef->getChild(2);
273
274 if (pColumnRef->count() == 1)
275 {
276 ::rtl::OUString sColumnName =
277 pColumnRef->getChild(0)->getTokenValue();
278 sal_Bool bAscending =
279 SQL_ISTOKEN(pAscendingDescending, DESC)?
280 sal_False:
281 sal_True;
282
283 return new KabSimpleOrder(sColumnName, bAscending);
284 }
285 }
286 }
287 }
288 lcl_throwError(STR_QUERY_TOO_COMPLEX);
289 // Unreachable:
290 OSL_ASSERT(false);
291 return 0;
292 }
293 //------------------------------------------------------------------------------
isTableKnown(KabResultSet * pResult) const294 sal_Bool KabCommonStatement::isTableKnown(KabResultSet *pResult) const
295 {
296 // can handle requests like SELECT * FROM addresses addresses
297 // but cannot handle requests like SELECT * FROM addresses persons
298 if (m_aSQLIterator.getTables().size() != 1)
299 return sal_False;
300
301 if (m_aSQLIterator.getTables().begin()->first != pResult->getMetaData()->getTableName(0))
302 return sal_False;
303
304 return sal_True;
305 }
306 //------------------------------------------------------------------------------
setKabFields(KabResultSet * pResult) const307 void KabCommonStatement::setKabFields(KabResultSet *pResult) const throw(SQLException)
308 {
309 ::vos::ORef<connectivity::OSQLColumns> xColumns; // selected columns
310 KabResultSetMetaData *pMeta; // meta information - holds the list of KAddressBook fields
311
312 xColumns = m_aSQLIterator.getSelectColumns();
313 if (!xColumns.isValid())
314 {
315 lcl_throwError(STR_INVALID_COLUMN_SELECTION);
316 }
317 pMeta = static_cast<KabResultSetMetaData *>(pResult->getMetaData().get());
318 pMeta->setKabFields(xColumns);
319 }
320 // -------------------------------------------------------------------------
selectAddressees(KabResultSet * pResult) const321 void KabCommonStatement::selectAddressees(KabResultSet *pResult) const throw(SQLException)
322 {
323 const OSQLParseNode *pParseNode;
324 KabCondition *pCondition;
325
326 pParseNode = m_aSQLIterator.getWhereTree();
327 if (pParseNode != NULL)
328 {
329 if (SQL_ISRULE(pParseNode, where_clause))
330 {
331 resetParameters();
332 pParseNode = pParseNode->getChild(1);
333 pCondition = analyseWhereClause(pParseNode);
334 if (pCondition->isAlwaysTrue())
335 pResult->allKabAddressees();
336 else if (!pCondition->isAlwaysFalse())
337 pResult->someKabAddressees(pCondition);
338 delete pCondition;
339 return;
340 }
341 }
342
343 // no WHERE clause: get all rows
344 pResult->allKabAddressees();
345 }
346 // -------------------------------------------------------------------------
sortAddressees(KabResultSet * pResult) const347 void KabCommonStatement::sortAddressees(KabResultSet *pResult) const throw(SQLException)
348 {
349 const OSQLParseNode *pParseNode;
350 KabOrder *pOrder;
351
352 pParseNode = m_aSQLIterator.getOrderTree();
353 if (pParseNode != NULL)
354 {
355 if (SQL_ISRULE(pParseNode, opt_order_by_clause))
356 {
357 pParseNode = pParseNode->getChild(2);
358 pOrder = analyseOrderByClause(pParseNode);
359 pResult->sortKabAddressees(pOrder);
360 delete pOrder;
361 }
362 }
363 }
364 //-----------------------------------------------------------------------------
queryInterface(const Type & rType)365 Any SAL_CALL KabCommonStatement::queryInterface( const Type & rType ) throw(RuntimeException)
366 {
367 Any aRet = KabCommonStatement_BASE::queryInterface(rType);
368 if (!aRet.hasValue())
369 aRet = OPropertySetHelper::queryInterface(rType);
370 return aRet;
371 }
372 // -------------------------------------------------------------------------
getTypes()373 Sequence< Type > SAL_CALL KabCommonStatement::getTypes( ) throw(RuntimeException)
374 {
375 ::cppu::OTypeCollection aTypes( ::getCppuType( (const Reference< XMultiPropertySet > *)0 ),
376 ::getCppuType( (const Reference< XFastPropertySet > *)0 ),
377 ::getCppuType( (const Reference< XPropertySet > *)0 ));
378
379 return comphelper::concatSequences(aTypes.getTypes(),KabCommonStatement_BASE::getTypes());
380 }
381 // -------------------------------------------------------------------------
cancel()382 void SAL_CALL KabCommonStatement::cancel( ) throw(RuntimeException)
383 {
384 ::osl::MutexGuard aGuard( m_aMutex );
385
386 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
387 // cancel the current sql statement
388 }
389 // -------------------------------------------------------------------------
close()390 void SAL_CALL KabCommonStatement::close( ) throw(SQLException, RuntimeException)
391 {
392 {
393 ::osl::MutexGuard aGuard( m_aMutex );
394 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
395
396 }
397 dispose();
398 }
399 // -------------------------------------------------------------------------
execute(const::rtl::OUString & sql)400 sal_Bool SAL_CALL KabCommonStatement::execute(
401 const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
402 {
403 ::osl::MutexGuard aGuard( m_aMutex );
404 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
405
406 Reference< XResultSet > xRS = executeQuery(sql);
407
408 return xRS.is();
409 }
410 // -------------------------------------------------------------------------
executeQuery(const::rtl::OUString & sql)411 Reference< XResultSet > SAL_CALL KabCommonStatement::executeQuery(
412 const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
413 {
414 ::osl::MutexGuard aGuard( m_aMutex );
415 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
416
417 OSL_TRACE("KDE Address book - SQL Request: %s", OUtoCStr(sql));
418
419 KabResultSet* pResult = new KabResultSet(this);
420 Reference< XResultSet > xRS = pResult;
421 ::rtl::OUString aErr;
422
423 m_pParseTree = m_aParser.parseTree(aErr, sql);
424 if (m_pParseTree == NULL)
425 throw SQLException(aErr, *this, aErr, 0, Any());
426
427 m_aSQLIterator.setParseTree(m_pParseTree);
428 m_aSQLIterator.traverseAll();
429 switch (m_aSQLIterator.getStatementType())
430 {
431 case SQL_STATEMENT_SELECT:
432 if (isTableKnown(pResult)) // FROM which table ?
433 {
434 setKabFields(pResult); // SELECT which columns ?
435 selectAddressees(pResult); // WHERE which condition ?
436 sortAddressees(pResult); // ORDER BY which columns ?
437 // To be continued: DISTINCT
438 // etc...
439 }
440 break;
441
442 default:
443 // To be continued: UPDATE
444 // DELETE
445 // etc...
446 lcl_throwError(STR_QUERY_TOO_COMPLEX);
447 }
448
449 return xRS;
450 }
451 // -------------------------------------------------------------------------
getConnection()452 Reference< XConnection > SAL_CALL KabCommonStatement::getConnection( ) throw(SQLException, RuntimeException)
453 {
454 ::osl::MutexGuard aGuard( m_aMutex );
455 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
456
457 // just return our connection here
458 return (Reference< XConnection >) m_pConnection;
459 }
460 // -------------------------------------------------------------------------
executeUpdate(const::rtl::OUString &)461 sal_Int32 SAL_CALL KabCommonStatement::executeUpdate( const ::rtl::OUString& ) throw(SQLException, RuntimeException)
462 {
463 ::osl::MutexGuard aGuard( m_aMutex );
464 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
465
466 // the return values gives information about how many rows are affected by executing the sql statement
467 return 0;
468 }
469 // -------------------------------------------------------------------------
getWarnings()470 Any SAL_CALL KabCommonStatement::getWarnings( ) throw(SQLException, RuntimeException)
471 {
472 ::osl::MutexGuard aGuard( m_aMutex );
473 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
474
475 return makeAny(m_aLastWarning);
476 }
477 // -------------------------------------------------------------------------
clearWarnings()478 void SAL_CALL KabCommonStatement::clearWarnings( ) throw(SQLException, RuntimeException)
479 {
480 ::osl::MutexGuard aGuard( m_aMutex );
481 checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
482
483 m_aLastWarning = SQLWarning();
484 }
485 // -------------------------------------------------------------------------
createArrayHelper() const486 ::cppu::IPropertyArrayHelper* KabCommonStatement::createArrayHelper( ) const
487 {
488 // this properties are defined by the service statement
489 // they must be in alphabetic order
490 Sequence< Property > aProps(10);
491 Property* pProperties = aProps.getArray();
492 sal_Int32 nPos = 0;
493 DECL_PROP0(CURSORNAME, ::rtl::OUString);
494 DECL_BOOL_PROP0(ESCAPEPROCESSING);
495 DECL_PROP0(FETCHDIRECTION,sal_Int32);
496 DECL_PROP0(FETCHSIZE, sal_Int32);
497 DECL_PROP0(MAXFIELDSIZE,sal_Int32);
498 DECL_PROP0(MAXROWS, sal_Int32);
499 DECL_PROP0(QUERYTIMEOUT,sal_Int32);
500 DECL_PROP0(RESULTSETCONCURRENCY,sal_Int32);
501 DECL_PROP0(RESULTSETTYPE,sal_Int32);
502 DECL_BOOL_PROP0(USEBOOKMARKS);
503
504 return new ::cppu::OPropertyArrayHelper(aProps);
505 }
506 // -------------------------------------------------------------------------
getInfoHelper()507 ::cppu::IPropertyArrayHelper & KabCommonStatement::getInfoHelper()
508 {
509 return *const_cast<KabCommonStatement*>(this)->getArrayHelper();
510 }
511 // -------------------------------------------------------------------------
convertFastPropertyValue(Any &,Any &,sal_Int32,const Any &)512 sal_Bool KabCommonStatement::convertFastPropertyValue(
513 Any &,
514 Any &,
515 sal_Int32,
516 const Any&) throw (::com::sun::star::lang::IllegalArgumentException)
517 {
518 sal_Bool bConverted = sal_False;
519 // here we have to try to convert
520 return bConverted;
521 }
522 // -------------------------------------------------------------------------
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any &)523 void KabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&) throw (Exception)
524 {
525 // set the value to whatever is nescessary
526 switch (nHandle)
527 {
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:
538 default:
539 ;
540 }
541 }
542 // -------------------------------------------------------------------------
getFastPropertyValue(Any &,sal_Int32 nHandle) const543 void KabCommonStatement::getFastPropertyValue(Any&,sal_Int32 nHandle) const
544 {
545 switch (nHandle)
546 {
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:
557 default:
558 ;
559 }
560 }
561 // -----------------------------------------------------------------------------
acquire()562 void SAL_CALL KabCommonStatement::acquire() throw()
563 {
564 KabCommonStatement_BASE::acquire();
565 }
566 // -----------------------------------------------------------------------------
release()567 void SAL_CALL KabCommonStatement::release() throw()
568 {
569 KabCommonStatement_BASE::release();
570 }
571 // -----------------------------------------------------------------------------
getPropertySetInfo()572 Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL KabCommonStatement::getPropertySetInfo( ) throw(RuntimeException)
573 {
574 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
575 }
576 // -----------------------------------------------------------------------------
KabStatement(KabConnection * _pConnection)577 KabStatement::KabStatement(KabConnection* _pConnection)
578 : KabStatement_BASE(_pConnection)
579 {
580 }
581