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