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_connectivity.hxx"
26 
27 #include "connectivity/sqlerror.hxx"
28 
29 /** === begin UNO includes === **/
30 #include <com/sun/star/sdbc/SQLException.hpp>
31 /** === end UNO includes === **/
32 
33 #include <comphelper/officeresourcebundle.hxx>
34 #include <cppuhelper/exc_hlp.hxx>
35 #include <rtl/ustrbuf.hxx>
36 
37 #include <string.h>
38 
39 //........................................................................
40 namespace connectivity
41 {
42 //........................................................................
43 
44 	/** === begin UNO using === **/
45 	using ::com::sun::star::uno::Reference;
46 	using ::com::sun::star::uno::UNO_QUERY;
47 	using ::com::sun::star::uno::UNO_QUERY_THROW;
48 	using ::com::sun::star::uno::Exception;
49 	using ::com::sun::star::uno::RuntimeException;
50 	using ::com::sun::star::uno::Any;
51 	using ::com::sun::star::uno::makeAny;
52     using ::com::sun::star::uno::XInterface;
53     using ::com::sun::star::sdbc::SQLException;
54     using ::com::sun::star::uno::Type;
55 	/** === end UNO using === **/
56 
57     //using SQLError::ParamValue; // GCC (unxlngi6) does not like this
58     namespace
59     {
60         typedef SQLError::ParamValue ParamValue;
61     }
62 
63 	//====================================================================
64 	//= SQLError_Impl - declaration
65 	//====================================================================
66     class SQLError_Impl
67     {
68     public:
69         SQLError_Impl( const ::comphelper::ComponentContext& _rContext );
70         ~SQLError_Impl();
71 
72         // versions of the public SQLError methods which are just delegated to this impl-class
73         static const ::rtl::OUString& getMessagePrefix();
74         ::rtl::OUString     getErrorMessage( const ErrorCondition _eCondition, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 );
75         ::rtl::OUString     getSQLState( const ErrorCondition _eCondition );
76         static ErrorCode    getErrorCode( const ErrorCondition _eCondition );
77         void                raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 );
78         void                raiseException( const ErrorCondition _eCondition, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 );
79         void                raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const Type& _rExceptionType, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 );
80         SQLException        getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 );
81 
82     private:
83         /// returns the basic error message associated with the given error condition, without any parameter replacements
84         ::rtl::OUString
85                 impl_getErrorMessage( const ErrorCondition& _eCondition );
86 
87         /// returns the SQLState associated with the given error condition
88         ::rtl::OUString
89                 impl_getSQLState( const ErrorCondition& _eCondition );
90 
91         /// returns an SQLException describing the given error condition
92         SQLException
93                 impl_buildSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
94                     const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 );
95 
96         /// initializes our resource bundle
97         bool    impl_initResources();
98 
99     private:
100         ::osl::Mutex                                            m_aMutex;
101         ::comphelper::ComponentContext                          m_aContext;
102         ::std::auto_ptr< ::comphelper::OfficeResourceBundle >   m_pResources;
103         bool                                                    m_bAttemptedInit;
104     };
105 
106 	//====================================================================
107 	//= SQLError_Impl - implementation
108 	//====================================================================
109 	//--------------------------------------------------------------------
SQLError_Impl(const::comphelper::ComponentContext & _rContext)110     SQLError_Impl::SQLError_Impl( const ::comphelper::ComponentContext& _rContext )
111         :m_aContext( _rContext )
112         ,m_pResources( )
113         ,m_bAttemptedInit( false )
114     {
115     }
116 
117 	//--------------------------------------------------------------------
~SQLError_Impl()118     SQLError_Impl::~SQLError_Impl()
119     {
120     }
121 
122 	//--------------------------------------------------------------------
getMessagePrefix()123     const ::rtl::OUString& SQLError_Impl::getMessagePrefix()
124     {
125         static ::rtl::OUString s_sMessagePrefix( RTL_CONSTASCII_USTRINGPARAM( "[OOoBase]" ) );
126         return s_sMessagePrefix;
127     }
128 
129 	//--------------------------------------------------------------------
130     namespace
131     {
132 	    //................................................................
133         /** substitutes a given placeholder in the given message with the given value
134         */
lcl_substitutePlaceholder(::rtl::OUString & _rMessage,const sal_Char * _pPlaceholder,ParamValue _rParamValue)135         void    lcl_substitutePlaceholder( ::rtl::OUString& _rMessage, const sal_Char* _pPlaceholder, ParamValue _rParamValue )
136         {
137             size_t nPlaceholderLen( strlen( _pPlaceholder ) );
138             sal_Int32 nIndex = _rMessage.indexOfAsciiL( _pPlaceholder, nPlaceholderLen );
139 
140             bool bHasPlaceholder = ( nIndex != -1 );
141             bool bWantsPlaceholder = _rParamValue.is();
142             OSL_ENSURE( bHasPlaceholder == bWantsPlaceholder, "lcl_substitutePlaceholder: placeholder where none is expected, or no placeholder where one is needed!" );
143 
144             if ( bHasPlaceholder && bWantsPlaceholder )
145                 _rMessage = _rMessage.replaceAt( nIndex, nPlaceholderLen, *_rParamValue );
146         }
147 
148         //................................................................
lcl_getResourceID(const ErrorCondition _eCondition,bool _bSQLState)149         sal_Int32   lcl_getResourceID( const ErrorCondition _eCondition, bool _bSQLState )
150         {
151             return  256
152                 +   2 * ::sal::static_int_cast< sal_Int32, ErrorCondition >( _eCondition )
153                 +   ( _bSQLState ? 1 : 0 );
154         }
155     }
156 
157 	//--------------------------------------------------------------------
getErrorMessage(const ErrorCondition _eCondition,const ParamValue & _rParamValue1,const ParamValue & _rParamValue2,const ParamValue & _rParamValue3)158     ::rtl::OUString SQLError_Impl::getErrorMessage( const ErrorCondition _eCondition, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 )
159     {
160         ::rtl::OUString sErrorMessage( impl_getErrorMessage( _eCondition ) );
161 
162         lcl_substitutePlaceholder( sErrorMessage, "$1$", _rParamValue1 );
163         lcl_substitutePlaceholder( sErrorMessage, "$2$", _rParamValue2 );
164         lcl_substitutePlaceholder( sErrorMessage, "$3$", _rParamValue3 );
165 
166         return sErrorMessage;
167     }
168 
169 	//--------------------------------------------------------------------
getSQLState(const ErrorCondition _eCondition)170     ::rtl::OUString SQLError_Impl::getSQLState( const ErrorCondition _eCondition )
171     {
172         return impl_getSQLState( _eCondition );
173     }
174 
175 	//--------------------------------------------------------------------
getErrorCode(const ErrorCondition _eCondition)176     ErrorCode SQLError_Impl::getErrorCode( const ErrorCondition _eCondition )
177     {
178         return 0 - ::sal::static_int_cast< ErrorCode, ErrorCondition >( _eCondition );
179     }
180 
181 	//--------------------------------------------------------------------
raiseException(const ErrorCondition _eCondition,const Reference<XInterface> & _rxContext,const ParamValue & _rParamValue1,const ParamValue & _rParamValue2,const ParamValue & _rParamValue3)182     void SQLError_Impl::raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 )
183     {
184         raiseTypedException(
185             _eCondition,
186             _rxContext,
187             ::cppu::UnoType< SQLException >::get(),
188             _rParamValue1,
189             _rParamValue2,
190             _rParamValue3
191         );
192     }
193 
194 	//--------------------------------------------------------------------
raiseException(const ErrorCondition _eCondition,const ParamValue & _rParamValue1,const ParamValue & _rParamValue2,const ParamValue & _rParamValue3)195     void SQLError_Impl::raiseException( const ErrorCondition _eCondition, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 )
196     {
197         raiseTypedException(
198             _eCondition,
199             NULL,
200             ::cppu::UnoType< SQLException >::get(),
201             _rParamValue1,
202             _rParamValue2,
203             _rParamValue3
204         );
205     }
206 
207 	//--------------------------------------------------------------------
raiseTypedException(const ErrorCondition _eCondition,const Reference<XInterface> & _rxContext,const Type & _rExceptionType,const ParamValue & _rParamValue1,const ParamValue & _rParamValue2,const ParamValue & _rParamValue3)208     void SQLError_Impl::raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
209         const Type& _rExceptionType, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 )
210     {
211         if ( !::cppu::UnoType< SQLException >::get().isAssignableFrom( _rExceptionType ) )
212             throw ::std::bad_cast();
213 
214         // default-construct an exception of the desired type
215         Any aException( NULL, _rExceptionType );
216 
217         // fill it
218         SQLException* pException = static_cast< SQLException* >( aException.pData );
219         *pException = impl_buildSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
220 
221         // throw it
222         ::cppu::throwException( aException );
223     }
224 
225 	//--------------------------------------------------------------------
getSQLException(const ErrorCondition _eCondition,const Reference<XInterface> & _rxContext,const ParamValue & _rParamValue1,const ParamValue & _rParamValue2,const ParamValue & _rParamValue3)226     SQLException SQLError_Impl::getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
227         const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 )
228     {
229         return impl_buildSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
230     }
231 
232 	//--------------------------------------------------------------------
impl_buildSQLException(const ErrorCondition _eCondition,const Reference<XInterface> & _rxContext,const ParamValue & _rParamValue1,const ParamValue & _rParamValue2,const ParamValue & _rParamValue3)233     SQLException SQLError_Impl::impl_buildSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
234         const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 )
235     {
236         return SQLException(
237             getErrorMessage( _eCondition, _rParamValue1, _rParamValue2, _rParamValue3 ),
238             _rxContext,
239             getSQLState( _eCondition ),
240             getErrorCode( _eCondition ),
241             Any()
242         );
243     }
244 
245 	//--------------------------------------------------------------------
impl_getErrorMessage(const ErrorCondition & _eCondition)246     ::rtl::OUString SQLError_Impl::impl_getErrorMessage( const ErrorCondition& _eCondition )
247     {
248         ::rtl::OUStringBuffer aMessage;
249 
250         if ( impl_initResources() )
251         {
252             ::rtl::OUString sResMessage( m_pResources->loadString( lcl_getResourceID( _eCondition, false ) ) );
253             OSL_ENSURE( sResMessage.getLength(), "SQLError_Impl::impl_getErrorMessage: illegal error condition, or invalid resource!" );
254             aMessage.append( getMessagePrefix() ).appendAscii( " " ).append( sResMessage );
255         }
256 
257         return aMessage.makeStringAndClear();
258     }
259 
260 	//--------------------------------------------------------------------
impl_getSQLState(const ErrorCondition & _eCondition)261     ::rtl::OUString SQLError_Impl::impl_getSQLState( const ErrorCondition& _eCondition )
262     {
263         ::rtl::OUString sState;
264 
265         if ( impl_initResources() )
266         {
267             sal_Int32 nResourceId( lcl_getResourceID( _eCondition, true ) );
268             if ( m_pResources->hasString( nResourceId ) )
269                 sState = m_pResources->loadString( nResourceId );
270         }
271 
272         if ( !sState.getLength() )
273             sState = ::rtl::OUString::intern( RTL_CONSTASCII_USTRINGPARAM( "S1000" ) );
274 
275         return sState;
276     }
277 
278 	//--------------------------------------------------------------------
impl_initResources()279     bool SQLError_Impl::impl_initResources()
280     {
281         if ( m_pResources.get() )
282             return true;
283         if ( m_bAttemptedInit )
284             return false;
285 
286         ::osl::MutexGuard aGuard( m_aMutex );
287         m_bAttemptedInit = true;
288 
289         m_pResources.reset( new ::comphelper::OfficeResourceBundle( m_aContext.getUNOContext(), "sdberr" ) );
290         return m_pResources.get() != NULL;
291     }
292 
293 	//====================================================================
294 	//= SQLError
295 	//====================================================================
296 	//--------------------------------------------------------------------
SQLError(const::comphelper::ComponentContext & _rContext)297     SQLError::SQLError( const ::comphelper::ComponentContext& _rContext )
298         :m_pImpl( new SQLError_Impl( _rContext ) )
299     {
300     }
301 
302 	//--------------------------------------------------------------------
~SQLError()303     SQLError::~SQLError()
304     {
305     }
306 
307 	//--------------------------------------------------------------------
getMessagePrefix()308     const ::rtl::OUString& SQLError::getMessagePrefix()
309     {
310         return SQLError_Impl::getMessagePrefix();
311     }
312 
313 	//--------------------------------------------------------------------
getErrorMessage(const ErrorCondition _eCondition,const ParamValue & _rParamValue1,const ParamValue & _rParamValue2,const ParamValue & _rParamValue3) const314     ::rtl::OUString SQLError::getErrorMessage( const ErrorCondition _eCondition, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 ) const
315     {
316         return m_pImpl->getErrorMessage( _eCondition, _rParamValue1, _rParamValue2, _rParamValue3 );
317     }
318 
319 	//--------------------------------------------------------------------
getSQLState(const ErrorCondition _eCondition) const320     ::rtl::OUString SQLError::getSQLState( const ErrorCondition _eCondition ) const
321     {
322         return m_pImpl->getSQLState( _eCondition );
323     }
324 
325 	//--------------------------------------------------------------------
getErrorCode(const ErrorCondition _eCondition)326     ErrorCode SQLError::getErrorCode( const ErrorCondition _eCondition )
327     {
328         return SQLError_Impl::getErrorCode( _eCondition );
329     }
330 
331 	//--------------------------------------------------------------------
raiseException(const ErrorCondition _eCondition,const Reference<XInterface> & _rxContext,const ParamValue & _rParamValue1,const ParamValue & _rParamValue2,const ParamValue & _rParamValue3) const332     void SQLError::raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 ) const
333     {
334         m_pImpl->raiseException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
335     }
336 
337 	//--------------------------------------------------------------------
raiseException(const ErrorCondition _eCondition,const ParamValue & _rParamValue1,const ParamValue & _rParamValue2,const ParamValue & _rParamValue3) const338     void SQLError::raiseException( const ErrorCondition _eCondition, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 ) const
339     {
340         m_pImpl->raiseException( _eCondition, _rParamValue1, _rParamValue2, _rParamValue3 );
341     }
342 
343 	//--------------------------------------------------------------------
raiseTypedException(const ErrorCondition _eCondition,const Reference<XInterface> & _rxContext,const Type & _rExceptionType,const ParamValue & _rParamValue1,const ParamValue & _rParamValue2,const ParamValue & _rParamValue3) const344     void SQLError::raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
345         const Type& _rExceptionType, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 ) const
346     {
347         m_pImpl->raiseTypedException( _eCondition, _rxContext, _rExceptionType, _rParamValue1, _rParamValue2, _rParamValue3 );
348     }
349 
350 	//--------------------------------------------------------------------
getSQLException(const ErrorCondition _eCondition,const Reference<XInterface> & _rxContext,const ParamValue & _rParamValue1,const ParamValue & _rParamValue2,const ParamValue & _rParamValue3) const351     SQLException SQLError::getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
352         const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 ) const
353     {
354         return m_pImpl->getSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
355     }
356 
357 //........................................................................
358 } // namespace connectivity
359 //........................................................................
360