xref: /trunk/main/dbaccess/source/core/api/tablecontainer.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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_dbaccess.hxx"
30 
31 #include "tablecontainer.hxx"
32 #include "dbastrings.hrc"
33 #include "table.hxx"
34 #include <comphelper/property.hxx>
35 #include <comphelper/processfactory.hxx>
36 #include <tools/debug.hxx>
37 #include <comphelper/enumhelper.hxx>
38 #include "core_resource.hxx"
39 #include "core_resource.hrc"
40 #include <com/sun/star/sdb/CommandType.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/beans/PropertyState.hpp>
43 #include <com/sun/star/beans/XPropertyState.hpp>
44 #include <com/sun/star/sdbc/XConnection.hpp>
45 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
46 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
47 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
48 #include <com/sun/star/sdbc/KeyRule.hpp>
49 #include <com/sun/star/sdbcx/KeyType.hpp>
50 #include <com/sun/star/sdbc/ColumnValue.hpp>
51 #include <com/sun/star/sdbc/XRow.hpp>
52 #include <comphelper/types.hxx>
53 #include <connectivity/dbtools.hxx>
54 #include <comphelper/extract.hxx>
55 #include <connectivity/dbexception.hxx>
56 #include "TableDeco.hxx"
57 #include "sdbcoretools.hxx"
58 #include "ContainerMediator.hxx"
59 #include "definitioncolumn.hxx"
60 #include "objectnameapproval.hxx"
61 #include <tools/string.hxx>
62 #include <rtl/logfile.hxx>
63 #ifndef TOOLS_DIAGNOSE_EX_H
64 #include <tools/diagnose_ex.h>
65 #endif
66 #ifndef TOOLS_DIAGNOSE_EX_H
67 #include <tools/diagnose_ex.h>
68 #endif
69 
70 using namespace dbaccess;
71 using namespace dbtools;
72 using namespace ::com::sun::star::uno;
73 using namespace ::com::sun::star::lang;
74 using namespace ::com::sun::star::beans;
75 using namespace ::com::sun::star::sdbc;
76 using namespace ::com::sun::star::sdb;
77 using namespace ::com::sun::star::sdbcx;
78 using namespace ::com::sun::star::container;
79 using namespace ::com::sun::star::util;
80 using namespace ::osl;
81 using namespace ::comphelper;
82 using namespace ::cppu;
83 using namespace ::connectivity::sdbcx;
84 
85 namespace
86 {
87     sal_Bool lcl_isPropertySetDefaulted(const Sequence< ::rtl::OUString>& _aNames,const Reference<XPropertySet>& _xProp)
88     {
89         Reference<XPropertyState> xState(_xProp,UNO_QUERY);
90         if ( xState.is() )
91         {
92             const ::rtl::OUString* pIter = _aNames.getConstArray();
93             const ::rtl::OUString* pEnd   = pIter + _aNames.getLength();
94             for(;pIter != pEnd;++pIter)
95             {
96                 try
97                 {
98                     PropertyState aState = xState->getPropertyState(*pIter);
99                     if ( aState != PropertyState_DEFAULT_VALUE )
100                         break;
101                 }
102                 catch(Exception)
103                 {
104                     OSL_ENSURE( 0, "lcl_isPropertySetDefaulted: Exception caught!" );
105                 }
106             }
107             return ( pIter == pEnd );
108         }
109         return sal_False;
110     }
111 }
112 //==========================================================================
113 //= OTableContainer
114 //==========================================================================
115 DBG_NAME(OTableContainer)
116 //------------------------------------------------------------------------------
117 OTableContainer::OTableContainer(::cppu::OWeakObject& _rParent,
118                                  ::osl::Mutex& _rMutex,
119                                  const Reference< XConnection >& _xCon,
120                                  sal_Bool _bCase,
121                                  const Reference< XNameContainer >& _xTableDefinitions,
122                                  IRefreshListener*  _pRefreshListener,
123                                  ::dbtools::IWarningsContainer* _pWarningsContainer
124                                  ,oslInterlockedCount& _nInAppend)
125     :OFilteredContainer(_rParent,_rMutex,_xCon,_bCase,_pRefreshListener,_pWarningsContainer,_nInAppend)
126     ,m_xTableDefinitions(_xTableDefinitions)
127     ,m_pTableMediator( NULL )
128     ,m_bInDrop(sal_False)
129 {
130     DBG_CTOR(OTableContainer, NULL);
131 }
132 
133 //------------------------------------------------------------------------------
134 OTableContainer::~OTableContainer()
135 {
136     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::OTableContainer" );
137     //  dispose();
138     DBG_DTOR(OTableContainer, NULL);
139 }
140 
141 // -----------------------------------------------------------------------------
142 void OTableContainer::removeMasterContainerListener()
143 {
144     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::removeMasterContainerListener" );
145     try
146     {
147         Reference<XContainer> xCont( m_xMasterContainer, UNO_QUERY_THROW );
148         xCont->removeContainerListener( this );
149     }
150     catch( const Exception& )
151     {
152         DBG_UNHANDLED_EXCEPTION();
153     }
154 }
155 
156 // -----------------------------------------------------------------------------
157 ::rtl::OUString OTableContainer::getTableTypeRestriction() const
158 {
159     // no restriction at all (other than the ones provided externally)
160     return ::rtl::OUString();
161 }
162 
163 // -----------------------------------------------------------------------------
164 // XServiceInfo
165 //------------------------------------------------------------------------------
166 IMPLEMENT_SERVICE_INFO2(OTableContainer, "com.sun.star.sdb.dbaccess.OTableContainer", SERVICE_SDBCX_CONTAINER, SERVICE_SDBCX_TABLES)
167 
168 // -----------------------------------------------------------------------------
169 namespace
170 {
171 void lcl_createDefintionObject(const ::rtl::OUString& _rName
172                            ,const Reference< XNameContainer >& _xTableDefinitions
173                            ,Reference<XPropertySet>& _xTableDefinition
174                            ,Reference<XNameAccess>& _xColumnDefinitions
175                            ,sal_Bool _bModified)
176 {
177     if ( _xTableDefinitions.is() )
178     {
179         if ( _xTableDefinitions->hasByName(_rName) )
180             _xTableDefinition.set(_xTableDefinitions->getByName(_rName),UNO_QUERY);
181         else
182         {
183             Sequence< Any > aArguments(1);
184             PropertyValue aValue;
185             // set as folder
186             aValue.Name = PROPERTY_NAME;
187             aValue.Value <<= _rName;
188             aArguments[0] <<= aValue;
189             _xTableDefinition.set(::comphelper::getProcessServiceFactory()->createInstanceWithArguments(SERVICE_SDB_TABLEDEFINITION,aArguments),UNO_QUERY);
190             _xTableDefinitions->insertByName(_rName,makeAny(_xTableDefinition));
191             ::dbaccess::notifyDataSourceModified(_xTableDefinitions,_bModified);
192         }
193         Reference<XColumnsSupplier> xColumnsSupplier(_xTableDefinition,UNO_QUERY);
194         if ( xColumnsSupplier.is() )
195             _xColumnDefinitions = xColumnsSupplier->getColumns();
196     }
197 }
198 // -------------------------------------------------------------------------
199 }
200 // -------------------------------------------------------------------------
201 connectivity::sdbcx::ObjectType OTableContainer::createObject(const ::rtl::OUString& _rName)
202 {
203     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::createObject" );
204     Reference<XColumnsSupplier > xSup;
205     if(m_xMasterContainer.is() && m_xMasterContainer->hasByName(_rName))
206         xSup.set(m_xMasterContainer->getByName(_rName),UNO_QUERY);
207 
208     connectivity::sdbcx::ObjectType xRet;
209     if ( m_xMetaData.is() )
210     {
211         Reference<XPropertySet> xTableDefinition;
212         Reference<XNameAccess> xColumnDefinitions;
213         lcl_createDefintionObject(_rName,m_xTableDefinitions,xTableDefinition,xColumnDefinitions,sal_False);
214 
215         if ( xSup.is() )
216         {
217             ODBTableDecorator* pTable = new ODBTableDecorator( m_xConnection, xSup, ::dbtools::getNumberFormats( m_xConnection ) ,xColumnDefinitions);
218             xRet = pTable;
219             pTable->construct();
220         }
221         else
222         {
223             ::rtl::OUString sCatalog,sSchema,sTable;
224             ::dbtools::qualifiedNameComponents(m_xMetaData,
225                                                 _rName,
226                                                 sCatalog,
227                                                 sSchema,
228                                                 sTable,
229                                                 ::dbtools::eInDataManipulation);
230             Any aCatalog;
231             if(sCatalog.getLength())
232                 aCatalog <<= sCatalog;
233             ::rtl::OUString sType,sDescription;
234             Sequence< ::rtl::OUString> aTypeFilter;
235             getAllTableTypeFilter( aTypeFilter );
236 
237             Reference< XResultSet > xRes =  m_xMetaData.is() ? m_xMetaData->getTables(aCatalog,sSchema,sTable,aTypeFilter) : Reference< XResultSet >();
238             if(xRes.is() && xRes->next())
239             {
240                 Reference< XRow > xRow(xRes,UNO_QUERY);
241                 if(xRow.is())
242                 {
243                     sType           = xRow->getString(4);
244                     sDescription    = xRow->getString(5);
245                 }
246             }
247             ::comphelper::disposeComponent(xRes);
248             ODBTable* pTable = new ODBTable(this
249                                 ,m_xConnection
250                                 ,sCatalog
251                                 ,sSchema
252                                 ,sTable
253                                 ,sType
254                                 ,sDescription
255                                 ,xColumnDefinitions);
256             xRet = pTable;
257             pTable->construct();
258         }
259         Reference<XPropertySet> xDest(xRet,UNO_QUERY);
260         if ( xTableDefinition.is() )
261             ::comphelper::copyProperties(xTableDefinition,xDest);
262 
263         if ( !m_pTableMediator.is() )
264             m_pTableMediator = new OContainerMediator(
265                     this, m_xTableDefinitions.get(), m_xConnection, OContainerMediator::eTables );
266         if ( m_pTableMediator.is() )
267             m_pTableMediator->notifyElementCreated(_rName,xDest);
268     }
269 
270     return xRet;
271 }
272 // -----------------------------------------------------------------------------
273 Reference< XPropertySet > OTableContainer::createDescriptor()
274 {
275     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::createDescriptor" );
276     Reference< XPropertySet > xRet;
277 
278     // frist we have to look if the master tables does support this
279     // and if then create a table object as well with the master tables
280     Reference<XColumnsSupplier > xMasterColumnsSup;
281     Reference<XDataDescriptorFactory> xDataFactory(m_xMasterContainer,UNO_QUERY);
282     if ( xDataFactory.is() && m_xMetaData.is() )
283     {
284         xMasterColumnsSup = Reference< XColumnsSupplier >( xDataFactory->createDataDescriptor(), UNO_QUERY );
285         ODBTableDecorator* pTable = new ODBTableDecorator( m_xConnection, xMasterColumnsSup, ::dbtools::getNumberFormats( m_xConnection ) ,NULL);
286         xRet = pTable;
287         pTable->construct();
288     }
289     else
290     {
291         ODBTable* pTable = new ODBTable(this, m_xConnection);
292         xRet = pTable;
293         pTable->construct();
294     }
295     return xRet;
296 }
297 // -----------------------------------------------------------------------------
298 // XAppend
299 ObjectType OTableContainer::appendObject( const ::rtl::OUString& _rForName, const Reference< XPropertySet >& descriptor )
300 {
301     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::appendObject" );
302     // append the new table with a create stmt
303     ::rtl::OUString aName = getString(descriptor->getPropertyValue(PROPERTY_NAME));
304     if(m_xMasterContainer.is() && m_xMasterContainer->hasByName(aName))
305     {
306         String sMessage(DBACORE_RESSTRING(RID_STR_TABLE_IS_FILTERED));
307         sMessage.SearchAndReplaceAscii("$name$", aName);
308         throw SQLException(sMessage,static_cast<XTypeProvider*>(static_cast<OFilteredContainer*>(this)),SQLSTATE_GENERAL,1000,Any());
309     }
310 
311     Reference< XConnection > xConnection( m_xConnection.get(), UNO_QUERY );
312     PContainerApprove pApprove( new ObjectNameApproval( xConnection, ObjectNameApproval::TypeTable ) );
313     pApprove->approveElement( aName, descriptor );
314 
315     try
316     {
317         EnsureReset aReset(m_nInAppend);
318         Reference<XAppend> xAppend(m_xMasterContainer,UNO_QUERY);
319         if(xAppend.is())
320         {
321             xAppend->appendByDescriptor(descriptor);
322         }
323         else
324         {
325             ::rtl::OUString aSql = ::dbtools::createSqlCreateTableStatement(descriptor,m_xConnection);
326 
327             Reference<XConnection> xCon = m_xConnection;
328             OSL_ENSURE(xCon.is(),"Connection is null!");
329             if ( xCon.is() )
330             {
331                 Reference< XStatement > xStmt = xCon->createStatement(  );
332                 if ( xStmt.is() )
333                     xStmt->execute(aSql);
334                 ::comphelper::disposeComponent(xStmt);
335             }
336         }
337     }
338     catch(Exception&)
339     {
340         throw;
341     }
342 
343     Reference<XPropertySet> xTableDefinition;
344     Reference<XNameAccess> xColumnDefinitions;
345     lcl_createDefintionObject(getNameForObject(descriptor),m_xTableDefinitions,xTableDefinition,xColumnDefinitions,sal_False);
346     Reference<XColumnsSupplier> xSup(descriptor,UNO_QUERY);
347     Reference<XDataDescriptorFactory> xFac(xColumnDefinitions,UNO_QUERY);
348     Reference<XAppend> xAppend(xColumnDefinitions,UNO_QUERY);
349     sal_Bool bModified = sal_False;
350     if ( xSup.is() && xColumnDefinitions.is() && xFac.is() && xAppend.is() )
351     {
352         Reference<XNameAccess> xNames = xSup->getColumns();
353         if ( xNames.is() )
354         {
355             Reference<XPropertySet> xProp = xFac->createDataDescriptor();
356             Sequence< ::rtl::OUString> aSeq = xNames->getElementNames();
357             const ::rtl::OUString* pIter = aSeq.getConstArray();
358             const ::rtl::OUString* pEnd   = pIter + aSeq.getLength();
359             for(;pIter != pEnd;++pIter)
360             {
361                 if ( !xColumnDefinitions->hasByName(*pIter) )
362                 {
363                     Reference<XPropertySet> xColumn(xNames->getByName(*pIter),UNO_QUERY);
364                     if ( !OColumnSettings::hasDefaultSettings( xColumn ) )
365                     {
366                         ::comphelper::copyProperties( xColumn, xProp );
367                         xAppend->appendByDescriptor( xProp );
368                         bModified = sal_True;
369                     }
370                 }
371             }
372         }
373     }
374     const static ::rtl::OUString s_pTableProps[] = {    ::rtl::OUString(PROPERTY_FILTER), ::rtl::OUString(PROPERTY_ORDER)
375                                                     , ::rtl::OUString(PROPERTY_APPLYFILTER), ::rtl::OUString(PROPERTY_FONT)
376                                                     , ::rtl::OUString(PROPERTY_ROW_HEIGHT), ::rtl::OUString(PROPERTY_TEXTCOLOR)
377                                                     , ::rtl::OUString(PROPERTY_TEXTLINECOLOR), ::rtl::OUString(PROPERTY_TEXTEMPHASIS)
378                                                     , ::rtl::OUString(PROPERTY_TEXTRELIEF) };
379     Sequence< ::rtl::OUString> aNames(s_pTableProps,sizeof(s_pTableProps)/sizeof(s_pTableProps[0]));
380     if ( bModified || !lcl_isPropertySetDefaulted(aNames,xTableDefinition) )
381         ::dbaccess::notifyDataSourceModified(m_xTableDefinitions,sal_True);
382 
383     return createObject( _rForName );
384 }
385 // -------------------------------------------------------------------------
386 // XDrop
387 void OTableContainer::dropObject(sal_Int32 _nPos,const ::rtl::OUString _sElementName)
388 {
389     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::dropObject" );
390     m_bInDrop = sal_True;
391     try
392     {
393         Reference< XDrop > xDrop(m_xMasterContainer,UNO_QUERY);
394         if(xDrop.is())
395             xDrop->dropByName(_sElementName);
396         else
397         {
398             ::rtl::OUString sCatalog,sSchema,sTable,sComposedName;
399 
400             sal_Bool bIsView = sal_False;
401             Reference<XPropertySet> xTable(getObject(_nPos),UNO_QUERY);
402             if ( xTable.is() && m_xMetaData.is() )
403             {
404                 if( m_xMetaData.is() && m_xMetaData->supportsCatalogsInTableDefinitions() )
405                     xTable->getPropertyValue(PROPERTY_CATALOGNAME)  >>= sCatalog;
406                 if( m_xMetaData.is() && m_xMetaData->supportsSchemasInTableDefinitions() )
407                     xTable->getPropertyValue(PROPERTY_SCHEMANAME)   >>= sSchema;
408                 xTable->getPropertyValue(PROPERTY_NAME)         >>= sTable;
409 
410                 sComposedName = ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sTable, sal_True, ::dbtools::eInTableDefinitions );
411 
412                 ::rtl::OUString sType;
413                 xTable->getPropertyValue(PROPERTY_TYPE)         >>= sType;
414                 bIsView = sType.equalsIgnoreAsciiCase(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("VIEW")));
415             }
416 
417             if(!sComposedName.getLength())
418                 ::dbtools::throwFunctionSequenceException(static_cast<XTypeProvider*>(static_cast<OFilteredContainer*>(this)));
419 
420             ::rtl::OUString aSql = ::rtl::OUString::createFromAscii("DROP ");
421 
422             // #104282# OJ
423             if ( bIsView ) // here we have a view
424                 aSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("VIEW "));
425             else
426                 aSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TABLE "));
427             aSql += sComposedName;
428             Reference<XConnection> xCon = m_xConnection;
429             OSL_ENSURE(xCon.is(),"Connection is null!");
430             if ( xCon.is() )
431             {
432                 Reference< XStatement > xStmt = xCon->createStatement(  );
433                 if(xStmt.is())
434                     xStmt->execute(aSql);
435                 ::comphelper::disposeComponent(xStmt);
436             }
437         }
438 
439         if ( m_xTableDefinitions.is() && m_xTableDefinitions->hasByName(_sElementName) )
440         {
441             m_xTableDefinitions->removeByName(_sElementName);
442         }
443     }
444     catch(Exception&)
445     {
446         m_bInDrop = sal_False;
447         throw;
448     }
449     m_bInDrop = sal_False;
450 }
451 // -----------------------------------------------------------------------------
452 void SAL_CALL OTableContainer::elementInserted( const ContainerEvent& Event ) throw (RuntimeException)
453 {
454     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::elementInserted" );
455     ::osl::MutexGuard aGuard(m_rMutex);
456     ::rtl::OUString sName;
457     Event.Accessor >>= sName;
458     if ( !m_nInAppend && !hasByName(sName) )
459     {
460         if(!m_xMasterContainer.is() || m_xMasterContainer->hasByName(sName))
461         {
462             ObjectType xName = createObject(sName);
463             insertElement(sName,xName);
464             // and notify our listeners
465             ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(sName), makeAny(xName), Any());
466             m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
467         }
468     }
469 }
470 // -----------------------------------------------------------------------------
471 void SAL_CALL OTableContainer::elementRemoved( const ContainerEvent& /*Event*/ ) throw (RuntimeException)
472 {
473     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::elementRemoved" );
474 }
475 // -----------------------------------------------------------------------------
476 void SAL_CALL OTableContainer::elementReplaced( const ContainerEvent& Event ) throw (RuntimeException)
477 {
478     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::elementReplaced" );
479     // create a new config entry
480     {
481         ::rtl::OUString sOldComposedName,sNewComposedName;
482         Event.ReplacedElement   >>= sOldComposedName;
483         Event.Accessor          >>= sNewComposedName;
484 
485         renameObject(sOldComposedName,sNewComposedName);
486     }
487 }
488 // -----------------------------------------------------------------------------
489 void SAL_CALL OTableContainer::disposing()
490 {
491     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::disposing" );
492     OFilteredContainer::disposing();
493     // say our listeners goobye
494     m_xTableDefinitions = NULL;
495     m_pTableMediator = NULL;
496 }
497 // -----------------------------------------------------------------------------
498 void SAL_CALL OTableContainer::disposing( const ::com::sun::star::lang::EventObject& /*Source*/ ) throw (::com::sun::star::uno::RuntimeException)
499 {
500     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::disposing" );
501 }
502 
503 // -----------------------------------------------------------------------------
504 void OTableContainer::addMasterContainerListener()
505 {
506     try
507     {
508         Reference< XContainer > xCont( m_xMasterContainer, UNO_QUERY_THROW );
509         xCont->addContainerListener( this );
510     }
511     catch( const Exception& )
512     {
513         DBG_UNHANDLED_EXCEPTION();
514     }
515 }
516 
517