/************************************************************************* * * $RCSfile: viewcontainer.cxx,v $ * * $Revision: 1.13 $ * * last change: $Author: oj $ $Date: 2002-08-21 10:33:54 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses * * - GNU Lesser General Public License Version 2.1 * - Sun Industry Standards Source License Version 1.1 * * Sun Microsystems Inc., October, 2000 * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2000 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * * Sun Industry Standards Source License Version 1.1 * ================================================= * The contents of this file are subject to the Sun Industry Standards * Source License Version 1.1 (the "License"); You may not use this file * except in compliance with the License. You may obtain a copy of the * License at http://www.openoffice.org/license.html. * * Software provided under this License is provided on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. * See the License for the specific provisions governing your rights and * obligations concerning the Software. * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2000 by Sun Microsystems, Inc. * * All Rights Reserved. * * Contributor(s): _______________________________________ * * ************************************************************************/ #ifndef _DBA_CORE_VIEWCONTAINER_HXX_ #include "viewcontainer.hxx" #endif #ifndef DBACCESS_SHARED_DBASTRINGS_HRC #include "dbastrings.hrc" #endif #ifndef _TOOLS_DEBUG_HXX #include #endif #ifndef _WLDCRD_HXX #include #endif #ifndef _COMPHELPER_ENUMHELPER_HXX_ #include #endif #ifndef _DBA_CORE_RESOURCE_HXX_ #include "core_resource.hxx" #endif #ifndef _DBA_CORE_RESOURCE_HRC_ #include "core_resource.hrc" #endif #ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBC_XCONNECTION_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBC_XDATABASEMETADATA_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBCX_XCOLUMNSSUPPLIER_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBCX_XTABLESSUPPLIER_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBC_KEYRULE_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBCX_KEYTYPE_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBC_COLUMNVALUE_HPP_ #include #endif #ifndef _COM_SUN_STAR_SDBC_XROW_HPP_ #include #endif #ifndef _COMPHELPER_TYPES_HXX_ #include #endif #ifndef _CONNECTIVITY_DBTOOLS_HXX_ #include #endif #ifndef _COMPHELPER_EXTRACT_HXX_ #include #endif #ifndef _DBHELPER_DBEXCEPTION_HXX_ #include #endif #ifndef _CONNECTIVITY_SDBCX_VIEW_HXX_ #include #endif using namespace dbaccess; using namespace dbtools; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::sdbc; using namespace ::com::sun::star::sdb; using namespace ::com::sun::star::sdbcx; using namespace ::com::sun::star::util; using namespace ::com::sun::star::container; using namespace ::osl; using namespace ::comphelper; using namespace ::cppu; using namespace ::connectivity::sdbcx; //========================================================================== //= OViewContainer //========================================================================== DBG_NAME(OViewContainer) //------------------------------------------------------------------------------ OViewContainer::OViewContainer(::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, const Reference< XConnection >& _xCon, sal_Bool _bCase, IRefreshListener* _pRefreshListener, IWarningsContainer* _pWarningsContainer) :OCollection(_rParent,_bCase,_rMutex,::std::vector< ::rtl::OUString>()) ,m_bConstructed(sal_False) ,m_xConnection(_xCon) ,m_pWarningsContainer(_pWarningsContainer) ,m_pRefreshListener(_pRefreshListener) { DBG_CTOR(OViewContainer, NULL); try { m_xMetaData = _xCon->getMetaData(); } catch(SQLException&) { } } //------------------------------------------------------------------------------ OViewContainer::~OViewContainer() { // dispose(); DBG_DTOR(OViewContainer, NULL); } // ----------------------------------------------------------------------------- void SAL_CALL OViewContainer::acquire() throw() { m_rParent.acquire(); } // ----------------------------------------------------------------------------- void SAL_CALL OViewContainer::release() throw() { m_rParent.release(); } //------------------------------------------------------------------------------ /** compare two strings */ extern int #if defined( WNT ) __cdecl #endif #if defined( ICC ) && defined( OS2 ) _Optlink #endif NameCompare( const void* pFirst, const void* pSecond); // ------------------------------------------------------------------------- void OViewContainer::construct(const Reference< XNameAccess >& _rxMasterContainer, const Sequence< ::rtl::OUString >& _rTableFilter, const Sequence< ::rtl::OUString >& _rTableTypeFilter) { m_xMasterViews = _rxMasterContainer; if(m_xMasterViews.is()) { sal_Int32 nTableFilterLen = _rTableFilter.getLength(); sal_Bool bNoTableFilters = ((nTableFilterLen == 1) && _rTableFilter[0].equalsAsciiL("%", 1)); connectivity::TStringVector aViewNames; if(!bNoTableFilters) { Sequence< ::rtl::OUString > aTableFilter = _rTableFilter; Sequence< ::rtl::OUString > aTableTypeFilter = _rTableTypeFilter; // build sorted versions of the filter sequences, so the visibility decision is faster qsort(aTableFilter.getArray(), nTableFilterLen, sizeof(::rtl::OUString), NameCompare); // as we want to modify nTableFilterLen, remember this // for wildcard search : remove all table filters which are a wildcard expression and build a WilCard // for them ::std::vector< WildCard > aWCSearch; // contains the wildcards for the table filter ::rtl::OUString* pTableFilters = aTableFilter.getArray(); sal_Int32 nShiftPos = 0; String sCurrentWCExpression; for (sal_Int32 i=0; iindexOf('%') != -1) { sCurrentWCExpression = sal_Unicode('*'); sCurrentWCExpression += (const sal_Unicode*)pTableFilters[i].replace('%', '*'); sCurrentWCExpression += sal_Unicode('*'); aWCSearch.push_back(WildCard(sCurrentWCExpression)); } else { if (nShiftPos != i) pTableFilters[nShiftPos] = pTableFilters[i]; ++nShiftPos; } } // now aTableFilter contains nShiftPos non-wc-strings and aWCSearch all wc-strings aTableFilter.realloc(nShiftPos); nTableFilterLen = nShiftPos; aViewNames.reserve(nShiftPos); Sequence< ::rtl::OUString> aNames = m_xMasterViews->getElementNames(); const ::rtl::OUString* pBegin = aNames.getConstArray(); const ::rtl::OUString* pEnd = pBegin + aNames.getLength(); for(;pBegin != pEnd;++pBegin) { if(isNameValid(*pBegin,aTableFilter,aTableTypeFilter,aWCSearch)) aViewNames.push_back(*pBegin); } } else { // no filter so insert all names Sequence< ::rtl::OUString> aNames = m_xMasterViews->getElementNames(); const ::rtl::OUString* pBegin = aNames.getConstArray(); const ::rtl::OUString* pEnd = pBegin + aNames.getLength(); aViewNames = connectivity::TStringVector(pBegin,pEnd); } reFill(aViewNames); m_bConstructed = sal_True; } } // ----------------------------------------------------------------------------- void OViewContainer::construct(const Sequence< ::rtl::OUString >& _rTableFilter, const Sequence< ::rtl::OUString >& _rTableTypeFilter) { // build sorted versions of the filter sequences, so the visibility decision is faster Sequence< ::rtl::OUString > aTableFilter(_rTableFilter); sal_Int32 nTableFilterLen = aTableFilter.getLength(); if (nTableFilterLen) qsort(aTableFilter.getArray(), nTableFilterLen, sizeof(::rtl::OUString), NameCompare); sal_Bool bNoTableFilters = ((nTableFilterLen == 1) && _rTableFilter[0].equalsAsciiL("%", 1)); // as we want to modify nTableFilterLen, remember this // for wildcard search : remove all table filters which are a wildcard expression and build a WilCard // for them ::rtl::OUString* pTableFilters = aTableFilter.getArray(); ::std::vector< WildCard > aWCSearch; sal_Int32 nShiftPos = 0; String sCurrentWCExpression; for (sal_Int32 i=0; iindexOf('%') != -1) { sCurrentWCExpression = sal_Unicode('*'); sCurrentWCExpression += (const sal_Unicode*)pTableFilters[i].replace('%', '*'); sCurrentWCExpression += sal_Unicode('*'); aWCSearch.push_back(WildCard(sCurrentWCExpression)); } else { if (nShiftPos != i) pTableFilters[nShiftPos] = pTableFilters[i]; ++nShiftPos; } } // now aTableFilter contains nShiftPos non-wc-strings and aWCSearch all wc-strings aTableFilter.realloc(nShiftPos); nTableFilterLen = nShiftPos; try { if (m_xMetaData.is()) { static const ::rtl::OUString s_sTableTypeView(RTL_CONSTASCII_USTRINGPARAM("VIEW")); if(_rTableTypeFilter.getLength() != 0) { const ::rtl::OUString* pBegin = _rTableTypeFilter.getConstArray(); const ::rtl::OUString* pEnd = pBegin + _rTableTypeFilter.getLength(); for(;pBegin != pEnd;++pBegin) { if ( *pBegin == s_sTableTypeView ) break; } if ( pBegin != pEnd ) { // view are filtered out m_bConstructed = sal_True; return; } } // we want all catalogues, all schemas, all tables Sequence< ::rtl::OUString > sTableTypes(1); sTableTypes[0] = s_sTableTypeView; static const ::rtl::OUString sAll = ::rtl::OUString::createFromAscii("%"); Reference< XResultSet > xTables = m_xMetaData->getTables(Any(), sAll, sAll, sTableTypes); Reference< XRow > xCurrentRow(xTables, UNO_QUERY); if (xCurrentRow.is()) { // after creation the set is positioned before the first record, per definitionem ::rtl::OUString sCatalog, sSchema, sName, sType; ::rtl::OUString sComposedName; // we first collect the names and construct the OTable objects later, as the ctor of the table may need // another result set from the connection, and some drivers support only one statement per connection String sWCCompare; sal_Bool bFilterMatch; while (xTables->next()) { sCatalog = xCurrentRow->getString(1); sSchema = xCurrentRow->getString(2); sName = xCurrentRow->getString(3); // we're not interested in the "wasNull", as the getStrings would return an empty string in // that case, which is sufficient here composeTableName(m_xMetaData, sCatalog, sSchema, sName, sComposedName, sal_False); bFilterMatch = bNoTableFilters || ((nTableFilterLen != 0) && (NULL != bsearch(&sComposedName, aTableFilter.getConstArray(), nTableFilterLen, sizeof(::rtl::OUString), NameCompare))); // the table is allowed to "pass" if we had no filters at all or any of the non-wildcard filters matches if (!bFilterMatch && aWCSearch.size()) { // or if one of the wildcrad expression matches sWCCompare += (const sal_Unicode*)sComposedName; for ( ::std::vector< WildCard >::const_iterator aLoop = aWCSearch.begin(); aLoop != aWCSearch.end() && !bFilterMatch; ++aLoop ) bFilterMatch = aLoop->Matches(sWCCompare); } if (bFilterMatch) { // the table name is allowed (not filtered out) insertElement(sComposedName,NULL); } } // dispose the tables result set, in case the connection can handle only one concurrent statement // (the table object creation will need it's own statements) disposeComponent(xTables); } else DBG_ERROR("OTableContainer::construct : did not get a XRow from the tables result set !"); } else DBG_ERROR("OTableContainer::construct : no connection meta data !"); } catch (SQLException&) { DBG_ERROR("OTableContainer::construct : catched an SQL-Exception !"); disposing(); return; } m_bConstructed = sal_True; } //------------------------------------------------------------------------------ void OViewContainer::disposing() { MutexGuard aGuard(m_rMutex); OCollection::disposing(); m_xMasterViews = NULL; m_xMetaData = NULL; m_xConnection = NULL; m_pWarningsContainer = NULL; m_bConstructed = sal_False; } // XServiceInfo //------------------------------------------------------------------------------ IMPLEMENT_SERVICE_INFO2(OViewContainer, "com.sun.star.sdb.dbaccess.OViewContainer", SERVICE_SDBCX_CONTAINER, SERVICE_SDBCX_TABLES) // ------------------------------------------------------------------------- sal_Bool OViewContainer::isNameValid( const ::rtl::OUString& _rName, const Sequence< ::rtl::OUString >& _rTableFilter, const Sequence< ::rtl::OUString >& _rTableTypeFilter, const ::std::vector< WildCard >& _rWCSearch) const { sal_Int32 nTableFilterLen = _rTableFilter.getLength(); sal_Bool bFilterMatch = (NULL != bsearch(&_rName, _rTableFilter.getConstArray(), nTableFilterLen, sizeof(::rtl::OUString), NameCompare)); // the table is allowed to "pass" if we had no filters at all or any of the non-wildcard filters matches if (!bFilterMatch && _rWCSearch.size()) { // or if one of the wildcrad expression matches String sWCCompare = (const sal_Unicode*)_rName; for ( ::std::vector< WildCard >::const_iterator aLoop = _rWCSearch.begin(); aLoop != _rWCSearch.end() && !bFilterMatch; ++aLoop ) bFilterMatch = aLoop->Matches(sWCCompare); } return bFilterMatch; } // ------------------------------------------------------------------------- void OViewContainer::impl_refresh() throw(RuntimeException) { if ( m_pRefreshListener ) { m_bConstructed = sal_False; Reference xRefresh(m_xMasterViews,UNO_QUERY); if ( xRefresh.is() ) xRefresh->refresh(); m_pRefreshListener->refresh(this); } } // ----------------------------------------------------------------------------- Reference< XNamed > OViewContainer::createObject(const ::rtl::OUString& _rName) { Reference< XNamed > xProp; if(m_xMasterViews.is() && m_xMasterViews->hasByName(_rName)) m_xMasterViews->getByName(_rName) >>= xProp; if ( !xProp.is() ) { ::rtl::OUString sCatalog,sSchema,sTable; ::dbtools::qualifiedNameComponents(m_xMetaData, _rName, sCatalog, sSchema, sTable); return new ::connectivity::sdbcx::OView(isCaseSensitive(), sTable, m_xMetaData, 0, ::rtl::OUString(), sSchema, sCatalog ); } return xProp; } // ----------------------------------------------------------------------------- Reference< XPropertySet > OViewContainer::createEmptyObject() { Reference< XPropertySet > xRet; // frist we have to look if the master tables does support this // and if then create a table object as well with the master tables Reference xMasterColumnsSup; Reference xDataFactory(m_xMasterViews,UNO_QUERY); if(xDataFactory.is()) xRet = xDataFactory->createDataDescriptor(); else xRet = new ::connectivity::sdbcx::OView(isCaseSensitive(),m_xMetaData); return xRet; } // ----------------------------------------------------------------------------- // XAppend void OViewContainer::appendObject( const Reference< XPropertySet >& descriptor ) { // append the new table with a create stmt ::rtl::OUString aName = getString(descriptor->getPropertyValue(PROPERTY_NAME)); Reference xAppend(m_xMasterViews,UNO_QUERY); Reference< XPropertySet > xProp = descriptor; if(xAppend.is()) { xAppend->appendByDescriptor(descriptor); if(m_xMasterViews->hasByName(aName)) m_xMasterViews->getByName(aName) >>= xProp; } else { ::rtl::OUString aSql = ::rtl::OUString::createFromAscii("CREATE VIEW "); ::rtl::OUString sCatalog,sSchema,sTable,sComposedName; if(m_xMetaData->supportsCatalogsInTableDefinitions()) descriptor->getPropertyValue(PROPERTY_CATALOGNAME) >>= sCatalog; if(m_xMetaData->supportsSchemasInTableDefinitions()) descriptor->getPropertyValue(PROPERTY_SCHEMANAME) >>= sSchema; descriptor->getPropertyValue(PROPERTY_NAME) >>= sTable; ::dbtools::composeTableName(m_xMetaData,sCatalog,sSchema,sTable,sComposedName,sal_True); if(!sComposedName.getLength()) ::dbtools::throwFunctionSequenceException(*this); aSql += sComposedName + ::rtl::OUString::createFromAscii(" AS "); ::rtl::OUString sCommand; descriptor->getPropertyValue(PROPERTY_COMMAND) >>= sCommand; aSql += sCommand; OSL_ENSURE(m_xConnection.is(),"Connection is null!"); Reference< XStatement > xStmt = m_xConnection->createStatement( ); if ( xStmt.is() ) xStmt->execute(aSql); ::comphelper::disposeComponent(xStmt); } } // ------------------------------------------------------------------------- // XDrop void OViewContainer::dropObject(sal_Int32 _nPos,const ::rtl::OUString _sElementName) { Reference< XDrop > xDrop(m_xMasterViews,UNO_QUERY); if(xDrop.is()) xDrop->dropByName(_sElementName); else { ObjectIter aIter = m_aElements[_nPos]; if(!aIter->second.is()) // we want to drop a object which isn't loaded yet so we must load it aIter->second = createObject(_sElementName); ::rtl::OUString sCatalog,sSchema,sTable,sComposedName; Reference xTable(aIter->second.get(),UNO_QUERY); if(xTable.is()) { if(m_xMetaData->supportsCatalogsInTableDefinitions()) xTable->getPropertyValue(PROPERTY_CATALOGNAME) >>= sCatalog; if(m_xMetaData->supportsSchemasInTableDefinitions()) xTable->getPropertyValue(PROPERTY_SCHEMANAME) >>= sSchema; xTable->getPropertyValue(PROPERTY_NAME) >>= sTable; ::dbtools::composeTableName(m_xMetaData,sCatalog,sSchema,sTable,sComposedName,sal_True); } if(!sComposedName.getLength()) ::dbtools::throwFunctionSequenceException(*this); ::rtl::OUString aSql = ::rtl::OUString::createFromAscii("DROP VIEW "); aSql += sComposedName; Reference< XStatement > xStmt = m_xConnection->createStatement( ); if(xStmt.is()) xStmt->execute(aSql); ::comphelper::disposeComponent(xStmt); } } // ----------------------------------------------------------------------------- void SAL_CALL OViewContainer::elementInserted( const ContainerEvent& Event ) throw (RuntimeException) { ::osl::MutexGuard aGuard(m_rMutex); ::rtl::OUString sName; if ( (Event.Accessor >>= sName) && !hasByName(sName) ) insertElement(sName,createObject(sName)); } // ----------------------------------------------------------------------------- void SAL_CALL OViewContainer::elementRemoved( const ContainerEvent& Event ) throw (RuntimeException) { } // ----------------------------------------------------------------------------- void SAL_CALL OViewContainer::disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException) { } // ----------------------------------------------------------------------------- void SAL_CALL OViewContainer::elementReplaced( const ContainerEvent& Event ) throw (RuntimeException) { } // ----------------------------------------------------------------------------- Reference< XNamed > OViewContainer::cloneObject(const Reference< XPropertySet >& _xDescriptor) { Reference< XNamed > xName(_xDescriptor,UNO_QUERY); OSL_ENSURE(xName.is(),"Must be a XName interface here !"); return xName.is() ? createObject(xName->getName()) : Reference< XNamed >(); } // -----------------------------------------------------------------------------