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 "MacabStatement.hxx" 28 #include "MacabConnection.hxx" 29 #include "MacabAddressBook.hxx" 30 #include "MacabDriver.hxx" 31 #include "MacabResultSet.hxx" 32 #include "MacabResultSetMetaData.hxx" 33 #include "macabcondition.hxx" 34 #include "macaborder.hxx" 35 #include "TConnection.hxx" 36 #include <connectivity/dbexception.hxx> 37 #include "resource/sharedresources.hxx" 38 #include "resource/macab_res.hrc" 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::macab; 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 connectivity 57 { 58 namespace macab 59 { 60 void impl_throwError(sal_uInt16 _nErrorId) 61 { 62 ::connectivity::SharedResources aResources; 63 const ::rtl::OUString sError( aResources.getResourceString(_nErrorId) ); 64 ::dbtools::throwGenericSQLException(sError,NULL); 65 } 66 } 67 } 68 69 IMPLEMENT_SERVICE_INFO(MacabStatement, "com.sun.star.sdbc.drivers.MacabStatement", "com.sun.star.sdbc.Statement"); 70 //------------------------------------------------------------------------------ 71 MacabCommonStatement::MacabCommonStatement(MacabConnection* _pConnection ) 72 : MacabCommonStatement_BASE(m_aMutex), 73 OPropertySetHelper(MacabCommonStatement_BASE::rBHelper), 74 m_aParser(_pConnection->getDriver()->getMSFactory()), 75 m_aSQLIterator(_pConnection, _pConnection->createCatalog()->getTables(), m_aParser, NULL ), 76 m_pParseTree(NULL), 77 m_pConnection(_pConnection), 78 rBHelper(MacabCommonStatement_BASE::rBHelper) 79 { 80 m_pConnection->acquire(); 81 } 82 // ----------------------------------------------------------------------------- 83 MacabCommonStatement::~MacabCommonStatement() 84 { 85 } 86 // ----------------------------------------------------------------------------- 87 void MacabCommonStatement::disposing() 88 { 89 MacabCommonStatement_BASE::disposing(); 90 } 91 // ----------------------------------------------------------------------------- 92 void MacabCommonStatement::resetParameters() const throw(::com::sun::star::sdbc::SQLException) 93 { 94 impl_throwError(STR_PARA_ONLY_PREPARED); 95 } 96 // ----------------------------------------------------------------------------- 97 void MacabCommonStatement::getNextParameter(::rtl::OUString &) const throw(::com::sun::star::sdbc::SQLException) 98 { 99 impl_throwError(STR_PARA_ONLY_PREPARED); 100 } 101 // ----------------------------------------------------------------------------- 102 MacabCondition *MacabCommonStatement::analyseWhereClause(const OSQLParseNode *pParseNode) const throw(SQLException) 103 { 104 if (pParseNode->count() == 3) 105 { 106 const OSQLParseNode *pLeft = pParseNode->getChild(0), 107 *pMiddle = pParseNode->getChild(1), 108 *pRight = pParseNode->getChild(2); 109 110 // WHERE ( ... ) ? 111 if (SQL_ISPUNCTUATION(pLeft, "(") && SQL_ISPUNCTUATION(pRight, ")")) 112 { 113 return analyseWhereClause(pMiddle); 114 } 115 else if (SQL_ISRULE(pParseNode, comparison_predicate)) 116 { 117 if (pLeft->isToken() && pRight->isToken()) 118 { 119 switch (pMiddle->getNodeType()) 120 { 121 case SQL_NODE_EQUAL: 122 // WHERE 0 = 1 123 return new MacabConditionConstant(pLeft->getTokenValue() == pRight->getTokenValue()); 124 125 case SQL_NODE_NOTEQUAL: 126 // WHERE 0 <> 1 127 // (might not be correct SQL... don't care, handling anyway) 128 return new MacabConditionConstant(pLeft->getTokenValue() != pRight->getTokenValue()); 129 130 default: 131 break; 132 } 133 } 134 else if (SQL_ISRULE(pLeft, column_ref)) 135 { 136 ::rtl::OUString sColumnName, 137 sTableRange; 138 139 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange); 140 141 if (pRight->isToken() || SQL_ISRULE(pRight, parameter)) 142 { 143 ::rtl::OUString sMatchString; 144 145 if (pRight->isToken()) // WHERE Name = 'Doe' 146 sMatchString = pRight->getTokenValue(); 147 else if (SQL_ISRULE(pRight, parameter)) // WHERE Name = ? 148 getNextParameter(sMatchString); 149 150 switch (pMiddle->getNodeType()) 151 { 152 case SQL_NODE_EQUAL: 153 // WHERE Name = 'Smith' 154 return new MacabConditionEqual(m_pHeader, sColumnName, sMatchString); 155 156 case SQL_NODE_NOTEQUAL: 157 // WHERE Name <> 'Jones' 158 return new MacabConditionDifferent(m_pHeader, sColumnName, sMatchString); 159 160 default: 161 break; 162 } 163 } 164 } 165 } 166 else if (SQL_ISRULE(pParseNode, search_condition)) 167 { 168 if (SQL_ISTOKEN(pMiddle, OR)) 169 { 170 // WHERE Name = 'Smith' OR Name = 'Jones' 171 return new MacabConditionOr( 172 analyseWhereClause(pLeft), 173 analyseWhereClause(pRight)); 174 } 175 } 176 else if (SQL_ISRULE(pParseNode, boolean_term)) 177 { 178 if (SQL_ISTOKEN(pMiddle, AND)) 179 { 180 // WHERE Name = 'Smith' AND "Given Name" = 'Peter' 181 return new MacabConditionAnd( 182 analyseWhereClause(pLeft), 183 analyseWhereClause(pRight)); 184 } 185 } 186 } 187 else if (SQL_ISRULE(pParseNode, test_for_null) || SQL_ISRULE(pParseNode, like_predicate)) 188 { 189 const OSQLParseNode *pLeft = pParseNode->getChild(0); 190 const OSQLParseNode* pPart2 = pParseNode->getChild(1); 191 const OSQLParseNode *pMiddleLeft = pPart2->getChild(0), 192 *pMiddleRight = pPart2->getChild(1), 193 *pRight = pPart2->getChild(2); 194 195 if (SQL_ISRULE(pParseNode, test_for_null)) 196 { 197 if (SQL_ISRULE(pLeft, column_ref) && 198 SQL_ISTOKEN(pMiddleLeft, IS) && 199 SQL_ISTOKEN(pRight, NULL)) 200 { 201 ::rtl::OUString sColumnName, 202 sTableRange; 203 204 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange); 205 206 if (SQL_ISTOKEN(pMiddleRight, NOT)) 207 { 208 // WHERE "Mobile Phone" IS NOT NULL 209 return new MacabConditionNotNull(m_pHeader, sColumnName); 210 } 211 else 212 { 213 // WHERE "Mobile Phone" IS NULL 214 return new MacabConditionNull(m_pHeader, sColumnName); 215 } 216 } 217 } 218 else if (SQL_ISRULE(pParseNode, like_predicate)) 219 { 220 if (SQL_ISRULE(pLeft, column_ref)) 221 { 222 ::rtl::OUString sColumnName, 223 sTableRange; 224 225 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange); 226 227 if (pMiddleRight->isToken() || SQL_ISRULE(pMiddleRight, parameter)) 228 { 229 ::rtl::OUString sMatchString; 230 231 if (pMiddleRight->isToken()) // WHERE Name LIKE 'Sm%' 232 sMatchString = pMiddleRight->getTokenValue(); 233 else if (SQL_ISRULE(pMiddleRight, parameter)) // WHERE Name LIKE ? 234 getNextParameter(sMatchString); 235 236 return new MacabConditionSimilar(m_pHeader, sColumnName, sMatchString); 237 } 238 } 239 } 240 } 241 impl_throwError(STR_QUERY_TOO_COMPLEX); 242 // Unreachable: 243 OSL_ASSERT(false); 244 return 0; 245 } 246 // ----------------------------------------------------------------------------- 247 MacabOrder *MacabCommonStatement::analyseOrderByClause(const OSQLParseNode *pParseNode) const throw(SQLException) 248 { 249 if (SQL_ISRULE(pParseNode, ordering_spec_commalist)) 250 { 251 MacabComplexOrder *list = new MacabComplexOrder(); 252 sal_uInt32 n = pParseNode->count(); 253 254 // Iterate through the ordering columns 255 for (sal_uInt32 i = 0; i < n; i++) 256 { 257 list->addOrder 258 (analyseOrderByClause(pParseNode->getChild(i))); 259 } 260 261 return list; 262 } 263 else if (SQL_ISRULE(pParseNode, ordering_spec)) 264 { 265 if (pParseNode->count() == 2) 266 { 267 OSQLParseNode* pColumnRef = pParseNode->getChild(0); 268 OSQLParseNode* pAscendingDescending = pParseNode->getChild(1); 269 270 if (SQL_ISRULE(pColumnRef, column_ref)) 271 { 272 if (pColumnRef->count() == 3) 273 pColumnRef = pColumnRef->getChild(2); 274 275 if (pColumnRef->count() == 1) 276 { 277 ::rtl::OUString sColumnName = 278 pColumnRef->getChild(0)->getTokenValue(); 279 sal_Bool bAscending = 280 SQL_ISTOKEN(pAscendingDescending, DESC)? 281 sal_False: 282 sal_True; 283 284 return new MacabSimpleOrder(m_pHeader, sColumnName, bAscending); 285 } 286 } 287 } 288 } 289 impl_throwError(STR_QUERY_TOO_COMPLEX); 290 // Unreachable: 291 OSL_ASSERT(false); 292 return 0; 293 } 294 //------------------------------------------------------------------------------ 295 ::rtl::OUString MacabCommonStatement::getTableName() const 296 { 297 const OSQLTables& xTabs = m_aSQLIterator.getTables(); 298 299 if( xTabs.empty() ) 300 return ::rtl::OUString(); 301 302 // can only deal with one table at a time 303 if(xTabs.size() > 1 || m_aSQLIterator.hasErrors() ) 304 return ::rtl::OUString(); 305 306 return xTabs.begin()->first; 307 } 308 //------------------------------------------------------------------------------ 309 void MacabCommonStatement::setMacabFields(MacabResultSet *pResult) const throw(SQLException) 310 { 311 ::vos::ORef<connectivity::OSQLColumns> xColumns; // selected columns 312 MacabResultSetMetaData *pMeta; // meta information - holds the list of AddressBook fields 313 314 xColumns = m_aSQLIterator.getSelectColumns(); 315 if (!xColumns.isValid()) 316 { 317 ::connectivity::SharedResources aResources; 318 const ::rtl::OUString sError( aResources.getResourceString( 319 STR_INVALID_COLUMN_SELECTION 320 ) ); 321 ::dbtools::throwGenericSQLException(sError,NULL); 322 } 323 pMeta = static_cast<MacabResultSetMetaData *>(pResult->getMetaData().get()); 324 pMeta->setMacabFields(xColumns); 325 } 326 // ------------------------------------------------------------------------- 327 void MacabCommonStatement::selectRecords(MacabResultSet *pResult) const throw(SQLException) 328 { 329 const OSQLParseNode *pParseNode; 330 MacabCondition *pCondition; 331 332 pParseNode = m_aSQLIterator.getWhereTree(); 333 if (pParseNode != NULL) 334 { 335 if (SQL_ISRULE(pParseNode, where_clause)) 336 { 337 // Since we don't support parameters, don't reset them. If we ever 338 // support them, uncomment this line and fix resetParameters. 339 //resetParameters(); 340 pParseNode = pParseNode->getChild(1); 341 pCondition = analyseWhereClause(pParseNode); 342 if (pCondition->isAlwaysTrue()) 343 pResult->allMacabRecords(); 344 else if (!pCondition->isAlwaysFalse()) 345 pResult->someMacabRecords(pCondition); 346 delete pCondition; 347 return; 348 } 349 } 350 351 // no WHERE clause: get all rows 352 pResult->allMacabRecords(); 353 } 354 // ------------------------------------------------------------------------- 355 void MacabCommonStatement::sortRecords(MacabResultSet *pResult) const throw(SQLException) 356 { 357 const OSQLParseNode *pParseNode; 358 MacabOrder *pOrder; 359 360 pParseNode = m_aSQLIterator.getOrderTree(); 361 if (pParseNode != NULL) 362 { 363 if (SQL_ISRULE(pParseNode, opt_order_by_clause)) 364 { 365 pParseNode = pParseNode->getChild(2); 366 pOrder = analyseOrderByClause(pParseNode); 367 pResult->sortMacabRecords(pOrder); 368 delete pOrder; 369 } 370 } 371 } 372 //----------------------------------------------------------------------------- 373 Any SAL_CALL MacabCommonStatement::queryInterface( const Type & rType ) throw(RuntimeException) 374 { 375 Any aRet = MacabCommonStatement_BASE::queryInterface(rType); 376 if (!aRet.hasValue()) 377 aRet = OPropertySetHelper::queryInterface(rType); 378 return aRet; 379 } 380 // ------------------------------------------------------------------------- 381 Sequence< Type > SAL_CALL MacabCommonStatement::getTypes( ) throw(RuntimeException) 382 { 383 ::cppu::OTypeCollection aTypes( ::getCppuType( (const Reference< XMultiPropertySet > *)0 ), 384 ::getCppuType( (const Reference< XFastPropertySet > *)0 ), 385 ::getCppuType( (const Reference< XPropertySet > *)0 )); 386 387 return comphelper::concatSequences(aTypes.getTypes(),MacabCommonStatement_BASE::getTypes()); 388 } 389 // ------------------------------------------------------------------------- 390 void SAL_CALL MacabCommonStatement::cancel( ) throw(RuntimeException) 391 { 392 ::osl::MutexGuard aGuard( m_aMutex ); 393 394 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); 395 // cancel the current sql statement 396 } 397 // ------------------------------------------------------------------------- 398 void SAL_CALL MacabCommonStatement::close( ) throw(SQLException, RuntimeException) 399 { 400 { 401 ::osl::MutexGuard aGuard( m_aMutex ); 402 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); 403 404 } 405 dispose(); 406 } 407 // ------------------------------------------------------------------------- 408 sal_Bool SAL_CALL MacabCommonStatement::execute( 409 const ::rtl::OUString& sql ) throw(SQLException, RuntimeException) 410 { 411 ::osl::MutexGuard aGuard( m_aMutex ); 412 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); 413 414 Reference< XResultSet > xRS = executeQuery(sql); 415 416 return xRS.is(); 417 } 418 // ------------------------------------------------------------------------- 419 Reference< XResultSet > SAL_CALL MacabCommonStatement::executeQuery( 420 const ::rtl::OUString& sql ) throw(SQLException, RuntimeException) 421 { 422 ::osl::MutexGuard aGuard( m_aMutex ); 423 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); 424 425 OSL_TRACE("Mac OS Address book - SQL Request: %s", OUtoCStr(sql)); 426 427 MacabResultSet* pResult = new MacabResultSet(this); 428 Reference< XResultSet > xRS = pResult; 429 ::rtl::OUString aErr; 430 431 m_pParseTree = m_aParser.parseTree(aErr, sql); 432 if (m_pParseTree == NULL) 433 throw SQLException(aErr, *this, aErr, 0, Any()); 434 435 m_aSQLIterator.setParseTree(m_pParseTree); 436 m_aSQLIterator.traverseAll(); 437 switch (m_aSQLIterator.getStatementType()) 438 { 439 case SQL_STATEMENT_SELECT: 440 { 441 ::rtl::OUString sTableName = getTableName(); // FROM which table ? 442 if (sTableName.getLength() != 0) // a match 443 { 444 MacabRecords *aRecords; 445 aRecords = m_pConnection->getAddressBook()->getMacabRecords(sTableName); 446 447 // In case, somehow, we don't have anything with the name m_sTableName 448 if(aRecords == NULL) 449 { 450 impl_throwError(STR_NO_TABLE); 451 } 452 else 453 { 454 m_pHeader = aRecords->getHeader(); 455 456 pResult->setTableName(sTableName); 457 458 setMacabFields(pResult); // SELECT which columns ? 459 selectRecords(pResult); // WHERE which condition ? 460 sortRecords(pResult); // ORDER BY which columns ? 461 } 462 // To be continued: DISTINCT 463 // etc... 464 } 465 } 466 break; 467 468 default: 469 // To be continued: UPDATE 470 // DELETE 471 // etc... 472 impl_throwError(STR_QUERY_TOO_COMPLEX); 473 } 474 475 m_xResultSet = Reference<XResultSet>(pResult); 476 return xRS; 477 } 478 // ------------------------------------------------------------------------- 479 Reference< XConnection > SAL_CALL MacabCommonStatement::getConnection( ) throw(SQLException, RuntimeException) 480 { 481 ::osl::MutexGuard aGuard( m_aMutex ); 482 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); 483 484 // just return our connection here 485 return (Reference< XConnection >) m_pConnection; 486 } 487 // ------------------------------------------------------------------------- 488 sal_Int32 SAL_CALL MacabCommonStatement::executeUpdate( const ::rtl::OUString& ) throw(SQLException, RuntimeException) 489 { 490 ::osl::MutexGuard aGuard( m_aMutex ); 491 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); 492 493 // the return values gives information about how many rows are affected by executing the sql statement 494 return 0; 495 } 496 // ------------------------------------------------------------------------- 497 Any SAL_CALL MacabCommonStatement::getWarnings( ) throw(SQLException, RuntimeException) 498 { 499 ::osl::MutexGuard aGuard( m_aMutex ); 500 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); 501 502 return makeAny(m_aLastWarning); 503 } 504 // ------------------------------------------------------------------------- 505 void SAL_CALL MacabCommonStatement::clearWarnings( ) throw(SQLException, RuntimeException) 506 { 507 ::osl::MutexGuard aGuard( m_aMutex ); 508 checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); 509 510 m_aLastWarning = SQLWarning(); 511 } 512 // ------------------------------------------------------------------------- 513 ::cppu::IPropertyArrayHelper* MacabCommonStatement::createArrayHelper( ) const 514 { 515 // this properties are defined by the service statement 516 // they must be in alphabetic order 517 Sequence< Property > aProps(10); 518 Property* pProperties = aProps.getArray(); 519 sal_Int32 nPos = 0; 520 DECL_PROP0(CURSORNAME, ::rtl::OUString); 521 DECL_BOOL_PROP0(ESCAPEPROCESSING); 522 DECL_PROP0(FETCHDIRECTION,sal_Int32); 523 DECL_PROP0(FETCHSIZE, sal_Int32); 524 DECL_PROP0(MAXFIELDSIZE,sal_Int32); 525 DECL_PROP0(MAXROWS, sal_Int32); 526 DECL_PROP0(QUERYTIMEOUT,sal_Int32); 527 DECL_PROP0(RESULTSETCONCURRENCY,sal_Int32); 528 DECL_PROP0(RESULTSETTYPE,sal_Int32); 529 DECL_BOOL_PROP0(USEBOOKMARKS); 530 531 return new ::cppu::OPropertyArrayHelper(aProps); 532 } 533 // ------------------------------------------------------------------------- 534 ::cppu::IPropertyArrayHelper & MacabCommonStatement::getInfoHelper() 535 { 536 return *const_cast<MacabCommonStatement*>(this)->getArrayHelper(); 537 } 538 // ------------------------------------------------------------------------- 539 sal_Bool MacabCommonStatement::convertFastPropertyValue( 540 Any &, 541 Any &, 542 sal_Int32, 543 const Any&) throw (::com::sun::star::lang::IllegalArgumentException) 544 { 545 sal_Bool bConverted = sal_False; 546 // here we have to try to convert 547 return bConverted; 548 } 549 // ------------------------------------------------------------------------- 550 void MacabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&) throw (Exception) 551 { 552 // set the value to whatever is nescessary 553 switch (nHandle) 554 { 555 case PROPERTY_ID_QUERYTIMEOUT: 556 case PROPERTY_ID_MAXFIELDSIZE: 557 case PROPERTY_ID_MAXROWS: 558 case PROPERTY_ID_CURSORNAME: 559 case PROPERTY_ID_RESULTSETCONCURRENCY: 560 case PROPERTY_ID_RESULTSETTYPE: 561 case PROPERTY_ID_FETCHDIRECTION: 562 case PROPERTY_ID_FETCHSIZE: 563 case PROPERTY_ID_ESCAPEPROCESSING: 564 case PROPERTY_ID_USEBOOKMARKS: 565 default: 566 ; 567 } 568 } 569 // ------------------------------------------------------------------------- 570 void MacabCommonStatement::getFastPropertyValue(Any&,sal_Int32 nHandle) const 571 { 572 switch (nHandle) 573 { 574 case PROPERTY_ID_QUERYTIMEOUT: 575 case PROPERTY_ID_MAXFIELDSIZE: 576 case PROPERTY_ID_MAXROWS: 577 case PROPERTY_ID_CURSORNAME: 578 case PROPERTY_ID_RESULTSETCONCURRENCY: 579 case PROPERTY_ID_RESULTSETTYPE: 580 case PROPERTY_ID_FETCHDIRECTION: 581 case PROPERTY_ID_FETCHSIZE: 582 case PROPERTY_ID_ESCAPEPROCESSING: 583 case PROPERTY_ID_USEBOOKMARKS: 584 default: 585 ; 586 } 587 } 588 // ----------------------------------------------------------------------------- 589 void SAL_CALL MacabCommonStatement::acquire() throw() 590 { 591 MacabCommonStatement_BASE::acquire(); 592 } 593 // ----------------------------------------------------------------------------- 594 void SAL_CALL MacabCommonStatement::release() throw() 595 { 596 MacabCommonStatement_BASE::release(); 597 } 598 // ----------------------------------------------------------------------------- 599 Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL MacabCommonStatement::getPropertySetInfo( ) throw(RuntimeException) 600 { 601 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); 602 } 603 // ----------------------------------------------------------------------------- 604 MacabStatement::MacabStatement(MacabConnection* _pConnection) 605 : MacabStatement_BASE(_pConnection) 606 { 607 } 608