build fix
[LibreOffice.git] / connectivity / source / drivers / mork / MStatement.cxx
blob505afda939c28d158cfeac945f80fdba4d41617d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include <tools/diagnose_ex.h>
22 #include <cppuhelper/queryinterface.hxx>
23 #include <comphelper/processfactory.hxx>
24 #include <connectivity/dbexception.hxx>
26 #include <algorithm>
28 #include "MDriver.hxx"
29 #include "MStatement.hxx"
30 #include "sqlbison.hxx"
31 #include "MResultSet.hxx"
33 #include "resource/mork_res.hrc"
34 #include "resource/common_res.hrc"
36 #if OSL_DEBUG_LEVEL > 0
37 # define OUtoCStr( x ) ( OUStringToOString ( (x), RTL_TEXTENCODING_ASCII_US).getStr())
38 #else /* OSL_DEBUG_LEVEL */
39 # define OUtoCStr( x ) ("dummy")
40 #endif /* OSL_DEBUG_LEVEL */
42 static ::osl::Mutex m_ThreadMutex;
44 using namespace ::comphelper;
45 using namespace connectivity::mork;
46 using namespace connectivity;
48 using namespace com::sun::star::uno;
49 using namespace com::sun::star::lang;
50 using namespace com::sun::star::beans;
51 using namespace com::sun::star::sdbc;
52 using namespace com::sun::star::container;
53 using namespace com::sun::star::io;
54 using namespace com::sun::star::util;
57 OStatement::OStatement( OConnection* _pConnection) : OCommonStatement( _pConnection)
61 OCommonStatement::OCommonStatement(OConnection* _pConnection )
62 :OCommonStatement_IBASE(m_aMutex)
63 ,OPropertySetHelper(OCommonStatement_IBASE::rBHelper)
64 ,OCommonStatement_SBASE(static_cast<cppu::OWeakObject*>(_pConnection), this)
65 ,m_pTable(nullptr)
66 ,m_pConnection(_pConnection)
67 ,m_aParser( comphelper::getComponentContext(_pConnection->getDriver()->getFactory()) )
68 ,m_pSQLIterator( new OSQLParseTreeIterator( _pConnection, _pConnection->createCatalog()->getTables(), m_aParser ) )
70 m_xDBMetaData = _pConnection->getMetaData();
71 m_pParseTree = nullptr;
75 OCommonStatement::~OCommonStatement()
80 void OCommonStatement::disposing()
82 ::osl::MutexGuard aGuard(m_aMutex);
84 clearWarnings();
85 clearCachedResultSet();
87 m_pConnection.clear();
89 m_pSQLIterator->dispose();
90 delete m_pParseTree;
92 dispose_ChildImpl();
93 OCommonStatement_IBASE::disposing();
96 Any SAL_CALL OCommonStatement::queryInterface( const Type & rType ) throw(RuntimeException, std::exception)
98 Any aRet = OCommonStatement_IBASE::queryInterface(rType);
99 if(!aRet.hasValue())
100 aRet = OPropertySetHelper::queryInterface(rType);
101 return aRet;
104 Sequence< Type > SAL_CALL OCommonStatement::getTypes( ) throw(RuntimeException, std::exception)
106 ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(),
107 cppu::UnoType<XFastPropertySet>::get(),
108 cppu::UnoType<XPropertySet>::get());
110 return ::comphelper::concatSequences(aTypes.getTypes(),OCommonStatement_IBASE::getTypes());
113 void SAL_CALL OCommonStatement::close( ) throw(SQLException, RuntimeException, std::exception)
116 ::osl::MutexGuard aGuard( m_aMutex );
117 checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed);
119 dispose();
122 OCommonStatement::StatementType OCommonStatement::parseSql( const OUString& sql , bool bAdjusted)
123 throw ( SQLException, RuntimeException, std::exception )
125 OUString aErr;
127 m_pParseTree = m_aParser.parseTree(aErr,sql);
129 #if OSL_DEBUG_LEVEL > 0
131 OSL_TRACE("ParseSQL: %s", OUtoCStr( sql ) );
133 #endif // OSL_DEBUG_LEVEL
135 if(m_pParseTree)
137 m_pSQLIterator->setParseTree(m_pParseTree);
138 m_pSQLIterator->traverseAll();
139 const OSQLTables& rTabs = m_pSQLIterator->getTables();
141 if (rTabs.empty())
143 getOwnConnection()->throwSQLException( STR_QUERY_AT_LEAST_ONE_TABLES, *this );
146 #if OSL_DEBUG_LEVEL > 0
147 OSQLTables::const_iterator citer;
148 for( citer = rTabs.begin(); citer != rTabs.end(); ++citer ) {
149 OSL_TRACE("SELECT Table : %s", OUtoCStr(citer->first) );
151 #endif
153 Reference<XIndexAccess> xNames;
154 switch(m_pSQLIterator->getStatementType())
156 case OSQLStatementType::Select:
158 // at this moment we support only one table per select statement
160 OSL_ENSURE( rTabs.begin() != rTabs.end(), "Need a Table");
162 m_pTable = static_cast< OTable* > (rTabs.begin()->second.get());
163 m_xColNames = m_pTable->getColumns();
164 xNames.set(m_xColNames,UNO_QUERY);
165 // set the binding of the resultrow
166 m_aRow = new OValueVector(xNames->getCount());
167 (m_aRow->get())[0].setBound(true);
168 ::std::for_each(m_aRow->get().begin()+1,m_aRow->get().end(),TSetBound(false));
169 // create the column mapping
170 createColumnMapping();
172 analyseSQL();
173 return eSelect;
175 case OSQLStatementType::CreateTable:
176 return eCreateTable;
178 default:
179 break;
182 else if(!bAdjusted) //Our sql parser does not support a statement like "create table foo"
183 // So we append ("E-mail" varchar) to the last of it to make it work
185 return parseSql(sql + "(""E-mail"" character)", true);
188 getOwnConnection()->throwSQLException( STR_QUERY_TOO_COMPLEX, *this );
189 OSL_FAIL( "OCommonStatement::parseSql: unreachable!" );
190 return eSelect;
194 Reference< XResultSet > OCommonStatement::impl_executeCurrentQuery()
196 clearCachedResultSet();
198 ::rtl::Reference< OResultSet > pResult( new OResultSet( this, m_pSQLIterator ) );
199 initializeResultSet( pResult.get() );
201 pResult->executeQuery();
202 cacheResultSet( pResult ); // only cache if we survived the execution
204 return pResult.get();
209 void OCommonStatement::initializeResultSet( OResultSet* _pResult )
211 ENSURE_OR_THROW( _pResult, "invalid result set" );
213 _pResult->setColumnMapping(m_aColMapping);
214 _pResult->setOrderByColumns(m_aOrderbyColumnNumber);
215 _pResult->setOrderByAscending(m_aOrderbyAscending);
216 _pResult->setBindingRow(m_aRow);
217 _pResult->setTable(m_pTable);
221 void OCommonStatement::clearCachedResultSet()
223 Reference< XResultSet > xResultSet( m_xResultSet.get(), UNO_QUERY );
224 if ( !xResultSet.is() )
225 return;
227 Reference< XCloseable >( xResultSet, UNO_QUERY_THROW )->close();
229 m_xResultSet.clear();
233 void OCommonStatement::cacheResultSet( const ::rtl::Reference< OResultSet >& _pResult )
235 ENSURE_OR_THROW( _pResult.is(), "invalid result set" );
236 m_xResultSet = Reference< XResultSet >( _pResult.get() );
240 sal_Bool SAL_CALL OCommonStatement::execute( const OUString& sql ) throw(SQLException, RuntimeException, std::exception)
242 ::osl::MutexGuard aGuard( m_aMutex );
243 checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed);
245 OSL_TRACE("Statement::execute( %s )", OUtoCStr( sql ) );
247 Reference< XResultSet > xRS = executeQuery( sql );
248 // returns true when a resultset is available
249 return xRS.is();
253 Reference< XResultSet > SAL_CALL OCommonStatement::executeQuery( const OUString& sql ) throw(SQLException, RuntimeException, std::exception)
255 ::osl::MutexGuard aGuard( m_ThreadMutex );
256 checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed);
258 OSL_TRACE("Statement::executeQuery( %s )", OUtoCStr( sql ) );
260 // parse the statement
261 StatementType eStatementType = parseSql( sql );
262 if ( eStatementType != eSelect )
263 return nullptr;
265 return impl_executeCurrentQuery();
269 Reference< XConnection > SAL_CALL OCommonStatement::getConnection( ) throw(SQLException, RuntimeException, std::exception)
271 ::osl::MutexGuard aGuard( m_aMutex );
272 checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed);
274 // just return our connection here
275 return Reference< XConnection >(m_pConnection.get());
278 Any SAL_CALL OStatement::queryInterface( const Type & rType ) throw(RuntimeException, std::exception)
280 Any aRet = ::cppu::queryInterface(rType,static_cast< XServiceInfo*> (this));
281 if(!aRet.hasValue())
282 aRet = OCommonStatement::queryInterface(rType);
283 return aRet;
286 sal_Int32 SAL_CALL OCommonStatement::executeUpdate( const OUString& /*sql*/ ) throw(SQLException, RuntimeException, std::exception)
288 ::dbtools::throwFeatureNotImplementedSQLException( "XStatement::executeUpdate", *this );
289 return 0;
293 Any SAL_CALL OCommonStatement::getWarnings( ) throw(SQLException, RuntimeException, std::exception)
295 ::osl::MutexGuard aGuard( m_aMutex );
296 checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed);
298 return makeAny(m_aLastWarning);
302 void SAL_CALL OCommonStatement::clearWarnings( ) throw(SQLException, RuntimeException, std::exception)
304 ::osl::MutexGuard aGuard( m_aMutex );
305 checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed);
308 m_aLastWarning = SQLWarning();
311 ::cppu::IPropertyArrayHelper* OCommonStatement::createArrayHelper( ) const
313 // this properties are define by the service resultset
314 // they must in alphabetic order
315 Sequence< Property > aProps(9);
316 Property* pProperties = aProps.getArray();
317 sal_Int32 nPos = 0;
318 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
319 PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0);
320 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),
321 PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0);
322 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
323 PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0);
324 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
325 PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0);
326 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE),
327 PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0);
328 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS),
329 PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0);
330 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT),
331 PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0);
332 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
333 PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0);
334 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
335 PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0);
337 return new ::cppu::OPropertyArrayHelper(aProps);
341 ::cppu::IPropertyArrayHelper & OCommonStatement::getInfoHelper()
343 return *getArrayHelper();
346 sal_Bool OCommonStatement::convertFastPropertyValue(
347 Any & /*rConvertedValue*/,
348 Any & /*rOldValue*/,
349 sal_Int32 /*nHandle*/,
350 const Any& /*rValue*/ )
351 throw (css::lang::IllegalArgumentException)
353 bool bConverted = false;
354 // here we have to try to convert
355 return bConverted;
358 void OCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& /*rValue*/) throw (Exception, std::exception)
360 // set the value to whatever is necessary
361 switch(nHandle)
363 case PROPERTY_ID_QUERYTIMEOUT:
364 case PROPERTY_ID_MAXFIELDSIZE:
365 case PROPERTY_ID_MAXROWS:
366 case PROPERTY_ID_RESULTSETCONCURRENCY:
367 case PROPERTY_ID_RESULTSETTYPE:
368 case PROPERTY_ID_FETCHDIRECTION:
369 case PROPERTY_ID_FETCHSIZE:
370 case PROPERTY_ID_ESCAPEPROCESSING:
371 default:
376 void OCommonStatement::getFastPropertyValue(Any& /*rValue*/,sal_Int32 nHandle) const
378 switch(nHandle)
380 case PROPERTY_ID_QUERYTIMEOUT:
381 case PROPERTY_ID_MAXFIELDSIZE:
382 case PROPERTY_ID_MAXROWS:
383 case PROPERTY_ID_RESULTSETCONCURRENCY:
384 case PROPERTY_ID_RESULTSETTYPE:
385 case PROPERTY_ID_FETCHDIRECTION:
386 case PROPERTY_ID_FETCHSIZE:
387 case PROPERTY_ID_ESCAPEPROCESSING:
388 default:
393 IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbcx.OStatement","com.sun.star.sdbc.Statement");
395 void SAL_CALL OCommonStatement::acquire() throw()
397 OCommonStatement_IBASE::acquire();
400 void SAL_CALL OCommonStatement::release() throw()
402 release_ChildImpl();
405 void SAL_CALL OStatement::acquire() throw()
407 OCommonStatement::acquire();
410 void SAL_CALL OStatement::release() throw()
412 OCommonStatement::release();
415 Reference< css::beans::XPropertySetInfo > SAL_CALL OCommonStatement::getPropertySetInfo( ) throw(RuntimeException, std::exception)
417 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
420 void OCommonStatement::createColumnMapping()
422 size_t i;
424 // initialize the column index map (mapping select columns to table columns)
425 ::rtl::Reference<connectivity::OSQLColumns> xColumns = m_pSQLIterator->getSelectColumns();
426 m_aColMapping.resize(xColumns->get().size() + 1);
427 for (i=0; i<m_aColMapping.size(); ++i)
428 m_aColMapping[i] = static_cast<sal_Int32>(i);
430 Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY);
431 // now check which columns are bound
432 #if OSL_DEBUG_LEVEL > 0
433 for ( i = 0; i < m_aColMapping.size(); i++ )
434 SAL_INFO(
435 "connectivity.mork",
436 "BEFORE Mapped: " << i << " -> " << m_aColMapping[i]);
437 #endif
438 OResultSet::setBoundedColumns(m_aRow,xColumns,xNames,true,m_xDBMetaData,m_aColMapping);
439 #if OSL_DEBUG_LEVEL > 0
440 for ( i = 0; i < m_aColMapping.size(); i++ )
441 SAL_INFO(
442 "connectivity.mork",
443 "AFTER Mapped: " << i << " -> " << m_aColMapping[i]);
444 #endif
448 void OCommonStatement::analyseSQL()
450 const OSQLParseNode* pOrderbyClause = m_pSQLIterator->getOrderTree();
451 if(pOrderbyClause)
453 OSQLParseNode * pOrderingSpecCommalist = pOrderbyClause->getChild(2);
454 OSL_ENSURE(SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OResultSet: Fehler im Parse Tree");
456 for (size_t m = 0; m < pOrderingSpecCommalist->count(); m++)
458 OSQLParseNode * pOrderingSpec = pOrderingSpecCommalist->getChild(m);
459 OSL_ENSURE(SQL_ISRULE(pOrderingSpec,ordering_spec),"OResultSet: Fehler im Parse Tree");
460 OSL_ENSURE(pOrderingSpec->count() == 2,"OResultSet: Fehler im Parse Tree");
462 OSQLParseNode * pColumnRef = pOrderingSpec->getChild(0);
463 if(!SQL_ISRULE(pColumnRef,column_ref))
465 throw SQLException();
467 OSQLParseNode * pAscendingDescending = pOrderingSpec->getChild(1);
468 setOrderbyColumn(pColumnRef,pAscendingDescending);
473 void OCommonStatement::setOrderbyColumn( OSQLParseNode* pColumnRef,
474 OSQLParseNode* pAscendingDescending)
476 OUString aColumnName;
477 if (pColumnRef->count() == 1)
478 aColumnName = pColumnRef->getChild(0)->getTokenValue();
479 else if (pColumnRef->count() == 3)
481 pColumnRef->getChild(2)->parseNodeToStr( aColumnName, getOwnConnection(), nullptr, false, false );
483 else
485 throw SQLException();
488 Reference<XColumnLocate> xColLocate(m_xColNames,UNO_QUERY);
489 if(!xColLocate.is())
490 return;
492 m_aOrderbyColumnNumber.push_back(xColLocate->findColumn(aColumnName));
494 // Ascending or Descending?
495 m_aOrderbyAscending.push_back((SQL_ISTOKEN(pAscendingDescending,DESC)) ? TAscendingOrder::DESC : TAscendingOrder::ASC);
499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */