1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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"
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>
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())
88 ,m_pConnection(_pConnection
)
89 ,m_aParser(_pConnection
->getDriver()->getMSFactory())
90 ,m_pSQLIterator( new OSQLParseTreeIterator( _pConnection
, _pConnection
->createCatalog()->getTables(), m_aParser
, 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
);
108 clearCachedResultSet();
111 m_pConnection
->release();
112 m_pConnection
= NULL
;
114 m_pSQLIterator
->dispose();
117 OCommonStatement_IBASE::disposing();
119 //-----------------------------------------------------------------------------
120 Any SAL_CALL
OCommonStatement::queryInterface( const Type
& rType
) throw(RuntimeException
)
122 Any aRet
= OCommonStatement_IBASE::queryInterface(rType
);
124 aRet
= OPropertySetHelper::queryInterface(rType
);
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
);
147 // -------------------------------------------------------------------------
148 void OCommonStatement::createTable( ) throw ( SQLException
, RuntimeException
)
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
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
) );
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
);
204 OSL_TRACE("ParseSQL: %s\n", OUtoCStr( sql
) );
206 #endif // OSL_DEBUG_LEVEL
210 m_pSQLIterator
->setParseTree(m_pParseTree
);
211 m_pSQLIterator
->traverseAll();
212 const OSQLTables
& xTabs
= m_pSQLIterator
->getTables();
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
) );
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();
245 case SQL_STATEMENT_CREATE_TABLE
:
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!" );
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() )
300 Reference
< XCloseable
> xCloseable( xResultSet
, UNO_QUERY_THROW
);
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
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
)
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));
361 aRet
= OCommonStatement::queryInterface(rType
);
364 // -------------------------------------------------------------------------
365 sal_Int32 SAL_CALL
OCommonStatement::executeUpdate( const ::rtl::OUString
& /*sql*/ ) throw(SQLException
, RuntimeException
)
367 ::dbtools::throwFeatureNotImplementedException( "XStatement::executeUpdate", *this );
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();
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*/,
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
428 // -------------------------------------------------------------------------
429 void OCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
,const Any
& /*rValue*/) throw (Exception
)
431 // set the value to what ever is nescessary
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
:
446 // -------------------------------------------------------------------------
447 void OCommonStatement::getFastPropertyValue(Any
& /*rValue*/,sal_Int32 nHandle
) const
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
:
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()
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()
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
] );
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
] );
513 // -----------------------------------------------------------------------------
515 void OCommonStatement::analyseSQL()
517 const OSQLParseNode
* pOrderbyClause
= m_pSQLIterator
->getOrderTree();
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
);
552 throw SQLException();
555 Reference
<XColumnLocate
> xColLocate(m_xColNames
,UNO_QUERY
);
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 // -----------------------------------------------------------------------------