update dev300-m58
[ooovba.git] / connectivity / source / drivers / mozab / MStatement.cxx
blob19f32d0cb5eacb81af45f2fbd7fa1d9e2042b2e3
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: MStatement.cxx,v $
10 * $Revision: 1.18.56.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
34 #include <stdio.h>
35 #include <osl/diagnose.h>
36 #include <comphelper/property.hxx>
37 #include <comphelper/uno3.hxx>
38 #include <osl/thread.h>
39 #include <tools/diagnose_ex.h>
40 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
41 #include <com/sun/star/sdbc/ResultSetType.hpp>
42 #include <com/sun/star/sdbc/FetchDirection.hpp>
43 #include <com/sun/star/lang/DisposedException.hpp>
44 #include <comphelper/sequence.hxx>
45 #include <cppuhelper/typeprovider.hxx>
46 #include <comphelper/extract.hxx>
47 #include <comphelper/types.hxx>
48 #include <connectivity/dbexception.hxx>
49 #include <com/sun/star/container/XIndexAccess.hpp>
51 #include <algorithm>
53 #include "diagnose_ex.h"
54 #include "MDriver.hxx"
55 #include "MStatement.hxx"
56 #include "MConnection.hxx"
57 #include "MResultSet.hxx"
58 #include "MDatabaseMetaData.hxx"
59 #include "resource/mozab_res.hrc"
60 #include "resource/common_res.hrc"
62 #if OSL_DEBUG_LEVEL > 0
63 # define OUtoCStr( x ) ( ::rtl::OUStringToOString ( (x), RTL_TEXTENCODING_ASCII_US).getStr())
64 #else /* OSL_DEBUG_LEVEL */
65 # define OUtoCStr( x ) ("dummy")
66 #endif /* OSL_DEBUG_LEVEL */
68 static ::osl::Mutex m_ThreadMutex;
70 using namespace ::comphelper;
71 using namespace connectivity::mozab;
72 using namespace connectivity;
73 //------------------------------------------------------------------------------
74 using namespace com::sun::star::uno;
75 using namespace com::sun::star::lang;
76 using namespace com::sun::star::beans;
77 using namespace com::sun::star::sdbc;
78 using namespace com::sun::star::container;
79 using namespace com::sun::star::io;
80 using namespace com::sun::star::util;
81 //------------------------------------------------------------------------------
82 OCommonStatement::OCommonStatement(OConnection* _pConnection )
83 :OCommonStatement_IBASE(m_aMutex)
84 ,OPropertySetHelper(OCommonStatement_IBASE::rBHelper)
85 ,OCommonStatement_SBASE((::cppu::OWeakObject*)_pConnection, this)
86 ,m_xDBMetaData(_pConnection->getMetaData())
87 ,m_pTable(NULL)
88 ,m_pConnection(_pConnection)
89 ,m_aParser(_pConnection->getDriver()->getMSFactory())
90 ,m_pSQLIterator( new OSQLParseTreeIterator( _pConnection, _pConnection->createCatalog()->getTables(), m_aParser, NULL ) )
91 ,m_pParseTree(NULL)
92 ,rBHelper(OCommonStatement_IBASE::rBHelper)
94 m_pConnection->acquire();
95 OSL_TRACE("In/Out: OCommonStatement::OCommonStatement" );
97 // -----------------------------------------------------------------------------
98 OCommonStatement::~OCommonStatement()
102 //------------------------------------------------------------------------------
103 void OCommonStatement::disposing()
105 ::osl::MutexGuard aGuard(m_aMutex);
107 clearWarnings();
108 clearCachedResultSet();
110 if (m_pConnection)
111 m_pConnection->release();
112 m_pConnection = NULL;
114 m_pSQLIterator->dispose();
116 dispose_ChildImpl();
117 OCommonStatement_IBASE::disposing();
119 //-----------------------------------------------------------------------------
120 Any SAL_CALL OCommonStatement::queryInterface( const Type & rType ) throw(RuntimeException)
122 Any aRet = OCommonStatement_IBASE::queryInterface(rType);
123 if(!aRet.hasValue())
124 aRet = OPropertySetHelper::queryInterface(rType);
125 return aRet;
127 // -------------------------------------------------------------------------
128 Sequence< Type > SAL_CALL OCommonStatement::getTypes( ) throw(RuntimeException)
130 ::cppu::OTypeCollection aTypes( ::getCppuType( (const Reference< XMultiPropertySet > *)0 ),
131 ::getCppuType( (const Reference< XFastPropertySet > *)0 ),
132 ::getCppuType( (const Reference< XPropertySet > *)0 ));
134 return ::comphelper::concatSequences(aTypes.getTypes(),OCommonStatement_IBASE::getTypes());
136 // -------------------------------------------------------------------------
137 void SAL_CALL OCommonStatement::close( ) throw(SQLException, RuntimeException)
140 ::osl::MutexGuard aGuard( m_aMutex );
141 checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed);
143 dispose();
147 // -------------------------------------------------------------------------
148 void OCommonStatement::createTable( ) throw ( SQLException, RuntimeException )
150 if(m_pParseTree)
152 ::vos::ORef<connectivity::OSQLColumns> xCreateColumn;
153 if (m_pSQLIterator->getStatementType() == SQL_STATEMENT_CREATE_TABLE)
155 const OSQLTables& xTabs = m_pSQLIterator->getTables();
156 OSL_ENSURE( !xTabs.empty(), "Need a Table");
157 ::rtl::OUString ouTableName=xTabs.begin()->first;
158 xCreateColumn = m_pSQLIterator->getCreateColumns();
159 OSL_ENSURE(xCreateColumn.isValid(), "Need the Columns!!");
161 const OColumnAlias& aColumnAlias = m_pConnection->getColumnAlias();
163 OSQLColumns::Vector::const_iterator aIter = xCreateColumn->get().begin();
164 const ::rtl::OUString sProprtyName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
165 ::rtl::OUString sName;
166 for (sal_Int32 i = 1; aIter != xCreateColumn->get().end();++aIter, i++)
168 (*aIter)->getPropertyValue(sProprtyName) >>= sName;
169 if ( !aColumnAlias.hasAlias( sName ) )
172 const ::rtl::OUString sError( getOwnConnection()->getResources().getResourceStringWithSubstitution(
173 STR_INVALID_COLUMNNAME,
174 "$columnname$", sName
175 ) );
176 ::dbtools::throwGenericSQLException(sError,*this);
179 MDatabaseMetaDataHelper _aDbHelper;
180 if (!_aDbHelper.NewAddressBook(m_pConnection,ouTableName))
182 getOwnConnection()->throwSQLException( _aDbHelper.getError(), *this );
184 m_pSQLIterator.reset( new ::connectivity::OSQLParseTreeIterator(
185 m_pConnection, m_pConnection->createCatalog()->getTables(), m_aParser, NULL ) );
189 else
190 getOwnConnection()->throwSQLException( STR_QUERY_TOO_COMPLEX, *this );
192 // -------------------------------------------------------------------------
193 OCommonStatement::StatementType OCommonStatement::parseSql( const ::rtl::OUString& sql , sal_Bool bAdjusted)
194 throw ( SQLException, RuntimeException )
196 ::rtl::OUString aErr;
198 m_pParseTree = m_aParser.parseTree(aErr,sql);
200 #if OSL_DEBUG_LEVEL > 0
202 const char* str = OUtoCStr(sql);
203 OSL_UNUSED( str );
204 OSL_TRACE("ParseSQL: %s\n", OUtoCStr( sql ) );
206 #endif // OSL_DEBUG_LEVEL
208 if(m_pParseTree)
210 m_pSQLIterator->setParseTree(m_pParseTree);
211 m_pSQLIterator->traverseAll();
212 const OSQLTables& xTabs = m_pSQLIterator->getTables();
213 if(xTabs.empty())
214 getOwnConnection()->throwSQLException( STR_QUERY_AT_LEAST_ONE_TABLES, *this );
216 #if OSL_DEBUG_LEVEL > 0
217 OSQLTables::const_iterator citer;
218 for( citer = xTabs.begin(); citer != xTabs.end(); ++citer ) {
219 OSL_TRACE("SELECT Table : %s\n", OUtoCStr(citer->first) );
221 #endif
223 Reference<XIndexAccess> xNames;
224 switch(m_pSQLIterator->getStatementType())
226 case SQL_STATEMENT_SELECT:
228 // at this moment we support only one table per select statement
230 OSL_ENSURE( xTabs.begin() != xTabs.end(), "Need a Table");
232 m_pTable = static_cast< OTable* > (xTabs.begin()->second.get());
233 m_xColNames = m_pTable->getColumns();
234 xNames = Reference<XIndexAccess>(m_xColNames,UNO_QUERY);
235 // set the binding of the resultrow
236 m_aRow = new OValueVector(xNames->getCount());
237 (m_aRow->get())[0].setBound(sal_True);
238 ::std::for_each(m_aRow->get().begin()+1,m_aRow->get().end(),TSetBound(sal_False));
239 // create the column mapping
240 createColumnMapping();
242 analyseSQL();
243 return eSelect;
245 case SQL_STATEMENT_CREATE_TABLE:
246 createTable();
247 return eCreateTable;
249 default:
250 break;
253 else if(!bAdjusted) //Our sql parser does not support a statement like "create table foo"
254 // So we append ("E-mail" varchar) to the last of it to make it work
256 return parseSql(sql + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("(""E-mail"" caracter)")),sal_True);
259 getOwnConnection()->throwSQLException( STR_QUERY_TOO_COMPLEX, *this );
260 OSL_ENSURE( false, "OCommonStatement::parseSql: unreachable!" );
261 return eSelect;
264 // -------------------------------------------------------------------------
265 Reference< XResultSet > OCommonStatement::impl_executeCurrentQuery()
267 clearCachedResultSet();
269 ::rtl::Reference< OResultSet > pResult( new OResultSet( this, m_pSQLIterator ) );
270 initializeResultSet( pResult.get() );
272 pResult->executeQuery();
273 cacheResultSet( pResult ); // only cache if we survived the execution
275 return pResult.get();
279 // -------------------------------------------------------------------------
280 void OCommonStatement::initializeResultSet( OResultSet* _pResult )
282 ENSURE_OR_THROW( _pResult, "invalid result set" );
284 _pResult->setColumnMapping(m_aColMapping);
285 _pResult->setOrderByColumns(m_aOrderbyColumnNumber);
286 _pResult->setOrderByAscending(m_aOrderbyAscending);
287 _pResult->setBindingRow(m_aRow);
288 _pResult->setTable(m_pTable);
291 // -------------------------------------------------------------------------
292 void OCommonStatement::clearCachedResultSet()
294 Reference< XResultSet > xResultSet( m_xResultSet.get(), UNO_QUERY );
295 if ( !xResultSet.is() )
296 return;
300 Reference< XCloseable > xCloseable( xResultSet, UNO_QUERY_THROW );
301 xCloseable->close();
303 catch( const DisposedException& )
305 DBG_UNHANDLED_EXCEPTION();
308 m_xResultSet = Reference< XResultSet >();
311 // -------------------------------------------------------------------------
312 void OCommonStatement::cacheResultSet( const ::rtl::Reference< OResultSet >& _pResult )
314 ENSURE_OR_THROW( _pResult.is(), "invalid result set" );
315 m_xResultSet = Reference< XResultSet >( _pResult.get() );
318 // -------------------------------------------------------------------------
319 sal_Bool SAL_CALL OCommonStatement::execute( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
321 ::osl::MutexGuard aGuard( m_aMutex );
322 checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed);
324 OSL_TRACE("Statement::execute( %s )", OUtoCStr( sql ) );
326 Reference< XResultSet > xRS = executeQuery( sql );
327 // returns true when a resultset is available
328 return xRS.is();
330 // -------------------------------------------------------------------------
332 Reference< XResultSet > SAL_CALL OCommonStatement::executeQuery( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
334 ::osl::MutexGuard aGuard( m_ThreadMutex );
335 checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed);
337 OSL_TRACE("Statement::executeQuery( %s )", OUtoCStr( sql ) );
339 // parse the statement
340 StatementType eStatementType = parseSql( sql );
341 if ( eStatementType != eSelect )
342 return NULL;
344 return impl_executeCurrentQuery();
346 // -------------------------------------------------------------------------
348 Reference< XConnection > SAL_CALL OCommonStatement::getConnection( ) throw(SQLException, RuntimeException)
350 ::osl::MutexGuard aGuard( m_aMutex );
351 checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed);
353 // just return our connection here
354 return (Reference< XConnection >)m_pConnection;
356 // -----------------------------------------------------------------------------
357 Any SAL_CALL OStatement::queryInterface( const Type & rType ) throw(RuntimeException)
359 Any aRet = ::cppu::queryInterface(rType,static_cast< XServiceInfo*> (this));
360 if(!aRet.hasValue())
361 aRet = OCommonStatement::queryInterface(rType);
362 return aRet;
364 // -------------------------------------------------------------------------
365 sal_Int32 SAL_CALL OCommonStatement::executeUpdate( const ::rtl::OUString& /*sql*/ ) throw(SQLException, RuntimeException)
367 ::dbtools::throwFeatureNotImplementedException( "XStatement::executeUpdate", *this );
368 return 0;
371 // -------------------------------------------------------------------------
372 Any SAL_CALL OCommonStatement::getWarnings( ) throw(SQLException, RuntimeException)
374 ::osl::MutexGuard aGuard( m_aMutex );
375 checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed);
377 return makeAny(m_aLastWarning);
379 // -------------------------------------------------------------------------
381 // -------------------------------------------------------------------------
382 void SAL_CALL OCommonStatement::clearWarnings( ) throw(SQLException, RuntimeException)
384 ::osl::MutexGuard aGuard( m_aMutex );
385 checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed);
388 m_aLastWarning = SQLWarning();
390 // -------------------------------------------------------------------------
391 ::cppu::IPropertyArrayHelper* OCommonStatement::createArrayHelper( ) const
393 // this properties are define by the service resultset
394 // they must in alphabetic order
395 Sequence< Property > aProps(9);
396 Property* pProperties = aProps.getArray();
397 sal_Int32 nPos = 0;
398 DECL_PROP0(CURSORNAME, ::rtl::OUString);
399 DECL_BOOL_PROP0(ESCAPEPROCESSING);
400 DECL_PROP0(FETCHDIRECTION,sal_Int32);
401 DECL_PROP0(FETCHSIZE, sal_Int32);
402 DECL_PROP0(MAXFIELDSIZE,sal_Int32);
403 DECL_PROP0(MAXROWS, sal_Int32);
404 DECL_PROP0(QUERYTIMEOUT,sal_Int32);
405 DECL_PROP0(RESULTSETCONCURRENCY,sal_Int32);
406 DECL_PROP0(RESULTSETTYPE,sal_Int32);
408 return new ::cppu::OPropertyArrayHelper(aProps);
411 // -------------------------------------------------------------------------
412 ::cppu::IPropertyArrayHelper & OCommonStatement::getInfoHelper()
414 return *const_cast<OCommonStatement*>(this)->getArrayHelper();
416 // -------------------------------------------------------------------------
417 sal_Bool OCommonStatement::convertFastPropertyValue(
418 Any & /*rConvertedValue*/,
419 Any & /*rOldValue*/,
420 sal_Int32 /*nHandle*/,
421 const Any& /*rValue*/ )
422 throw (::com::sun::star::lang::IllegalArgumentException)
424 sal_Bool bConverted = sal_False;
425 // here we have to try to convert
426 return bConverted;
428 // -------------------------------------------------------------------------
429 void OCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& /*rValue*/) throw (Exception)
431 // set the value to what ever is nescessary
432 switch(nHandle)
434 case PROPERTY_ID_QUERYTIMEOUT:
435 case PROPERTY_ID_MAXFIELDSIZE:
436 case PROPERTY_ID_MAXROWS:
437 case PROPERTY_ID_RESULTSETCONCURRENCY:
438 case PROPERTY_ID_RESULTSETTYPE:
439 case PROPERTY_ID_FETCHDIRECTION:
440 case PROPERTY_ID_FETCHSIZE:
441 case PROPERTY_ID_ESCAPEPROCESSING:
442 default:
446 // -------------------------------------------------------------------------
447 void OCommonStatement::getFastPropertyValue(Any& /*rValue*/,sal_Int32 nHandle) const
449 switch(nHandle)
451 case PROPERTY_ID_QUERYTIMEOUT:
452 case PROPERTY_ID_MAXFIELDSIZE:
453 case PROPERTY_ID_MAXROWS:
454 case PROPERTY_ID_RESULTSETCONCURRENCY:
455 case PROPERTY_ID_RESULTSETTYPE:
456 case PROPERTY_ID_FETCHDIRECTION:
457 case PROPERTY_ID_FETCHSIZE:
458 case PROPERTY_ID_ESCAPEPROCESSING:
459 default:
463 // -------------------------------------------------------------------------
464 IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbcx.OStatement","com.sun.star.sdbc.Statement");
465 // -----------------------------------------------------------------------------
466 void SAL_CALL OCommonStatement::acquire() throw()
468 OCommonStatement_IBASE::acquire();
470 // -----------------------------------------------------------------------------
471 void SAL_CALL OCommonStatement::release() throw()
473 relase_ChildImpl();
475 // -----------------------------------------------------------------------------
476 void SAL_CALL OStatement::acquire() throw()
478 OCommonStatement::acquire();
480 // -----------------------------------------------------------------------------
481 void SAL_CALL OStatement::release() throw()
483 OCommonStatement::release();
485 // -----------------------------------------------------------------------------
486 Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL OCommonStatement::getPropertySetInfo( ) throw(RuntimeException)
488 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
490 // -----------------------------------------------------------------------------
491 void OCommonStatement::createColumnMapping()
493 size_t i;
495 // initialize the column index map (mapping select columns to table columns)
496 ::vos::ORef<connectivity::OSQLColumns> xColumns = m_pSQLIterator->getSelectColumns();
497 m_aColMapping.resize(xColumns->get().size() + 1);
498 for (i=0; i<m_aColMapping.size(); ++i)
499 m_aColMapping[i] = i;
501 Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY);
502 // now check which columns are bound
503 #if OSL_DEBUG_LEVEL > 0
504 for ( i = 0; i < m_aColMapping.size(); i++ )
505 OSL_TRACE("BEFORE Mapped: %d -> %d", i, m_aColMapping[i] );
506 #endif
507 OResultSet::setBoundedColumns(m_aRow,xColumns,xNames,sal_True,m_xDBMetaData,m_aColMapping);
508 #if OSL_DEBUG_LEVEL > 0
509 for ( i = 0; i < m_aColMapping.size(); i++ )
510 OSL_TRACE("AFTER Mapped: %d -> %d", i, m_aColMapping[i] );
511 #endif
513 // -----------------------------------------------------------------------------
515 void OCommonStatement::analyseSQL()
517 const OSQLParseNode* pOrderbyClause = m_pSQLIterator->getOrderTree();
518 if(pOrderbyClause)
520 OSQLParseNode * pOrderingSpecCommalist = pOrderbyClause->getChild(2);
521 OSL_ENSURE(SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OResultSet: Fehler im Parse Tree");
523 for (sal_uInt32 m = 0; m < pOrderingSpecCommalist->count(); m++)
525 OSQLParseNode * pOrderingSpec = pOrderingSpecCommalist->getChild(m);
526 OSL_ENSURE(SQL_ISRULE(pOrderingSpec,ordering_spec),"OResultSet: Fehler im Parse Tree");
527 OSL_ENSURE(pOrderingSpec->count() == 2,"OResultSet: Fehler im Parse Tree");
529 OSQLParseNode * pColumnRef = pOrderingSpec->getChild(0);
530 if(!SQL_ISRULE(pColumnRef,column_ref))
532 throw SQLException();
534 OSQLParseNode * pAscendingDescending = pOrderingSpec->getChild(1);
535 setOrderbyColumn(pColumnRef,pAscendingDescending);
539 //------------------------------------------------------------------
540 void OCommonStatement::setOrderbyColumn( OSQLParseNode* pColumnRef,
541 OSQLParseNode* pAscendingDescending)
543 ::rtl::OUString aColumnName;
544 if (pColumnRef->count() == 1)
545 aColumnName = pColumnRef->getChild(0)->getTokenValue();
546 else if (pColumnRef->count() == 3)
548 pColumnRef->getChild(2)->parseNodeToStr( aColumnName, getOwnConnection(), NULL, sal_False, sal_False );
550 else
552 throw SQLException();
555 Reference<XColumnLocate> xColLocate(m_xColNames,UNO_QUERY);
556 if(!xColLocate.is())
557 return;
559 m_aOrderbyColumnNumber.push_back(xColLocate->findColumn(aColumnName));
561 // Ascending or Descending?
562 m_aOrderbyAscending.push_back((SQL_ISTOKEN(pAscendingDescending,DESC)) ? SQL_DESC : SQL_ASC);
564 // -----------------------------------------------------------------------------