1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "connectivity/TTableHelper.hxx"
21 #include <com/sun/star/sdbc/XRow.hpp>
22 #include <com/sun/star/sdbc/XResultSet.hpp>
23 #include <com/sun/star/sdbcx/KeyType.hpp>
24 #include <com/sun/star/sdbc/KeyRule.hpp>
25 #include <cppuhelper/typeprovider.hxx>
26 #include <com/sun/star/lang/DisposedException.hpp>
27 #include <com/sun/star/sdbc/ColumnValue.hpp>
28 #include <comphelper/implementationreference.hxx>
29 #include <comphelper/sequence.hxx>
30 #include <comphelper/extract.hxx>
31 #include <comphelper/types.hxx>
32 #include "connectivity/dbtools.hxx"
33 #include "connectivity/sdbcx/VCollection.hxx"
34 #include <unotools/sharedunocomponent.hxx>
35 #include "TConnection.hxx"
37 #include <o3tl/compat_functional.hxx>
41 using namespace ::comphelper
;
42 using namespace connectivity
;
43 using namespace ::com::sun::star::uno
;
44 using namespace ::com::sun::star::beans
;
45 using namespace ::com::sun::star::sdbcx
;
46 using namespace ::com::sun::star::sdbc
;
47 using namespace ::com::sun::star::container
;
48 using namespace ::com::sun::star::lang
;
51 /// helper class for column property change events which holds the OComponentDefinition weak
52 typedef ::cppu::WeakImplHelper1
< XContainerListener
> OTableContainerListener_BASE
;
53 class OTableContainerListener
: public OTableContainerListener_BASE
55 OTableHelper
* m_pComponent
;
56 ::std::map
< OUString
,bool> m_aRefNames
;
58 OTableContainerListener(const OTableContainerListener
&);
59 void operator =(const OTableContainerListener
&);
61 virtual ~OTableContainerListener(){}
63 OTableContainerListener(OTableHelper
* _pComponent
) : m_pComponent(_pComponent
){}
64 virtual void SAL_CALL
elementInserted( const ::com::sun::star::container::ContainerEvent
& /*Event*/ ) throw (RuntimeException
)
67 virtual void SAL_CALL
elementRemoved( const ::com::sun::star::container::ContainerEvent
& Event
) throw (RuntimeException
)
70 Event
.Accessor
>>= sName
;
71 if ( m_aRefNames
.find(sName
) != m_aRefNames
.end() )
72 m_pComponent
->refreshKeys();
74 virtual void SAL_CALL
elementReplaced( const ::com::sun::star::container::ContainerEvent
& Event
) throw (RuntimeException
)
76 OUString sOldComposedName
,sNewComposedName
;
77 Event
.ReplacedElement
>>= sOldComposedName
;
78 Event
.Accessor
>>= sNewComposedName
;
79 if ( sOldComposedName
!= sNewComposedName
&& m_aRefNames
.find(sOldComposedName
) != m_aRefNames
.end() )
80 m_pComponent
->refreshKeys();
83 virtual void SAL_CALL
disposing( const EventObject
& /*_rSource*/ ) throw (RuntimeException
)
86 void clear() { m_pComponent
= NULL
; }
87 inline void add(const OUString
& _sRefName
) { m_aRefNames
.insert(::std::map
< OUString
,bool>::value_type(_sRefName
,true)); }
90 namespace connectivity
92 OUString
lcl_getServiceNameForSetting(const Reference
< ::com::sun::star::sdbc::XConnection
>& _xConnection
,const OUString
& i_sSetting
)
94 OUString sSupportService
;
96 if ( ::dbtools::getDataSourceSetting(_xConnection
,i_sSetting
,aValue
) )
98 aValue
>>= sSupportService
;
100 return sSupportService
;
102 struct OTableHelperImpl
105 // helper services which can be provided by extensions
106 Reference
< ::com::sun::star::sdb::tools::XTableRename
> m_xRename
;
107 Reference
< ::com::sun::star::sdb::tools::XTableAlteration
> m_xAlter
;
108 Reference
< ::com::sun::star::sdb::tools::XKeyAlteration
> m_xKeyAlter
;
109 Reference
< ::com::sun::star::sdb::tools::XIndexAlteration
> m_xIndexAlter
;
111 Reference
< ::com::sun::star::sdbc::XDatabaseMetaData
> m_xMetaData
;
112 Reference
< ::com::sun::star::sdbc::XConnection
> m_xConnection
;
113 ::comphelper::ImplementationReference
< OTableContainerListener
,XContainerListener
>
114 m_xTablePropertyListener
;
115 ::std::vector
< ColumnDesc
> m_aColumnDesc
;
116 OTableHelperImpl(const Reference
< ::com::sun::star::sdbc::XConnection
>& _xConnection
)
117 : m_xConnection(_xConnection
)
121 m_xMetaData
= m_xConnection
->getMetaData();
122 Reference
<XMultiServiceFactory
> xFac(_xConnection
,UNO_QUERY
);
125 static const OUString
s_sTableRename("TableRenameServiceName");
126 m_xRename
.set(xFac
->createInstance(lcl_getServiceNameForSetting(m_xConnection
,s_sTableRename
)),UNO_QUERY
);
127 static const OUString
s_sTableAlteration("TableAlterationServiceName");
128 m_xAlter
.set(xFac
->createInstance(lcl_getServiceNameForSetting(m_xConnection
,s_sTableAlteration
)),UNO_QUERY
);
129 static const OUString
s_sKeyAlteration("KeyAlterationServiceName");
130 m_xKeyAlter
.set(xFac
->createInstance(lcl_getServiceNameForSetting(m_xConnection
,s_sKeyAlteration
)),UNO_QUERY
);
131 static const OUString
s_sIndexAlteration("IndexAlterationServiceName");
132 m_xIndexAlter
.set(xFac
->createInstance(lcl_getServiceNameForSetting(m_xConnection
,s_sIndexAlteration
)),UNO_QUERY
);
135 catch(const Exception
&)
142 OTableHelper::OTableHelper( sdbcx::OCollection
* _pTables
,
143 const Reference
< XConnection
>& _xConnection
,
145 :OTable_TYPEDEF(_pTables
,_bCase
)
146 ,m_pImpl(new OTableHelperImpl(_xConnection
))
149 // -------------------------------------------------------------------------
150 OTableHelper::OTableHelper( sdbcx::OCollection
* _pTables
,
151 const Reference
< XConnection
>& _xConnection
,
153 const OUString
& _Name
,
154 const OUString
& _Type
,
155 const OUString
& _Description
,
156 const OUString
& _SchemaName
,
157 const OUString
& _CatalogName
158 ) : OTable_TYPEDEF(_pTables
,
165 ,m_pImpl(new OTableHelperImpl(_xConnection
))
168 // -----------------------------------------------------------------------------
169 OTableHelper::~OTableHelper()
172 // -----------------------------------------------------------------------------
173 void SAL_CALL
OTableHelper::disposing()
175 ::osl::MutexGuard
aGuard(m_aMutex
);
176 if ( m_pImpl
->m_xTablePropertyListener
.is() )
178 m_pTables
->removeContainerListener(m_pImpl
->m_xTablePropertyListener
.getRef());
179 m_pImpl
->m_xTablePropertyListener
->clear();
180 m_pImpl
->m_xTablePropertyListener
.dispose();
182 OTable_TYPEDEF::disposing();
184 m_pImpl
->m_xConnection
= NULL
;
185 m_pImpl
->m_xMetaData
= NULL
;
189 // -------------------------------------------------------------------------
192 /** collects ColumnDesc's from a resultset produced by XDatabaseMetaData::getColumns
194 void lcl_collectColumnDescs_throw( const Reference
< XResultSet
>& _rxResult
, ::std::vector
< ColumnDesc
>& _out_rColumns
)
196 Reference
< XRow
> xRow( _rxResult
, UNO_QUERY_THROW
);
198 OrdinalPosition
nOrdinalPosition( 0 );
199 while ( _rxResult
->next() )
201 sName
= xRow
->getString( 4 ); // COLUMN_NAME
202 sal_Int32 nField5
= xRow
->getInt(5);
203 OUString aField6
= xRow
->getString(6);
204 sal_Int32 nField7
= xRow
->getInt(7)
205 , nField9
= xRow
->getInt(9)
206 , nField11
= xRow
->getInt(11);
207 OUString sField12
= xRow
->getString(12)
208 ,sField13
= xRow
->getString(13);
209 nOrdinalPosition
= xRow
->getInt( 17 ); // ORDINAL_POSITION
210 _out_rColumns
.push_back( ColumnDesc( sName
,nField5
,aField6
,nField7
,nField9
,nField11
,sField12
,sField13
, nOrdinalPosition
) );
214 /** checks a given array of ColumnDesc's whether it has reasonable ordinal positions. If not,
215 they will be normalized to be the array index.
217 void lcl_sanitizeColumnDescs( ::std::vector
< ColumnDesc
>& _rColumns
)
219 if ( _rColumns
.empty() )
222 // collect all used ordinals
223 ::std::set
< OrdinalPosition
> aUsedOrdinals
;
224 for ( ::std::vector
< ColumnDesc
>::iterator collect
= _rColumns
.begin();
225 collect
!= _rColumns
.end();
228 aUsedOrdinals
.insert( collect
->nOrdinalPosition
);
230 // we need to have as much different ordinals as we have different columns
231 bool bDuplicates
= aUsedOrdinals
.size() != _rColumns
.size();
232 // and it needs to be a continuous range
233 size_t nOrdinalsRange
= *aUsedOrdinals
.rbegin() - *aUsedOrdinals
.begin() + 1;
234 bool bGaps
= nOrdinalsRange
!= _rColumns
.size();
236 // if that's not the case, normalize it
237 if ( bGaps
|| bDuplicates
)
239 OSL_FAIL( "lcl_sanitizeColumnDescs: database did provide invalid ORDINAL_POSITION values!" );
241 OrdinalPosition nNormalizedPosition
= 1;
242 for ( ::std::vector
< ColumnDesc
>::iterator normalize
= _rColumns
.begin();
243 normalize
!= _rColumns
.end();
246 normalize
->nOrdinalPosition
= nNormalizedPosition
++;
250 // what's left is that the range might not be from 1 to <column count>, but for instance
251 // 0 to <column count>-1.
252 size_t nOffset
= *aUsedOrdinals
.begin() - 1;
253 for ( ::std::vector
< ColumnDesc
>::iterator offset
= _rColumns
.begin();
254 offset
!= _rColumns
.end();
257 offset
->nOrdinalPosition
-= nOffset
;
261 // -------------------------------------------------------------------------
262 void OTableHelper::refreshColumns()
264 TStringVector aVector
;
268 if ( !m_CatalogName
.isEmpty() )
269 aCatalog
<<= m_CatalogName
;
271 ::utl::SharedUNOComponent
< XResultSet
> xResult( getMetaData()->getColumns(
278 // collect the column names, together with their ordinal position
279 m_pImpl
->m_aColumnDesc
.clear();
280 lcl_collectColumnDescs_throw( xResult
, m_pImpl
->m_aColumnDesc
);
282 // ensure that the ordinal positions as obtained from the meta data do make sense
283 lcl_sanitizeColumnDescs( m_pImpl
->m_aColumnDesc
);
285 // sort by ordinal position
286 ::std::map
< OrdinalPosition
, OUString
> aSortedColumns
;
287 for ( ::std::vector
< ColumnDesc
>::const_iterator copy
= m_pImpl
->m_aColumnDesc
.begin();
288 copy
!= m_pImpl
->m_aColumnDesc
.end();
291 aSortedColumns
[ copy
->nOrdinalPosition
] = copy
->sName
;
293 // copy them to aVector, now that we have the proper ordering
295 aSortedColumns
.begin(),
296 aSortedColumns
.end(),
297 ::std::insert_iterator
< TStringVector
>( aVector
, aVector
.begin() ),
298 ::o3tl::select2nd
< ::std::map
< OrdinalPosition
, OUString
>::value_type
>()
303 m_pColumns
->reFill(aVector
);
305 m_pColumns
= createColumns(aVector
);
307 // -----------------------------------------------------------------------------
308 const ColumnDesc
* OTableHelper::getColumnDescription(const OUString
& _sName
) const
310 const ColumnDesc
* pRet
= NULL
;
311 ::std::vector
< ColumnDesc
>::const_iterator aEnd
= m_pImpl
->m_aColumnDesc
.end();
312 for (::std::vector
< ColumnDesc
>::const_iterator aIter
= m_pImpl
->m_aColumnDesc
.begin();aIter
!= aEnd
;++aIter
)
314 if ( aIter
->sName
== _sName
)
319 } // for (::std::vector< ColumnDesc >::const_iterator aIter = m_pImpl->m_aColumnDesc.begin();aIter != aEnd;++aIter)
322 // -------------------------------------------------------------------------
323 void OTableHelper::refreshPrimaryKeys(TStringVector
& _rNames
)
326 if ( !m_CatalogName
.isEmpty() )
327 aCatalog
<<= m_CatalogName
;
328 Reference
< XResultSet
> xResult
= getMetaData()->getPrimaryKeys(aCatalog
,m_SchemaName
,m_Name
);
332 sdbcx::TKeyProperties
pKeyProps(new sdbcx::KeyProperties(OUString(),KeyType::PRIMARY
,0,0));
334 bool bAlreadyFetched
= false;
335 const Reference
< XRow
> xRow(xResult
,UNO_QUERY
);
336 while ( xResult
->next() )
338 pKeyProps
->m_aKeyColumnNames
.push_back(xRow
->getString(4));
339 if ( !bAlreadyFetched
)
341 aPkName
= xRow
->getString(6);
342 SAL_WARN_IF(xRow
->wasNull(),"connectivity.commontools", "NULL Primary Key name");
343 SAL_WARN_IF(aPkName
.isEmpty(),"connectivity.commontools", "empty Primary Key name");
344 bAlreadyFetched
= true;
350 SAL_WARN_IF(aPkName
.isEmpty(),"connectivity.commontools", "empty Primary Key name");
351 SAL_WARN_IF(pKeyProps
->m_aKeyColumnNames
.size() == 0,"connectivity.commontools", "Primary Key has no columns");
352 m_pImpl
->m_aKeys
.insert(TKeyMap::value_type(aPkName
,pKeyProps
));
353 _rNames
.push_back(aPkName
);
355 } // if ( xResult.is() && xResult->next() )
356 ::comphelper::disposeComponent(xResult
);
358 // -------------------------------------------------------------------------
359 void OTableHelper::refreshForeignKeys(TStringVector
& _rNames
)
362 if ( !m_CatalogName
.isEmpty() )
363 aCatalog
<<= m_CatalogName
;
364 Reference
< XResultSet
> xResult
= getMetaData()->getImportedKeys(aCatalog
,m_SchemaName
,m_Name
);
365 Reference
< XRow
> xRow(xResult
,UNO_QUERY
);
369 sdbcx::TKeyProperties pKeyProps
;
370 OUString aName
,sCatalog
,aSchema
,sOldFKName
;
371 while( xResult
->next() )
373 // this must be outsid the "if" because we have to call in a right order
374 sCatalog
= xRow
->getString(1);
375 if ( xRow
->wasNull() )
376 sCatalog
= OUString();
377 aSchema
= xRow
->getString(2);
378 aName
= xRow
->getString(3);
380 const OUString sForeignKeyColumn
= xRow
->getString(8);
381 const sal_Int32 nUpdateRule
= xRow
->getInt(10);
382 const sal_Int32 nDeleteRule
= xRow
->getInt(11);
383 const OUString sFkName
= xRow
->getString(12);
385 if ( pKeyProps
.get() )
390 if ( !sFkName
.isEmpty() && !xRow
->wasNull() )
392 if ( sOldFKName
!= sFkName
)
394 if ( pKeyProps
.get() )
395 m_pImpl
->m_aKeys
.insert(TKeyMap::value_type(sOldFKName
,pKeyProps
));
397 const OUString sReferencedName
= ::dbtools::composeTableName(getMetaData(),sCatalog
,aSchema
,aName
,sal_False
,::dbtools::eInDataManipulation
);
398 pKeyProps
.reset(new sdbcx::KeyProperties(sReferencedName
,KeyType::FOREIGN
,nUpdateRule
,nDeleteRule
));
399 pKeyProps
->m_aKeyColumnNames
.push_back(sForeignKeyColumn
);
400 _rNames
.push_back(sFkName
);
401 if ( m_pTables
->hasByName(sReferencedName
) )
403 if ( !m_pImpl
->m_xTablePropertyListener
.is() )
404 m_pImpl
->m_xTablePropertyListener
= ::comphelper::ImplementationReference
< OTableContainerListener
,XContainerListener
>( new OTableContainerListener(this) );
405 m_pTables
->addContainerListener(m_pImpl
->m_xTablePropertyListener
.getRef());
406 m_pImpl
->m_xTablePropertyListener
->add(sReferencedName
);
407 } // if ( m_pTables->hasByName(sReferencedName) )
408 sOldFKName
= sFkName
;
409 } // if ( sOldFKName != sFkName )
410 else if ( pKeyProps
.get() )
412 pKeyProps
->m_aKeyColumnNames
.push_back(sForeignKeyColumn
);
415 } // while( xResult->next() )
416 if ( pKeyProps
.get() )
417 m_pImpl
->m_aKeys
.insert(TKeyMap::value_type(sOldFKName
,pKeyProps
));
418 ::comphelper::disposeComponent(xResult
);
421 // -------------------------------------------------------------------------
422 void OTableHelper::refreshKeys()
424 m_pImpl
->m_aKeys
.clear();
426 TStringVector aNames
;
430 refreshPrimaryKeys(aNames
);
431 refreshForeignKeys(aNames
);
432 m_pKeys
= createKeys(aNames
);
435 m_pKeys
= createKeys(aNames
);
437 m_pKeys->reFill(aVector);
441 // -------------------------------------------------------------------------
442 void OTableHelper::refreshIndexes()
444 TStringVector aVector
;
449 if ( !m_CatalogName
.isEmpty() )
450 aCatalog
<<= m_CatalogName
;
451 Reference
< XResultSet
> xResult
= getMetaData()->getIndexInfo(aCatalog
,m_SchemaName
,m_Name
,sal_False
,sal_False
);
455 Reference
< XRow
> xRow(xResult
,UNO_QUERY
);
457 OUString sCatalogSep
= getMetaData()->getCatalogSeparator();
458 OUString sPreviousRoundName
;
459 while( xResult
->next() )
461 aName
= xRow
->getString(5);
463 aName
+= sCatalogSep
;
464 aName
+= xRow
->getString(6);
465 if ( !aName
.isEmpty() )
467 // don't insert the name if the last one we inserted was the same
468 if (sPreviousRoundName
!= aName
)
469 aVector
.push_back(aName
);
471 sPreviousRoundName
= aName
;
473 ::comphelper::disposeComponent(xResult
);
478 m_pIndexes
->reFill(aVector
);
480 m_pIndexes
= createIndexes(aVector
);
482 // -----------------------------------------------------------------------------
483 OUString
OTableHelper::getRenameStart() const
485 OUString
sSql("RENAME ");
486 if ( m_Type
== OUString("VIEW") )
487 sSql
+= OUString(" VIEW ");
489 sSql
+= OUString(" TABLE ");
493 // -------------------------------------------------------------------------
495 void SAL_CALL
OTableHelper::rename( const OUString
& newName
) throw(SQLException
, ElementExistException
, RuntimeException
)
497 ::osl::MutexGuard
aGuard(m_aMutex
);
500 ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper
.bDisposed
508 if ( m_pImpl
->m_xRename
.is() )
510 m_pImpl
->m_xRename
->rename(this,newName
);
514 OUString sSql
= getRenameStart();
516 OUString sCatalog
,sSchema
,sTable
;
517 ::dbtools::qualifiedNameComponents(getMetaData(),newName
,sCatalog
,sSchema
,sTable
,::dbtools::eInDataManipulation
);
519 OUString sComposedName
;
520 sComposedName
= ::dbtools::composeTableName(getMetaData(),m_CatalogName
,m_SchemaName
,m_Name
,sal_True
,::dbtools::eInDataManipulation
);
521 sSql
+= sComposedName
523 sComposedName
= ::dbtools::composeTableName(getMetaData(),sCatalog
,sSchema
,sTable
,sal_True
,::dbtools::eInDataManipulation
);
524 sSql
+= sComposedName
;
526 Reference
< XStatement
> xStmt
= m_pImpl
->m_xConnection
->createStatement( );
529 xStmt
->execute(sSql
);
530 ::comphelper::disposeComponent(xStmt
);
534 OTable_TYPEDEF::rename(newName
);
537 ::dbtools::qualifiedNameComponents(getMetaData(),newName
,m_CatalogName
,m_SchemaName
,m_Name
,::dbtools::eInTableDefinitions
);
539 // -----------------------------------------------------------------------------
540 Reference
< XDatabaseMetaData
> OTableHelper::getMetaData() const
542 return m_pImpl
->m_xMetaData
;
544 // -------------------------------------------------------------------------
545 void SAL_CALL
OTableHelper::alterColumnByIndex( sal_Int32 index
, const Reference
< XPropertySet
>& descriptor
) throw(SQLException
, ::com::sun::star::lang::IndexOutOfBoundsException
, RuntimeException
)
547 ::osl::MutexGuard
aGuard(m_aMutex
);
550 ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper
.bDisposed
556 Reference
< XPropertySet
> xOld
;
557 if(::cppu::extractInterface(xOld
,m_pColumns
->getByIndex(index
)) && xOld
.is())
558 alterColumnByName(getString(xOld
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
))),descriptor
);
561 // -------------------------------------------------------------------------
562 OUString SAL_CALL
OTableHelper::getName() throw(RuntimeException
)
564 OUString sComposedName
;
565 sComposedName
= ::dbtools::composeTableName(getMetaData(),m_CatalogName
,m_SchemaName
,m_Name
,sal_False
,::dbtools::eInDataManipulation
);
566 return sComposedName
;
568 // -----------------------------------------------------------------------------
569 void SAL_CALL
OTableHelper::acquire() throw()
571 OTable_TYPEDEF::acquire();
573 // -----------------------------------------------------------------------------
574 void SAL_CALL
OTableHelper::release() throw()
576 OTable_TYPEDEF::release();
578 // -----------------------------------------------------------------------------
579 sdbcx::TKeyProperties
OTableHelper::getKeyProperties(const OUString
& _sName
) const
581 sdbcx::TKeyProperties pKeyProps
;
582 TKeyMap::const_iterator aFind
= m_pImpl
->m_aKeys
.find(_sName
);
583 if ( aFind
!= m_pImpl
->m_aKeys
.end() )
585 pKeyProps
= aFind
->second
;
587 else // only a fall back
589 OSL_FAIL("No key with the given name found");
590 pKeyProps
.reset(new sdbcx::KeyProperties());
595 // -----------------------------------------------------------------------------
596 void OTableHelper::addKey(const OUString
& _sName
,const sdbcx::TKeyProperties
& _aKeyProperties
)
598 m_pImpl
->m_aKeys
.insert(TKeyMap::value_type(_sName
,_aKeyProperties
));
600 // -----------------------------------------------------------------------------
601 OUString
OTableHelper::getTypeCreatePattern() const
605 // -----------------------------------------------------------------------------
606 Reference
< XConnection
> OTableHelper::getConnection() const
608 return m_pImpl
->m_xConnection
;
610 // -----------------------------------------------------------------------------
611 Reference
< ::com::sun::star::sdb::tools::XTableRename
> OTableHelper::getRenameService() const
613 return m_pImpl
->m_xRename
;
615 // -----------------------------------------------------------------------------
616 Reference
< ::com::sun::star::sdb::tools::XTableAlteration
> OTableHelper::getAlterService() const
618 return m_pImpl
->m_xAlter
;
620 // -----------------------------------------------------------------------------
621 Reference
< ::com::sun::star::sdb::tools::XKeyAlteration
> OTableHelper::getKeyService() const
623 return m_pImpl
->m_xKeyAlter
;
625 // -----------------------------------------------------------------------------
626 Reference
< ::com::sun::star::sdb::tools::XIndexAlteration
> OTableHelper::getIndexService() const
628 return m_pImpl
->m_xIndexAlter
;
630 // -----------------------------------------------------------------------------
632 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */