update dev300-m58
[ooovba.git] / connectivity / source / commontools / TTableHelper.cxx
blob9a150d4694890428e1f66121e84fab5e2eafebfe
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: TTableHelper.cxx,v $
10 * $Revision: 1.10 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
33 #include "connectivity/TTableHelper.hxx"
34 #include <com/sun/star/sdbc/XRow.hpp>
35 #include <com/sun/star/sdbc/XResultSet.hpp>
36 #include <com/sun/star/sdbcx/KeyType.hpp>
37 #include <com/sun/star/sdbc/KeyRule.hpp>
38 #include <cppuhelper/typeprovider.hxx>
39 #include <com/sun/star/lang/DisposedException.hpp>
40 #include <com/sun/star/sdbc/ColumnValue.hpp>
41 #include <comphelper/implementationreference.hxx>
42 #include <comphelper/sequence.hxx>
43 #include <comphelper/extract.hxx>
44 #include <comphelper/types.hxx>
45 #include "connectivity/dbtools.hxx"
46 #include "connectivity/sdbcx/VCollection.hxx"
47 #include <unotools/sharedunocomponent.hxx>
48 #include "TConnection.hxx"
50 using namespace ::comphelper;
51 using namespace connectivity;
52 using namespace ::com::sun::star::uno;
53 using namespace ::com::sun::star::beans;
54 using namespace ::com::sun::star::sdbcx;
55 using namespace ::com::sun::star::sdbc;
56 using namespace ::com::sun::star::container;
57 using namespace ::com::sun::star::lang;
58 namespace
60 /// helper class for column property change events which holds the OComponentDefinition weak
61 typedef ::cppu::WeakImplHelper1 < XContainerListener > OTableContainerListener_BASE;
62 class OTableContainerListener : public OTableContainerListener_BASE
64 OTableHelper* m_pComponent;
65 ::std::map< ::rtl::OUString,bool> m_aRefNames;
67 OTableContainerListener(const OTableContainerListener&);
68 void operator =(const OTableContainerListener&);
69 protected:
70 virtual ~OTableContainerListener(){}
71 public:
72 OTableContainerListener(OTableHelper* _pComponent) : m_pComponent(_pComponent){}
73 virtual void SAL_CALL elementInserted( const ::com::sun::star::container::ContainerEvent& /*Event*/ ) throw (RuntimeException)
76 virtual void SAL_CALL elementRemoved( const ::com::sun::star::container::ContainerEvent& Event ) throw (RuntimeException)
78 ::rtl::OUString sName;
79 Event.Accessor >>= sName;
80 if ( m_aRefNames.find(sName) != m_aRefNames.end() )
81 m_pComponent->refreshKeys();
83 virtual void SAL_CALL elementReplaced( const ::com::sun::star::container::ContainerEvent& Event ) throw (RuntimeException)
85 ::rtl::OUString sOldComposedName,sNewComposedName;
86 Event.ReplacedElement >>= sOldComposedName;
87 Event.Accessor >>= sNewComposedName;
88 if ( sOldComposedName != sNewComposedName && m_aRefNames.find(sOldComposedName) != m_aRefNames.end() )
89 m_pComponent->refreshKeys();
91 // XEventListener
92 virtual void SAL_CALL disposing( const EventObject& /*_rSource*/ ) throw (RuntimeException)
95 void clear() { m_pComponent = NULL; }
96 inline void add(const ::rtl::OUString& _sRefName) { m_aRefNames.insert(::std::map< ::rtl::OUString,bool>::value_type(_sRefName,true)); }
99 namespace connectivity
101 struct OTableHelperImpl
103 TKeyMap m_aKeys;
104 Reference< ::com::sun::star::sdbc::XDatabaseMetaData > m_xMetaData;
105 Reference< ::com::sun::star::sdbc::XConnection > m_xConnection;
106 ::comphelper::ImplementationReference< OTableContainerListener,XContainerListener>
107 m_xTablePropertyListener;
108 ::std::vector< ColumnDesc > m_aColumnDesc;
112 OTableHelper::OTableHelper( sdbcx::OCollection* _pTables,
113 const Reference< XConnection >& _xConnection,
114 sal_Bool _bCase)
115 :OTable_TYPEDEF(_pTables,_bCase)
116 ,m_pImpl(new OTableHelperImpl)
120 m_pImpl->m_xConnection = _xConnection;
121 m_pImpl->m_xMetaData = m_pImpl->m_xConnection->getMetaData();
123 catch(const Exception&)
127 // -------------------------------------------------------------------------
128 OTableHelper::OTableHelper( sdbcx::OCollection* _pTables,
129 const Reference< XConnection >& _xConnection,
130 sal_Bool _bCase,
131 const ::rtl::OUString& _Name,
132 const ::rtl::OUString& _Type,
133 const ::rtl::OUString& _Description ,
134 const ::rtl::OUString& _SchemaName,
135 const ::rtl::OUString& _CatalogName
136 ) : OTable_TYPEDEF(_pTables,
137 _bCase,
138 _Name,
139 _Type,
140 _Description,
141 _SchemaName,
142 _CatalogName)
143 ,m_pImpl(new OTableHelperImpl)
147 m_pImpl->m_xConnection = _xConnection;
148 m_pImpl->m_xMetaData = m_pImpl->m_xConnection->getMetaData();
150 catch(const Exception&)
154 // -----------------------------------------------------------------------------
155 OTableHelper::~OTableHelper()
158 // -----------------------------------------------------------------------------
159 void SAL_CALL OTableHelper::disposing()
161 ::osl::MutexGuard aGuard(m_aMutex);
162 if ( m_pImpl->m_xTablePropertyListener.is() )
164 m_pTables->removeContainerListener(m_pImpl->m_xTablePropertyListener.getRef());
165 m_pImpl->m_xTablePropertyListener->clear();
166 m_pImpl->m_xTablePropertyListener.dispose();
168 OTable_TYPEDEF::disposing();
170 m_pImpl->m_xConnection = NULL;
171 m_pImpl->m_xMetaData = NULL;
175 // -------------------------------------------------------------------------
176 namespace
178 /** collects ColumnDesc's from a resultset produced by XDatabaseMetaData::getColumns
180 void lcl_collectColumnDescs_throw( const Reference< XResultSet >& _rxResult, ::std::vector< ColumnDesc >& _out_rColumns )
182 Reference< XRow > xRow( _rxResult, UNO_QUERY_THROW );
183 ::rtl::OUString sName;
184 OrdinalPosition nOrdinalPosition( 0 );
185 while ( _rxResult->next() )
187 sName = xRow->getString( 4 ); // COLUMN_NAME
188 sal_Int32 nField5 = xRow->getInt(5);
189 ::rtl::OUString aField6 = xRow->getString(6);
190 sal_Int32 nField7 = xRow->getInt(7)
191 , nField9 = xRow->getInt(9)
192 , nField11= xRow->getInt(11);
193 ::rtl::OUString sField13 = xRow->getString(13);
194 nOrdinalPosition = xRow->getInt( 17 ); // ORDINAL_POSITION
195 _out_rColumns.push_back( ColumnDesc( sName,nField5,aField6,nField7,nField9,nField11,sField13, nOrdinalPosition ) );
199 /** checks a given array of ColumnDesc's whether it has reasonable ordinal positions. If not,
200 they will be normalized to be the array index.
202 void lcl_sanitizeColumnDescs( ::std::vector< ColumnDesc >& _rColumns )
204 if ( _rColumns.empty() )
205 return;
207 // collect all used ordinals
208 ::std::set< OrdinalPosition > aUsedOrdinals;
209 for ( ::std::vector< ColumnDesc >::iterator collect = _rColumns.begin();
210 collect != _rColumns.end();
211 ++collect
213 aUsedOrdinals.insert( collect->nOrdinalPosition );
215 // we need to have as much different ordinals as we have different columns
216 bool bDuplicates = aUsedOrdinals.size() != _rColumns.size();
217 // and it needs to be a continuous range
218 size_t nOrdinalsRange = *aUsedOrdinals.rbegin() - *aUsedOrdinals.begin() + 1;
219 bool bGaps = nOrdinalsRange != _rColumns.size();
221 // if that's not the case, normalize it
222 if ( bGaps || bDuplicates )
224 OSL_ENSURE( false, "lcl_sanitizeColumnDescs: database did provide invalid ORDINAL_POSITION values!" );
226 OrdinalPosition nNormalizedPosition = 1;
227 for ( ::std::vector< ColumnDesc >::iterator normalize = _rColumns.begin();
228 normalize != _rColumns.end();
229 ++normalize
231 normalize->nOrdinalPosition = nNormalizedPosition++;
232 return;
235 // what's left is that the range might not be from 1 to <column count>, but for instance
236 // 0 to <column count>-1.
237 size_t nOffset = *aUsedOrdinals.begin() - 1;
238 for ( ::std::vector< ColumnDesc >::iterator offset = _rColumns.begin();
239 offset != _rColumns.end();
240 ++offset
242 offset->nOrdinalPosition -= nOffset;
246 // -------------------------------------------------------------------------
247 void OTableHelper::refreshColumns()
249 TStringVector aVector;
250 if(!isNew())
252 Any aCatalog;
253 if ( m_CatalogName.getLength() )
254 aCatalog <<= m_CatalogName;
256 ::utl::SharedUNOComponent< XResultSet > xResult( getMetaData()->getColumns(
257 aCatalog,
258 m_SchemaName,
259 m_Name,
260 ::rtl::OUString::createFromAscii("%")
261 ) );
263 // collect the column names, together with their ordinal position
264 m_pImpl->m_aColumnDesc.clear();
265 lcl_collectColumnDescs_throw( xResult, m_pImpl->m_aColumnDesc );
267 // ensure that the ordinal positions as obtained from the meta data do make sense
268 lcl_sanitizeColumnDescs( m_pImpl->m_aColumnDesc );
270 // sort by ordinal position
271 ::std::map< OrdinalPosition, ::rtl::OUString > aSortedColumns;
272 for ( ::std::vector< ColumnDesc >::const_iterator copy = m_pImpl->m_aColumnDesc.begin();
273 copy != m_pImpl->m_aColumnDesc.end();
274 ++copy
276 aSortedColumns[ copy->nOrdinalPosition ] = copy->sName;
278 // copy them to aVector, now that we have the proper ordering
279 ::std::transform(
280 aSortedColumns.begin(),
281 aSortedColumns.end(),
282 ::std::insert_iterator< TStringVector >( aVector, aVector.begin() ),
283 ::std::select2nd< ::std::map< OrdinalPosition, ::rtl::OUString >::value_type >()
287 if(m_pColumns)
288 m_pColumns->reFill(aVector);
289 else
290 m_pColumns = createColumns(aVector);
292 // -----------------------------------------------------------------------------
293 const ColumnDesc* OTableHelper::getColumnDescription(const ::rtl::OUString& _sName) const
295 const ColumnDesc* pRet = NULL;
296 ::std::vector< ColumnDesc >::const_iterator aEnd = m_pImpl->m_aColumnDesc.end();
297 for (::std::vector< ColumnDesc >::const_iterator aIter = m_pImpl->m_aColumnDesc.begin();aIter != aEnd;++aIter)
299 if ( aIter->sName == _sName )
301 pRet = &*aIter;
302 break;
304 } // for (::std::vector< ColumnDesc >::const_iterator aIter = m_pImpl->m_aColumnDesc.begin();aIter != aEnd;++aIter)
305 return pRet;
307 // -------------------------------------------------------------------------
308 void OTableHelper::refreshPrimaryKeys(TStringVector& _rNames)
310 Any aCatalog;
311 if ( m_CatalogName.getLength() )
312 aCatalog <<= m_CatalogName;
313 Reference< XResultSet > xResult = getMetaData()->getPrimaryKeys(aCatalog,m_SchemaName,m_Name);
315 if ( xResult.is() )
317 sdbcx::TKeyProperties pKeyProps(new sdbcx::KeyProperties(::rtl::OUString(),KeyType::PRIMARY,0,0));
318 ::rtl::OUString aPkName;
319 bool bAlreadyFetched = false;
320 const Reference< XRow > xRow(xResult,UNO_QUERY);
321 while ( xResult->next() )
323 pKeyProps->m_aKeyColumnNames.push_back(xRow->getString(4));
324 if ( !bAlreadyFetched )
326 aPkName = xRow->getString(6);
327 bAlreadyFetched = true;
331 m_pImpl->m_aKeys.insert(TKeyMap::value_type(aPkName,pKeyProps));
332 _rNames.push_back(aPkName);
333 } // if ( xResult.is() && xResult->next() )
334 ::comphelper::disposeComponent(xResult);
336 // -------------------------------------------------------------------------
337 void OTableHelper::refreshForgeinKeys(TStringVector& _rNames)
339 Any aCatalog;
340 if ( m_CatalogName.getLength() )
341 aCatalog <<= m_CatalogName;
342 Reference< XResultSet > xResult = getMetaData()->getImportedKeys(aCatalog,m_SchemaName,m_Name);
343 Reference< XRow > xRow(xResult,UNO_QUERY);
345 if ( xRow.is() )
347 sdbcx::TKeyProperties pKeyProps;
348 ::rtl::OUString aName,sCatalog,aSchema,sOldFKName;
349 while( xResult->next() )
351 // this must be outsid the "if" because we have to call in a right order
352 sCatalog = xRow->getString(1);
353 if ( xRow->wasNull() )
354 sCatalog = ::rtl::OUString();
355 aSchema = xRow->getString(2);
356 aName = xRow->getString(3);
358 const ::rtl::OUString sForeignKeyColumn = xRow->getString(8);
359 const sal_Int32 nUpdateRule = xRow->getInt(10);
360 const sal_Int32 nDeleteRule = xRow->getInt(11);
361 const ::rtl::OUString sFkName = xRow->getString(12);
363 if ( pKeyProps.get() )
368 if ( sFkName.getLength() && !xRow->wasNull() )
370 if ( sOldFKName != sFkName )
372 if ( pKeyProps.get() )
373 m_pImpl->m_aKeys.insert(TKeyMap::value_type(sOldFKName,pKeyProps));
375 const ::rtl::OUString sReferencedName = ::dbtools::composeTableName(getMetaData(),sCatalog,aSchema,aName,sal_False,::dbtools::eInDataManipulation);
376 pKeyProps.reset(new sdbcx::KeyProperties(sReferencedName,KeyType::FOREIGN,nUpdateRule,nDeleteRule));
377 pKeyProps->m_aKeyColumnNames.push_back(sForeignKeyColumn);
378 _rNames.push_back(sFkName);
379 if ( m_pTables->hasByName(sReferencedName) )
381 if ( !m_pImpl->m_xTablePropertyListener.is() )
382 m_pImpl->m_xTablePropertyListener = ::comphelper::ImplementationReference< OTableContainerListener,XContainerListener>( new OTableContainerListener(this) );
383 m_pTables->addContainerListener(m_pImpl->m_xTablePropertyListener.getRef());
384 m_pImpl->m_xTablePropertyListener->add(sReferencedName);
385 } // if ( m_pTables->hasByName(sReferencedName) )
386 sOldFKName = sFkName;
387 } // if ( sOldFKName != sFkName )
388 else if ( pKeyProps.get() )
390 pKeyProps->m_aKeyColumnNames.push_back(sForeignKeyColumn);
393 } // while( xResult->next() )
394 if ( pKeyProps.get() )
395 m_pImpl->m_aKeys.insert(TKeyMap::value_type(sOldFKName,pKeyProps));
396 ::comphelper::disposeComponent(xResult);
399 // -------------------------------------------------------------------------
400 void OTableHelper::refreshKeys()
402 m_pImpl->m_aKeys.clear();
404 TStringVector aNames;
406 if(!isNew())
408 refreshPrimaryKeys(aNames);
409 refreshForgeinKeys(aNames);
410 m_pKeys = createKeys(aNames);
411 } // if(!isNew())
412 else if (!m_pKeys )
413 m_pKeys = createKeys(aNames);
414 /*if(m_pKeys)
415 m_pKeys->reFill(aVector);
416 else*/
419 // -------------------------------------------------------------------------
420 void OTableHelper::refreshIndexes()
422 TStringVector aVector;
423 if(!isNew())
425 // fill indexes
426 Any aCatalog;
427 if ( m_CatalogName.getLength() )
428 aCatalog <<= m_CatalogName;
429 Reference< XResultSet > xResult = getMetaData()->getIndexInfo(aCatalog,m_SchemaName,m_Name,sal_False,sal_False);
431 if(xResult.is())
433 Reference< XRow > xRow(xResult,UNO_QUERY);
434 ::rtl::OUString aName;
435 ::rtl::OUString sCatalogSep = getMetaData()->getCatalogSeparator();
436 ::rtl::OUString sPreviousRoundName;
437 while( xResult->next() )
439 aName = xRow->getString(5);
440 if(aName.getLength())
441 aName += sCatalogSep;
442 aName += xRow->getString(6);
443 if ( aName.getLength() )
445 // don't insert the name if the last one we inserted was the same
446 if (sPreviousRoundName != aName)
447 aVector.push_back(aName);
449 sPreviousRoundName = aName;
451 ::comphelper::disposeComponent(xResult);
455 if(m_pIndexes)
456 m_pIndexes->reFill(aVector);
457 else
458 m_pIndexes = createIndexes(aVector);
460 // -----------------------------------------------------------------------------
461 ::rtl::OUString OTableHelper::getRenameStart() const
463 ::rtl::OUString sSql(RTL_CONSTASCII_USTRINGPARAM("RENAME "));
464 if ( m_Type == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("VIEW")) )
465 sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" VIEW "));
466 else
467 sSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" TABLE "));
469 return sSql;
471 // -------------------------------------------------------------------------
472 // XRename
473 void SAL_CALL OTableHelper::rename( const ::rtl::OUString& newName ) throw(SQLException, ElementExistException, RuntimeException)
475 ::osl::MutexGuard aGuard(m_aMutex);
476 checkDisposed(
477 #ifdef GCC
478 ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed
479 #else
480 rBHelper.bDisposed
481 #endif
484 if(!isNew())
486 ::rtl::OUString sSql = getRenameStart();
487 ::rtl::OUString sQuote = getMetaData()->getIdentifierQuoteString( );
489 ::rtl::OUString sCatalog,sSchema,sTable;
490 ::dbtools::qualifiedNameComponents(getMetaData(),newName,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
492 ::rtl::OUString sComposedName;
493 sComposedName = ::dbtools::composeTableName(getMetaData(),m_CatalogName,m_SchemaName,m_Name,sal_True,::dbtools::eInDataManipulation);
494 sSql += sComposedName
495 + ::rtl::OUString::createFromAscii(" TO ");
496 sComposedName = ::dbtools::composeTableName(getMetaData(),sCatalog,sSchema,sTable,sal_True,::dbtools::eInDataManipulation);
497 sSql += sComposedName;
499 Reference< XStatement > xStmt = m_pImpl->m_xConnection->createStatement( );
500 if ( xStmt.is() )
502 xStmt->execute(sSql);
503 ::comphelper::disposeComponent(xStmt);
506 OTable_TYPEDEF::rename(newName);
508 else
509 ::dbtools::qualifiedNameComponents(getMetaData(),newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::eInTableDefinitions);
511 // -----------------------------------------------------------------------------
512 Reference< XDatabaseMetaData> OTableHelper::getMetaData() const
514 return m_pImpl->m_xMetaData;
516 // -------------------------------------------------------------------------
517 void SAL_CALL OTableHelper::alterColumnByIndex( sal_Int32 index, const Reference< XPropertySet >& descriptor ) throw(SQLException, ::com::sun::star::lang::IndexOutOfBoundsException, RuntimeException)
519 ::osl::MutexGuard aGuard(m_aMutex);
520 checkDisposed(
521 #ifdef GCC
522 ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed
523 #else
524 rBHelper.bDisposed
525 #endif
528 Reference< XPropertySet > xOld;
529 if(::cppu::extractInterface(xOld,m_pColumns->getByIndex(index)) && xOld.is())
530 alterColumnByName(getString(xOld->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),descriptor);
533 // -------------------------------------------------------------------------
534 ::rtl::OUString SAL_CALL OTableHelper::getName() throw(RuntimeException)
536 ::rtl::OUString sComposedName;
537 sComposedName = ::dbtools::composeTableName(getMetaData(),m_CatalogName,m_SchemaName,m_Name,sal_False,::dbtools::eInDataManipulation);
538 return sComposedName;
540 // -----------------------------------------------------------------------------
541 void SAL_CALL OTableHelper::acquire() throw()
543 OTable_TYPEDEF::acquire();
545 // -----------------------------------------------------------------------------
546 void SAL_CALL OTableHelper::release() throw()
548 OTable_TYPEDEF::release();
550 // -----------------------------------------------------------------------------
551 sdbcx::TKeyProperties OTableHelper::getKeyProperties(const ::rtl::OUString& _sName) const
553 sdbcx::TKeyProperties pKeyProps;
554 TKeyMap::const_iterator aFind = m_pImpl->m_aKeys.find(_sName);
555 if ( aFind != m_pImpl->m_aKeys.end() )
557 pKeyProps = aFind->second;
559 else // only a fall back
561 OSL_ENSURE(0,"No key with the given name found");
562 pKeyProps.reset(new sdbcx::KeyProperties());
565 return pKeyProps;
567 // -----------------------------------------------------------------------------
568 void OTableHelper::addKey(const ::rtl::OUString& _sName,const sdbcx::TKeyProperties& _aKeyProperties)
570 m_pImpl->m_aKeys.insert(TKeyMap::value_type(_sName,_aKeyProperties));
572 // -----------------------------------------------------------------------------
573 ::rtl::OUString OTableHelper::getTypeCreatePattern() const
575 return ::rtl::OUString();
577 // -----------------------------------------------------------------------------
578 Reference< XConnection> OTableHelper::getConnection() const
580 return m_pImpl->m_xConnection;