LibreOffice Module dbaccess (master) 1
query.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include "query.hxx"
21#include <stringconstants.hxx>
25#include "HelperCollections.hxx"
26#include <core_resource.hxx>
27#include <strings.hrc>
28#include <strings.hxx>
29
31#include <osl/diagnose.h>
32
33#include <com/sun/star/sdbc/XConnection.hpp>
34#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
35#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
36#include <com/sun/star/sdb/SQLContext.hpp>
37
40#include <definitioncolumn.hxx>
41
42#include <com/sun/star/beans/PropertyAttribute.hpp>
43#include <com/sun/star/lang/XMultiServiceFactory.hpp>
44#include <ContainerMediator.hxx>
45
46using namespace dbaccess;
47using namespace ::com::sun::star::uno;
48using namespace ::com::sun::star::sdbc;
49using namespace ::com::sun::star::sdbcx;
50using namespace ::com::sun::star::sdb;
51using namespace ::com::sun::star::lang;
52using namespace ::com::sun::star::util;
53using namespace ::com::sun::star::beans;
54using namespace ::com::sun::star::container;
55using namespace ::comphelper;
56using namespace ::osl;
57using namespace ::cppu;
58using namespace ::utl;
59
60namespace dbaccess
61{
62
63// OQuery
64
65OQuery::OQuery( const Reference< XPropertySet >& _rxCommandDefinition
66 ,const Reference< XConnection >& _rxConn
67 ,const Reference< XComponentContext >& _xORB)
70 ,ODataSettings(OContentHelper::rBHelper,true)
71 ,m_xCommandDefinition(_rxCommandDefinition)
72 ,m_xConnection(_rxConn)
73 ,m_pWarnings( nullptr )
74 ,m_eDoingCurrently(AggregateAction::NONE)
75{
78
79 osl_atomic_increment(&m_refCount);
80 OSL_ENSURE(m_xCommandDefinition.is(), "OQuery::OQuery : invalid CommandDefinition object !");
81 if ( m_xCommandDefinition.is() )
82 {
83 try
84 {
85 ::comphelper::copyProperties(_rxCommandDefinition,this);
86 }
87 catch(Exception&)
88 {
89 TOOLS_WARN_EXCEPTION("dbaccess", "OQueryDescriptor_Base::OQueryDescriptor_Base");
90 }
91
92 m_xCommandDefinition->addPropertyChangeListener(OUString(), this);
93 // m_xCommandDefinition->addPropertyChangeListener(PROPERTY_NAME, this);
94 m_xCommandPropInfo = m_xCommandDefinition->getPropertySetInfo();
95 }
96 OSL_ENSURE(m_xConnection.is(), "OQuery::OQuery : invalid connection !");
97 osl_atomic_decrement(&m_refCount);
98}
99
101{
102}
103
104css::uno::Sequence<sal_Int8> OQuery::getImplementationId()
105{
106 return css::uno::Sequence<sal_Int8>();
107}
108
109css::uno::Sequence< css::uno::Type > OQuery::getTypes()
110{
111 return ::comphelper::concatSequences(
113 ODataSettings::getTypes( ),
114 OContentHelper::getTypes( )
115 );
116}
117
119
120void OQuery::rebuildColumns()
121{
122 OSL_PRECOND( getColumnCount() == 0, "OQuery::rebuildColumns: column container should be empty!" );
123 // the base class' definition of rebuildColumns promised that clearColumns is called before rebuildColumns
124
125 try
126 {
127 m_pColumnMediator = nullptr;
128
129 Reference<XColumnsSupplier> xColSup(m_xCommandDefinition,UNO_QUERY);
130 Reference< XNameAccess > xColumnDefinitions;
131 if ( xColSup.is() )
132 {
133 xColumnDefinitions = xColSup->getColumns();
134 if ( xColumnDefinitions.is() )
135 m_pColumnMediator = new OContainerMediator( m_pColumns.get(), xColumnDefinitions );
136 }
137
138 // fill the columns with columns from the statement
139 Reference< XMultiServiceFactory > xFactory( m_xConnection, UNO_QUERY_THROW );
140 SharedUNOComponent< XSingleSelectQueryComposer, DisposableComponent > xComposer(
141 Reference< XSingleSelectQueryComposer >( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW ) );
142
143 Reference< XNameAccess > xColumns;
144 Reference< XIndexAccess > xColumnsIndexed;
145 try
146 {
147 xComposer->setQuery( m_sCommand );
148 Reference< XColumnsSupplier > xCols( xComposer, UNO_QUERY_THROW );
149 xColumns.set( xCols->getColumns(), UNO_SET_THROW );
150 xColumnsIndexed.set( xColumns, UNO_QUERY_THROW );
151 }
152 catch( const SQLException& ) { }
153
154 SharedUNOComponent< XPreparedStatement, DisposableComponent > xPreparedStatement;
155 if ( !xColumns.is() || ( xColumnsIndexed->getCount() == 0 ) )
156 { // the QueryComposer could not parse it. Try a lean version.
157 xPreparedStatement.set( m_xConnection->prepareStatement( m_sCommand ), UNO_QUERY_THROW );
158 Reference< XResultSetMetaDataSupplier > xResMetaDataSup( xPreparedStatement, UNO_QUERY_THROW );
159 Reference< XResultSetMetaData > xResultSetMeta( xResMetaDataSup->getMetaData() );
160 if ( !xResultSetMeta.is() )
161 {
162 OUString sError( DBA_RES( RID_STR_STATEMENT_WITHOUT_RESULT_SET ) );
163 ::dbtools::throwSQLException( sError, StandardSQLState::GENERAL_ERROR, *this );
164 }
165
166 Reference< XDatabaseMetaData > xDBMeta( m_xConnection->getMetaData(), UNO_SET_THROW );
168 ::connectivity::parse::OParseColumn::createColumnsForResultSet( xResultSetMeta, xDBMeta,xColumnDefinitions ) );
170 aParseColumns, xDBMeta->supportsMixedCaseQuotedIdentifiers(), *this, m_aMutex ).release();
171 if ( !xColumns.is() )
172 throw RuntimeException();
173 }
174
175 const Sequence<OUString> aColNames = xColumns->getElementNames();
176 for ( const OUString& rName : aColNames )
177 {
178 Reference<XPropertySet> xSource(xColumns->getByName( rName ),UNO_QUERY);
179 OUString sLabel = rName;
180 if ( xColumnDefinitions.is() && xColumnDefinitions->hasByName(rName) )
181 {
182 Reference<XPropertySet> xCommandColumn(xColumnDefinitions->getByName( rName ),UNO_QUERY);
183 xCommandColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
184 }
185 rtl::Reference<OQueryColumn> pColumn = new OQueryColumn( xSource, m_xConnection, sLabel);
186 pColumn->setParent( *this );
187
188 implAppendColumn( rName, pColumn.get() );
189 Reference< XPropertySet > xDest( *pColumn, UNO_QUERY_THROW );
190 if ( m_pColumnMediator.is() )
191 m_pColumnMediator->notifyElementCreated( rName, xDest );
192 }
193 }
194 catch( const SQLContext& e )
195 {
196 if ( m_pWarnings )
197 m_pWarnings->appendWarning( e );
198 }
199 catch( const SQLWarning& e )
200 {
201 if ( m_pWarnings )
202 m_pWarnings->appendWarning( e );
203 }
204 catch( const SQLException& e )
205 {
206 if ( m_pWarnings )
207 m_pWarnings->appendWarning( e );
208 }
209 catch( const Exception& )
210 {
211 DBG_UNHANDLED_EXCEPTION("dbaccess");
212 }
213}
214
215// XServiceInfo
216OUString SAL_CALL OQuery::getImplementationName()
217 {
218 return "com.sun.star.sdb.dbaccess.OQuery";
219 }
220sal_Bool SAL_CALL OQuery::supportsService(const OUString& _rServiceName)
221 {
222 const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
223 for (const OUString& s : aSupported)
224 if (s == _rServiceName)
225 return true;
226
227 return false;
228 }
229css::uno::Sequence< OUString > SAL_CALL OQuery::getSupportedServiceNames( )
230{
231 return { SERVICE_SDB_DATASETTINGS, SERVICE_SDB_QUERY, "com.sun.star.sdb.QueryDefinition" };
232}
233
234// css::beans::XPropertyChangeListener
235void SAL_CALL OQuery::propertyChange( const PropertyChangeEvent& _rSource )
236{
237 sal_Int32 nOwnHandle = -1;
238 {
239 MutexGuard aGuard(m_aMutex);
240
241 OSL_ENSURE(_rSource.Source.get() == Reference< XInterface >(m_xCommandDefinition, UNO_QUERY).get(),
242 "OQuery::propertyChange : where did this call come from ?");
243
245 // we're setting the property ourself, so we will do the necessary notifications later
246 return;
247
248 // forward this to our own member holding a copy of the property value
249 if (getArrayHelper()->hasPropertyByName(_rSource.PropertyName))
250 {
251 Property aOwnProp = getArrayHelper()->getPropertyByName(_rSource.PropertyName);
252 nOwnHandle = aOwnProp.Handle;
253 ODataSettings::setFastPropertyValue_NoBroadcast(nOwnHandle, _rSource.NewValue);
254 // don't use our own setFastPropertyValue_NoBroadcast, this would forward it to the CommandSettings,
255 // again
256 // and don't use the "real" setPropertyValue, this is too expensive and not sure to succeed
257 }
258 else
259 {
260 OSL_FAIL("OQuery::propertyChange : my CommandDefinition has more properties than I do !");
261 }
262 }
263
264 fire(&nOwnHandle, &_rSource.NewValue, &_rSource.OldValue, 1, false);
265}
266
267void SAL_CALL OQuery::disposing( const EventObject& _rSource )
268{
269 MutexGuard aGuard(m_aMutex);
270
271 OSL_ENSURE(_rSource.Source.get() == Reference< XInterface >(m_xCommandDefinition, UNO_QUERY).get(),
272 "OQuery::disposing : where did this call come from ?");
273
274 m_xCommandDefinition->removePropertyChangeListener(OUString(), this);
275 m_xCommandDefinition = nullptr;
276}
277
278// XDataDescriptorFactory
279Reference< XPropertySet > SAL_CALL OQuery::createDataDescriptor( )
280{
281 return new OQueryDescriptor(*this);
282}
283
284// pseudo-XComponent
285void SAL_CALL OQuery::disposing()
286{
287 MutexGuard aGuard(m_aMutex);
288 if (m_xCommandDefinition.is())
289 {
290 m_xCommandDefinition->removePropertyChangeListener(OUString(), this);
291 m_xCommandDefinition = nullptr;
292 }
294
295 m_pWarnings = nullptr;
296}
297
298void OQuery::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue )
299{
301 OUString sAggPropName;
302 sal_Int16 nAttr = 0;
303 if (getInfoHelper().fillPropertyMembersByHandle(&sAggPropName,&nAttr,_nHandle) &&
304 m_xCommandPropInfo.is() &&
305 m_xCommandPropInfo->hasPropertyByName(sAggPropName))
306 { // the base class holds the property values itself, but we have to forward this to our CommandDefinition
307
309 OAutoActionReset aAutoReset(*this);
310 m_xCommandDefinition->setPropertyValue(sAggPropName, _rValue);
311
312 if ( PROPERTY_ID_COMMAND == _nHandle )
313 // the columns are out of date if we are based on a new statement...
315 }
316}
317
318Reference< XPropertySetInfo > SAL_CALL OQuery::getPropertySetInfo( )
319{
320 return createPropertySetInfo( getInfoHelper() ) ;
321}
322
324{
325 return *getArrayHelper();
326}
327
329{
330 Sequence< Property > aProps;
331 // our own props
332 describeProperties(aProps);
333 return new ::cppu::OPropertyArrayHelper(aProps);
334}
335
336rtl::Reference<OColumn> OQuery::createColumn(const OUString& /*_rName*/) const
337{
338 return nullptr;
339}
340
341void SAL_CALL OQuery::rename( const OUString& newName )
342{
343 MutexGuard aGuard(m_aMutex);
344 Reference<XRename> xRename(m_xCommandDefinition,UNO_QUERY);
345 OSL_ENSURE(xRename.is(),"No XRename interface!");
346 if(xRename.is())
347 xRename->rename(newName);
348}
349
351{
352 // the properties which OCommandBase supplies (it has no own registration, as it's not derived from
353 // an OPropertyStateContainer)
354 registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND|PropertyAttribute::CONSTRAINED,
355 &m_sElementName, cppu::UnoType<decltype(m_sElementName)>::get());
356
357 registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND,
358 &m_sCommand, cppu::UnoType<decltype(m_sCommand)>::get());
359
362
365
368
371
374}
375
377{
378 return "application/vnd.org.openoffice.DatabaseQuery";
379}
380
381} // namespace dbaccess
382
383/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void describeProperties(css::uno::Sequence< css::beans::Property > &_rProps) const
void registerProperty(const OUString &_rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, void *_pPointerToMember, const css::uno::Type &_rMemberType)
virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const css::uno::Any &rValue) override
static ::rtl::Reference< OSQLColumns > createColumnsForResultSet(const css::uno::Reference< css::sdbc::XResultSetMetaData > &_rxResMetaData, const css::uno::Reference< css::sdbc::XDatabaseMetaData > &_rxDBMetaData, const css::uno::Reference< css::container::XNameAccess > &i_xQueryColumns)
mutable::osl::Mutex m_aMutex
virtual css::beans::Property SAL_CALL getPropertyByName(const ::rtl::OUString &rPropertyName)=0
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() SAL_OVERRIDE
css::uno::Sequence< css::beans::PropertyValue > m_aLayoutInformation
Definition: commandbase.hxx:35
void registerPropertiesFor(ODataSettings_Base *_pItem)
register the properties from the param given.
static std::unique_ptr< OPrivateColumns > createWithIntrinsicNames(const ::rtl::Reference< ::connectivity::OSQLColumns > &_rColumns, bool _bCase, ::cppu::OWeakObject &_rParent, ::osl::Mutex &_rMutex)
creates a columns instance as above, but taking the names from the columns itself
a column of a Query, with additional information obtained from parsing the query statement
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
void setColumnsOutOfDate(bool _bOutOfDate=true)
virtual OUString SAL_CALL getImplementationName() override
virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent &evt) override
Definition: query.cxx:235
::dbtools::WarningsContainer * m_pWarnings
Definition: query.hxx:63
virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor() override
Definition: query.cxx:279
AggregateAction m_eDoingCurrently
Definition: query.hxx:67
void registerProperties()
Definition: query.cxx:350
css::uno::Reference< css::beans::XPropertySetInfo > m_xCommandPropInfo
Definition: query.hxx:61
virtual OUString determineContentType() const override
Definition: query.cxx:376
::cppu::IPropertyArrayHelper * getArrayHelper()
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override
Definition: query.cxx:104
virtual void SAL_CALL disposing() override
Definition: query.cxx:285
virtual ::cppu::IPropertyArrayHelper * createArrayHelper() const override
Definition: query.cxx:328
OQuery(const css::uno::Reference< css::beans::XPropertySet > &_rxCommandDefinition, const css::uno::Reference< css::sdbc::XConnection > &_rxConn, const css::uno::Reference< css::uno::XComponentContext > &_xORB)
Definition: query.cxx:65
virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const css::uno::Any &rValue) override
Definition: query.cxx:298
virtual ~OQuery() override
Definition: query.cxx:100
virtual void SAL_CALL rename(const OUString &newName) override
Definition: query.cxx:341
css::uno::Reference< css::sdbc::XConnection > m_xConnection
Definition: query.hxx:60
virtual rtl::Reference< OColumn > createColumn(const OUString &_rName) const override
creates an OColumn object which should represent the column with a given name
Definition: query.cxx:336
css::uno::Reference< css::beans::XPropertySet > m_xCommandDefinition
Definition: query.hxx:59
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
Definition: query.cxx:109
virtual ::cppu::IPropertyArrayHelper &SAL_CALL getInfoHelper() override
Definition: query.cxx:323
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
Definition: query.cxx:318
#define DBA_RES(id)
#define TOOLS_WARN_EXCEPTION(area, stream)
#define DBG_UNHANDLED_EXCEPTION(...)
ULONG m_refCount
Reference< XSingleServiceFactory > xFactory
std::mutex m_aMutex
NONE
@ Exception
OUString newName(std::u16string_view aNewPrefix, std::u16string_view aOldPrefix, std::u16string_view old_Name)
std::shared_ptr< T > make_shared(Args &&... args)
Reference< XConnection > m_xConnection
Definition: objectnames.cxx:79
const Color aColNames[SC_RANGECOLORS]
#define PROPERTY_ID_NAME
#define PROPERTY_ID_ESCAPE_PROCESSING
#define PROPERTY_ID_UPDATE_CATALOGNAME
#define PROPERTY_ID_UPDATE_SCHEMANAME
#define PROPERTY_ID_COMMAND
#define PROPERTY_ID_UPDATE_TABLENAME
#define PROPERTY_ID_LAYOUTINFORMATION
constexpr OUStringLiteral PROPERTY_COMMAND(u"Command")
constexpr OUStringLiteral PROPERTY_UPDATE_TABLENAME(u"UpdateTableName")
constexpr OUStringLiteral PROPERTY_LABEL(u"Label")
constexpr OUStringLiteral PROPERTY_UPDATE_SCHEMANAME(u"UpdateSchemaName")
constexpr OUStringLiteral SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
Definition: strings.hxx:201
constexpr OUStringLiteral SERVICE_SDB_QUERY
Definition: strings.hxx:192
constexpr OUStringLiteral PROPERTY_ESCAPE_PROCESSING(u"EscapeProcessing")
constexpr OUStringLiteral SERVICE_SDB_DATASETTINGS
Definition: strings.hxx:190
constexpr OUStringLiteral PROPERTY_NAME(u"Name")
constexpr OUStringLiteral PROPERTY_UPDATE_CATALOGNAME(u"UpdateCatalogName")
constexpr OUStringLiteral PROPERTY_LAYOUTINFORMATION(u"LayoutInformation")
unsigned char sal_Bool
#define IMPLEMENT_FORWARD_XINTERFACE3(classname, refcountbase, baseclass2, baseclass3)