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