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