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 "java/sql/Connection.hxx"
28 #include "java/lang/Class.hxx"
29 #include "java/tools.hxx"
30 #include "java/ContextClassLoader.hxx"
31 #include "java/sql/DatabaseMetaData.hxx"
32 #include "java/sql/JStatement.hxx"
33 #include "java/sql/Driver.hxx"
34 #include "java/sql/PreparedStatement.hxx"
35 #include "java/sql/CallableStatement.hxx"
36 #include "java/sql/SQLWarning.hxx"
37 #include <com/sun/star/lang/DisposedException.hpp>
38 #include <com/sun/star/sdbc/SQLWarning.hpp>
39 #include <com/sun/star/sdbc/SQLWarning.hpp>
40 #include <com/sun/star/beans/NamedValue.hpp>
41 #include "connectivity/sqlparse.hxx"
42 #include "connectivity/dbexception.hxx"
43 #include "java/util/Property.hxx"
44 #include "java/LocalRef.hxx"
45 #include "resource/jdbc_log.hrc"
46 #include "com/sun/star/uno/XComponentContext.hpp"
47 #include "jvmaccess/classpath.hxx"
48 #include <comphelper/namedvaluecollection.hxx>
49 #include <rtl/ustrbuf.hxx>
50 #include <jni.h>
51 #include "resource/common_res.hrc"
52 #include <unotools/confignode.hxx>
53 
54 #include <list>
55 #include <memory>
56 
57 using namespace connectivity;
58 using namespace connectivity::jdbc;
59 using namespace ::com::sun::star::uno;
60 using namespace ::com::sun::star::beans;
61 using namespace ::com::sun::star::sdbc;
62 using namespace ::com::sun::star::container;
63 using namespace ::com::sun::star::lang;
64 
65 namespace {
66 
67 struct ClassMapEntry {
ClassMapEntry__anon8cc39e270111::ClassMapEntry68     ClassMapEntry(
69         rtl::OUString const & theClassPath, rtl::OUString const & theClassName):
70         classPath(theClassPath), className(theClassName), classLoader(NULL),
71         classObject(NULL) {}
72 
73     rtl::OUString classPath;
74     rtl::OUString className;
75     jweak classLoader;
76     jweak classObject;
77 };
78 
79 typedef std::list< ClassMapEntry > ClassMap;
80 
81 struct ClassMapData {
82     osl::Mutex mutex;
83 
84     ClassMap map;
85 };
86 
87 struct ClassMapDataInit {
operator ()__anon8cc39e270111::ClassMapDataInit88     ClassMapData * operator()() {
89         static ClassMapData instance;
90         return &instance;
91     }
92 };
93 
94 template < typename T >
getLocalFromWeakRef(jweak & _weak,LocalRef<T> & _inout_local)95 bool getLocalFromWeakRef( jweak& _weak, LocalRef< T >& _inout_local )
96 {
97     _inout_local.set( static_cast< T >( _inout_local.env().NewLocalRef( _weak ) ) );
98 
99     if ( !_inout_local.is() )
100     {
101         if ( _inout_local.env().ExceptionCheck())
102         {
103             return false;
104         }
105         else if ( _weak != NULL )
106         {
107             _inout_local.env().DeleteWeakGlobalRef( _weak );
108             _weak = NULL;
109         }
110     }
111     return true;
112 }
113 
114 // Load a class.  A map from pairs of (classPath, name) to pairs of weak Java
115 // references to (ClassLoader, Class) is maintained, so that a class is only
116 // loaded once.
117 //
118 // It may happen that the weak reference to the ClassLoader becomes null while
119 // the reference to the Class remains non-null (in case the Class was actually
120 // loaded by some parent of the ClassLoader), in which case the ClassLoader is
121 // resurrected (which cannot cause any classes to be loaded multiple times, as
122 // the ClassLoader is no longer reachable, so no classes it has ever loaded are
123 // still reachable).
124 //
125 // Similarly, it may happen that the weak reference to the Class becomes null
126 // while the reference to the ClassLoader remains non-null, in which case the
127 // Class is simply re-loaded.
128 //
129 // This code is close to the implementation of jvmaccess::ClassPath::loadClass
130 // in jvmaccess/classpath.hxx, but not close enough to avoid the duplication.
131 //
132 // If false is returned, a (still pending) JNI exception occurred.
loadClass(Reference<XComponentContext> const & context,JNIEnv & environment,rtl::OUString const & classPath,rtl::OUString const & name,LocalRef<jobject> * classLoaderPtr,LocalRef<jclass> * classPtr)133 bool loadClass(
134     Reference< XComponentContext > const & context, JNIEnv& environment,
135     rtl::OUString const & classPath, rtl::OUString const & name,
136     LocalRef< jobject > * classLoaderPtr, LocalRef< jclass > * classPtr)
137 {
138     OSL_ASSERT(classLoaderPtr != NULL);
139     // For any jweak entries still present in the map upon destruction,
140     // DeleteWeakGlobalRef is not called (which is a leak):
141     ClassMapData * d =
142         rtl_Instance< ClassMapData, ClassMapDataInit, osl::MutexGuard,
143         osl::GetGlobalMutex >::create(
144             ClassMapDataInit(), osl::GetGlobalMutex());
145     osl::MutexGuard g(d->mutex);
146     ClassMap::iterator i(d->map.begin());
147     LocalRef< jobject > cloader(environment);
148     LocalRef< jclass > cl(environment);
149     // Prune dangling weak references from the list while searching for a match,
150     // so that the list cannot grow unbounded:
151     for (; i != d->map.end();)
152     {
153         LocalRef< jobject > classLoader( environment );
154         if ( !getLocalFromWeakRef( i->classLoader, classLoader ) )
155             return false;
156 
157         LocalRef< jclass > classObject( environment );
158         if ( !getLocalFromWeakRef( i->classObject, classObject ) )
159             return false;
160 
161         if ( !classLoader.is() && !classObject.is() )
162         {
163             i = d->map.erase(i);
164         }
165         else if ( i->classPath == classPath && i->className == name )
166         {
167             cloader.set( classLoader.release() );
168             cl.set( classObject.release() );
169             break;
170         }
171         else
172         {
173             ++i;
174         }
175     }
176     if ( !cloader.is() || !cl.is() )
177     {
178         if ( i == d->map.end() )
179         {
180             // Push a new ClassMapEntry (which can potentially fail) before
181             // loading the class, so that it never happens that a class is
182             // loaded but not added to the map (which could have effects on the
183             // JVM that are not easily undone).  If the pushed ClassMapEntry is
184             // not used after all (return false, etc.) it will be pruned on next
185             // call because its classLoader/classObject are null:
186             d->map.push_front( ClassMapEntry( classPath, name ) );
187             i = d->map.begin();
188         }
189 
190         LocalRef< jclass > clClass( environment );
191         clClass.set( environment.FindClass( "java/net/URLClassLoader" ) );
192         if ( !clClass.is() )
193             return false;
194 
195         jweak wcloader = NULL;
196         if (!cloader.is())
197         {
198             jmethodID ctorLoader( environment.GetMethodID( clClass.get(), "<init>", "([Ljava/net/URL;)V" ) );
199             if (ctorLoader == NULL)
200                 return false;
201 
202             LocalRef< jobjectArray > arr( environment );
203             arr.set( jvmaccess::ClassPath::translateToUrls( context, &environment, classPath ) );
204             if ( !arr.is() )
205                 return false;
206 
207             jvalue arg;
208             arg.l = arr.get();
209             cloader.set( environment.NewObjectA( clClass.get(), ctorLoader, &arg ) );
210             if ( !cloader.is() )
211                 return false;
212 
213             wcloader = environment.NewWeakGlobalRef( cloader.get() );
214             if ( wcloader == NULL )
215                 return false;
216         }
217 
218         jweak wcl = NULL;
219         if ( !cl.is() )
220         {
221             jmethodID methLoadClass( environment.GetMethodID( clClass.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;" ) );
222             if ( methLoadClass == NULL )
223                 return false;
224 
225             LocalRef< jstring > str( environment );
226             str.set( convertwchar_tToJavaString( &environment, name ) );
227             if ( !str.is() )
228                 return false;
229 
230             jvalue arg;
231             arg.l = str.get();
232             cl.set( static_cast< jclass >( environment.CallObjectMethodA( cloader.get(), methLoadClass, &arg ) ) );
233             if ( !cl.is() )
234                 return false;
235 
236             wcl = environment.NewWeakGlobalRef( cl.get() );
237             if ( wcl == NULL )
238                 return false;
239         }
240 
241         if ( wcloader != NULL)
242         {
243             i->classLoader = wcloader;
244         }
245         if ( wcl != NULL )
246         {
247             i->classObject = wcl;
248         }
249     }
250 
251     classLoaderPtr->set( cloader.release() );
252     classPtr->set( cl.release() );
253     return true;
254 }
255 
256 }
257 
258 //------------------------------------------------------------------------------
259 IMPLEMENT_SERVICE_INFO(java_sql_Connection,"com.sun.star.sdbcx.JConnection","com.sun.star.sdbc.Connection");
260 //------------------------------------------------------------------------------
261 //**************************************************************
262 //************ Class: java.sql.Connection
263 //**************************************************************
264 jclass java_sql_Connection::theClass = 0;
265 
java_sql_Connection(const java_sql_Driver & _rDriver)266 java_sql_Connection::java_sql_Connection( const java_sql_Driver& _rDriver )
267     :java_lang_Object( _rDriver.getContext().getLegacyServiceFactory() )
268     ,OSubComponent<java_sql_Connection, java_sql_Connection_BASE>((::cppu::OWeakObject*)(&_rDriver), this)
269     ,m_pDriver( &_rDriver )
270     ,m_pDriverobject(NULL)
271     ,m_pDriverClassLoader()
272     ,m_Driver_theClass(NULL)
273     ,m_aLogger( _rDriver.getLogger() )
274     ,m_bParameterSubstitution(sal_False)
275     ,m_bIgnoreDriverPrivileges(sal_True)
276     ,m_bIgnoreCurrency(sal_False)
277 {
278 }
279 // -----------------------------------------------------------------------------
~java_sql_Connection()280 java_sql_Connection::~java_sql_Connection()
281 {
282 	::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM();
283 	if ( xTest.is() )
284 	{
285 		SDBThreadAttach t;
286         clearObject(*t.pEnv);
287 
288 		{
289 			if ( m_pDriverobject )
290 				t.pEnv->DeleteGlobalRef( m_pDriverobject );
291 			m_pDriverobject = NULL;
292 			if ( m_Driver_theClass )
293 				t.pEnv->DeleteGlobalRef( m_Driver_theClass );
294 			m_Driver_theClass = NULL;
295 		}
296 		t.releaseRef();
297 	}
298 }
299 //-----------------------------------------------------------------------------
release()300 void SAL_CALL java_sql_Connection::release() throw()
301 {
302 	relase_ChildImpl();
303 }
304 //------------------------------------------------------------------------------
disposing()305 void java_sql_Connection::disposing()
306 {
307 	::osl::MutexGuard aGuard(m_aMutex);
308 
309     m_aLogger.log( LogLevel::INFO, STR_LOG_SHUTDOWN_CONNECTION );
310 
311     dispose_ChildImpl();
312 	java_sql_Connection_BASE::disposing();
313 
314 	if ( object )
315 	{
316         static jmethodID mID(NULL);
317         callVoidMethod("close",mID);
318 	}
319 }
320 // -------------------------------------------------------------------------
getMyClass() const321 jclass java_sql_Connection::getMyClass() const
322 {
323 	// die Klasse muss nur einmal geholt werden, daher statisch
324 	if( !theClass )
325         theClass = findMyClass("java/sql/Connection");
326 	return theClass;
327 }
328 
329 // -------------------------------------------------------------------------
getCatalog()330 ::rtl::OUString SAL_CALL java_sql_Connection::getCatalog(  ) throw(SQLException, RuntimeException)
331 {
332 	::osl::MutexGuard aGuard( m_aMutex );
333 	checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
334 
335     static jmethodID mID(NULL);
336     return callStringMethod("getCatalog",mID);
337 }
338 // -------------------------------------------------------------------------
getMetaData()339 Reference< XDatabaseMetaData > SAL_CALL java_sql_Connection::getMetaData(  ) throw(SQLException, RuntimeException)
340 {
341 	::osl::MutexGuard aGuard( m_aMutex );
342 	checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
343 
344 
345 	Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
346 	if(!xMetaData.is())
347 	{
348         SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
349         static jmethodID mID(NULL);
350         jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/DatabaseMetaData;", mID);
351 		if(out)
352 		{
353 			xMetaData = new java_sql_DatabaseMetaData( t.pEnv, out, *this );
354 			m_xMetaData = xMetaData;
355 		}
356 	}
357 
358 	return xMetaData;
359 }
360 // -------------------------------------------------------------------------
close()361 void SAL_CALL java_sql_Connection::close(  ) throw(SQLException, RuntimeException)
362 {
363 	dispose();
364 }
365 // -------------------------------------------------------------------------
commit()366 void SAL_CALL java_sql_Connection::commit(  ) throw(SQLException, RuntimeException)
367 {
368     static jmethodID mID(NULL);
369     callVoidMethod("commit",mID);
370 }
371 // -------------------------------------------------------------------------
isClosed()372 sal_Bool SAL_CALL java_sql_Connection::isClosed(  ) throw(SQLException, RuntimeException)
373 {
374 	::osl::MutexGuard aGuard( m_aMutex );
375 
376     static jmethodID mID(NULL);
377     return callBooleanMethod( "isClosed", mID ) && java_sql_Connection_BASE::rBHelper.bDisposed;
378 }
379 // -------------------------------------------------------------------------
isReadOnly()380 sal_Bool SAL_CALL java_sql_Connection::isReadOnly(  ) throw(SQLException, RuntimeException)
381 {
382 	::osl::MutexGuard aGuard( m_aMutex );
383 	checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
384     static jmethodID mID(NULL);
385     return callBooleanMethod( "isReadOnly", mID );
386 }
387 // -------------------------------------------------------------------------
setCatalog(const::rtl::OUString & catalog)388 void SAL_CALL java_sql_Connection::setCatalog( const ::rtl::OUString& catalog ) throw(SQLException, RuntimeException)
389 {
390     static jmethodID mID(NULL);
391     callVoidMethodWithStringArg("setCatalog",mID,catalog);
392 }
393 // -------------------------------------------------------------------------
rollback()394 void SAL_CALL java_sql_Connection::rollback(  ) throw(SQLException, RuntimeException)
395 {
396     static jmethodID mID(NULL);
397     callVoidMethod("rollback",mID);
398 }
399 // -------------------------------------------------------------------------
getAutoCommit()400 sal_Bool SAL_CALL java_sql_Connection::getAutoCommit(  ) throw(SQLException, RuntimeException)
401 {
402     static jmethodID mID(NULL);
403     return callBooleanMethod( "getAutoCommit", mID );
404 }
405 // -------------------------------------------------------------------------
setReadOnly(sal_Bool readOnly)406 void SAL_CALL java_sql_Connection::setReadOnly( sal_Bool readOnly ) throw(SQLException, RuntimeException)
407 {
408     static jmethodID mID(NULL);
409     callVoidMethodWithBoolArg("setReadOnly",mID,readOnly);
410 }
411 // -------------------------------------------------------------------------
setAutoCommit(sal_Bool autoCommit)412 void SAL_CALL java_sql_Connection::setAutoCommit( sal_Bool autoCommit ) throw(SQLException, RuntimeException)
413 {
414     static jmethodID mID(NULL);
415     callVoidMethodWithBoolArg("setAutoCommit",mID,autoCommit);
416 }
417 // -------------------------------------------------------------------------
getTypeMap()418 Reference< ::com::sun::star::container::XNameAccess > SAL_CALL java_sql_Connection::getTypeMap(  ) throw(SQLException, RuntimeException)
419 {
420 	::osl::MutexGuard aGuard( m_aMutex );
421 	checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
422 
423     SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
424     static jmethodID mID(NULL);
425     /*jobject out = */callObjectMethod(t.pEnv,"getTypeMap","()Ljava/util/Map;", mID);
426 	// ACHTUNG: der Aufrufer wird Eigentuemer des zurueckgelieferten Zeigers !!!
427 	return 0;// ? 0 : Map2XNameAccess( t.pEnv, out );
428 }
429 // -------------------------------------------------------------------------
setTypeMap(const Reference<::com::sun::star::container::XNameAccess> &)430 void SAL_CALL java_sql_Connection::setTypeMap( const Reference< ::com::sun::star::container::XNameAccess >& /*typeMap*/ ) throw(SQLException, RuntimeException)
431 {
432 	::osl::MutexGuard aGuard( m_aMutex );
433 	checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
434 
435     ::dbtools::throwFeatureNotImplementedException( "XConnection::setTypeMap", *this );
436 }
437 
438 // -------------------------------------------------------------------------
getTransactionIsolation()439 sal_Int32 SAL_CALL java_sql_Connection::getTransactionIsolation(  ) throw(SQLException, RuntimeException)
440 {
441 	::osl::MutexGuard aGuard( m_aMutex );
442 	checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
443 
444     static jmethodID mID(NULL);
445 	return callIntMethod("getTransactionIsolation",mID);
446 }
447 // -------------------------------------------------------------------------
setTransactionIsolation(sal_Int32 level)448 void SAL_CALL java_sql_Connection::setTransactionIsolation( sal_Int32 level ) throw(SQLException, RuntimeException)
449 {
450 	::osl::MutexGuard aGuard( m_aMutex );
451 	checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
452 
453     static jmethodID mID(NULL);
454     callVoidMethodWithIntArg("setTransactionIsolation",mID,level);
455 }
456 // -------------------------------------------------------------------------
createStatement()457 Reference< XStatement > SAL_CALL java_sql_Connection::createStatement(  ) throw(SQLException, RuntimeException)
458 {
459 	::osl::MutexGuard aGuard( m_aMutex );
460 	checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
461     m_aLogger.log( LogLevel::FINE, STR_LOG_CREATE_STATEMENT );
462 
463 	SDBThreadAttach t;
464     java_sql_Statement* pStatement = new java_sql_Statement( t.pEnv, *this );
465 	Reference< XStatement > xStmt = pStatement;
466 	m_aStatements.push_back( WeakReferenceHelper( xStmt ) );
467 
468     m_aLogger.log( LogLevel::FINE, STR_LOG_CREATED_STATEMENT_ID, pStatement->getStatementObjectID() );
469     return xStmt;
470 }
471 // -----------------------------------------------------------------------------
transFormPreparedStatement(const::rtl::OUString & _sSQL)472 ::rtl::OUString java_sql_Connection::transFormPreparedStatement(const ::rtl::OUString& _sSQL)
473 {
474 	::rtl::OUString sSqlStatement = _sSQL;
475 	if ( m_bParameterSubstitution )
476 	{
477 		try
478 		{
479 			OSQLParser aParser( m_pDriver->getContext().getLegacyServiceFactory() );
480 			::rtl::OUString sErrorMessage;
481 			::rtl::OUString sNewSql;
482 			OSQLParseNode* pNode = aParser.parseTree(sErrorMessage,_sSQL);
483 			if(pNode)
484 			{	// special handling for parameters
485 				OSQLParseNode::substituteParameterNames(pNode);
486 				pNode->parseNodeToStr( sNewSql, this );
487 				delete pNode;
488 				sSqlStatement = sNewSql;
489 			}
490 		}
491 		catch(const Exception&)
492 		{
493 		}
494 	}
495 	return sSqlStatement;
496 }
497 // -------------------------------------------------------------------------
prepareStatement(const::rtl::OUString & sql)498 Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
499 {
500 	::osl::MutexGuard aGuard( m_aMutex );
501 	checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
502     m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_STATEMENT, sql );
503 
504     SDBThreadAttach t;
505 	::rtl::OUString sSqlStatement = sql;
506 	sSqlStatement = transFormPreparedStatement( sSqlStatement );
507 
508     java_sql_PreparedStatement* pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sSqlStatement );
509 	Reference< XPreparedStatement > xReturn( pStatement );
510 	m_aStatements.push_back(WeakReferenceHelper(xReturn));
511 
512     m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_STATEMENT_ID, pStatement->getStatementObjectID() );
513 	return xReturn;
514 }
515 // -------------------------------------------------------------------------
prepareCall(const::rtl::OUString & sql)516 Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareCall( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
517 {
518 	::osl::MutexGuard aGuard( m_aMutex );
519 	checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
520     m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_CALL, sql );
521 
522 	SDBThreadAttach t;
523 	::rtl::OUString sSqlStatement = sql;
524 	sSqlStatement = transFormPreparedStatement( sSqlStatement );
525 
526     java_sql_CallableStatement* pStatement = new java_sql_CallableStatement( t.pEnv, *this, sSqlStatement );
527 	Reference< XPreparedStatement > xStmt( pStatement );
528 	m_aStatements.push_back(WeakReferenceHelper(xStmt));
529 
530     m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_CALL_ID, pStatement->getStatementObjectID() );
531     return xStmt;
532 }
533 // -------------------------------------------------------------------------
nativeSQL(const::rtl::OUString & sql)534 ::rtl::OUString SAL_CALL java_sql_Connection::nativeSQL( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
535 {
536 	::osl::MutexGuard aGuard( m_aMutex );
537 	checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
538 
539 	::rtl::OUString aStr;
540     SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
541 	{
542 
543 		// temporaere Variable initialisieren
544 		static const char * cSignature = "(Ljava/lang/String;)Ljava/lang/String;";
545 		static const char * cMethodName = "nativeSQL";
546 		// Java-Call absetzen
547 		static jmethodID mID(NULL);
548         obtainMethodId(t.pEnv, cMethodName,cSignature, mID);
549 		// Parameter konvertieren
550 		jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,sql));
551 
552 		jobject out = t.pEnv->CallObjectMethod( object, mID, str.get() );
553 		aStr = JavaString2String(t.pEnv, (jstring)out );
554 		ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
555 	} //t.pEnv
556 
557     m_aLogger.log( LogLevel::FINER, STR_LOG_NATIVE_SQL, sql, aStr );
558 
559 	return aStr;
560 }
561 // -------------------------------------------------------------------------
clearWarnings()562 void SAL_CALL java_sql_Connection::clearWarnings(  ) throw(SQLException, RuntimeException)
563 {
564     static jmethodID mID(NULL);
565     callVoidMethod("clearWarnings",mID);
566 }
567 // -------------------------------------------------------------------------
getWarnings()568 Any SAL_CALL java_sql_Connection::getWarnings(  ) throw(SQLException, RuntimeException)
569 {
570 	::osl::MutexGuard aGuard( m_aMutex );
571 	checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
572 
573 	SDBThreadAttach t;
574     static jmethodID mID(NULL);
575     jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID);
576 	// ACHTUNG: der Aufrufer wird Eigentuemer des zurueckgelieferten Zeigers !!!
577 	if( out )
578 	{
579 		java_sql_SQLWarning_BASE		warn_base(t.pEnv, out);
580         SQLException aAsException( static_cast< starsdbc::SQLException >( java_sql_SQLWarning( warn_base, *this ) ) );
581 
582         // translate to warning
583         SQLWarning aWarning;
584         aWarning.Context = aAsException.Context;
585         aWarning.Message = aAsException.Message;
586         aWarning.SQLState = aAsException.SQLState;
587         aWarning.ErrorCode = aAsException.ErrorCode;
588         aWarning.NextException = aAsException.NextException;
589 
590 		return makeAny( aWarning );
591 	}
592 
593 	return Any();
594 }
595 
596 // -----------------------------------------------------------------------------
597 namespace
598 {
lcl_getDriverLoadErrorMessage(const::connectivity::SharedResources & _aResource,const::rtl::OUString & _rDriverClass,const::rtl::OUString & _rDriverClassPath)599     ::rtl::OUString lcl_getDriverLoadErrorMessage( const ::connectivity::SharedResources& _aResource,const ::rtl::OUString& _rDriverClass, const ::rtl::OUString& _rDriverClassPath )
600     {
601         ::rtl::OUString sError1( _aResource.getResourceStringWithSubstitution(
602                 STR_NO_CLASSNAME,
603                 "$classname$", _rDriverClass
604              ) );
605         if ( _rDriverClassPath.getLength() )
606         {
607             const ::rtl::OUString sError2( _aResource.getResourceStringWithSubstitution(
608                 STR_NO_CLASSNAME_PATH,
609                 "$classpath$", _rDriverClassPath
610              ) );
611             sError1 += sError2;
612         } // if ( _rDriverClassPath.getLength() )
613         return sError1;
614     }
615 }
616 
617 // -----------------------------------------------------------------------------
618 namespace
619 {
lcl_setSystemProperties_nothrow(const java::sql::ConnectionLog & _rLogger,JNIEnv & _rEnv,const Sequence<NamedValue> & _rSystemProperties)620     bool lcl_setSystemProperties_nothrow( const java::sql::ConnectionLog& _rLogger,
621         JNIEnv& _rEnv, const Sequence< NamedValue >& _rSystemProperties )
622     {
623         if ( _rSystemProperties.getLength() == 0 )
624             // nothing to do
625             return true;
626 
627         LocalRef< jclass > systemClass( _rEnv );
628         jmethodID nSetPropertyMethodID = 0;
629         // retrieve the java.lang.System class
630         systemClass.set( _rEnv.FindClass( "java/lang/System" ) );
631         if ( systemClass.is() )
632         {
633             nSetPropertyMethodID = _rEnv.GetStaticMethodID(
634                 systemClass.get(), "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" );
635         }
636 
637         if ( nSetPropertyMethodID == 0 )
638             return false;
639 
640         for (   const NamedValue* pSystemProp = _rSystemProperties.getConstArray();
641                 pSystemProp != _rSystemProperties.getConstArray() + _rSystemProperties.getLength();
642                 ++pSystemProp
643             )
644         {
645             ::rtl::OUString sValue;
646             OSL_VERIFY( pSystemProp->Value >>= sValue );
647 
648             _rLogger.log( LogLevel::FINER, STR_LOG_SETTING_SYSTEM_PROPERTY, pSystemProp->Name, sValue );
649 
650             LocalRef< jstring > jName( _rEnv, convertwchar_tToJavaString( &_rEnv, pSystemProp->Name ) );
651             LocalRef< jstring > jValue( _rEnv, convertwchar_tToJavaString( &_rEnv, sValue ) );
652 
653             _rEnv.CallStaticObjectMethod( systemClass.get(), nSetPropertyMethodID, jName.get(), jValue.get() );
654             LocalRef< jthrowable > throwable( _rEnv, _rEnv.ExceptionOccurred() );
655             if ( throwable.is() )
656                 return false;
657         }
658 
659         return true;
660     }
661 }
662 
663 // -----------------------------------------------------------------------------
loadDriverFromProperties(const::rtl::OUString & _sDriverClass,const::rtl::OUString & _sDriverClassPath,const Sequence<NamedValue> & _rSystemProperties)664 void java_sql_Connection::loadDriverFromProperties( const ::rtl::OUString& _sDriverClass, const ::rtl::OUString& _sDriverClassPath,
665     const Sequence< NamedValue >& _rSystemProperties )
666 {
667     // contains the statement which should be used when query for automatically generated values
668 	::rtl::OUString		sGeneratedValueStatement;
669     // set to <TRUE/> when we should allow to query for generated values
670 	sal_Bool			bAutoRetrievingEnabled = sal_False;
671 
672     // first try if the jdbc driver is alraedy registered at the driver manager
673     SDBThreadAttach t;
674 	try
675 	{
676         if ( !object )
677         {
678             if ( !lcl_setSystemProperties_nothrow( getLogger(), *t.pEnv, _rSystemProperties ) )
679                 ThrowLoggedSQLException( getLogger(), t.pEnv, *this );
680 
681             m_pDriverClassLoader.reset();
682 
683             // here I try to find the class for jdbc driver
684             java_sql_SQLException_BASE::st_getMyClass();
685             java_lang_Throwable::st_getMyClass();
686 
687             if ( !_sDriverClass.getLength() )
688             {
689                 m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_DRIVER_CLASS );
690                 ::dbtools::throwGenericSQLException(
691                     lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
692                     *this
693                 );
694             }
695             else
696             {
697                 m_aLogger.log( LogLevel::INFO, STR_LOG_LOADING_DRIVER, _sDriverClass );
698                 // the driver manager holds the class of the driver for later use
699                 ::std::auto_ptr< java_lang_Class > pDrvClass;
700                 if ( !_sDriverClassPath.getLength() )
701                 {
702 					// if forName didn't find the class it will throw an exception
703 					pDrvClass = ::std::auto_ptr< java_lang_Class >(java_lang_Class::forName(_sDriverClass));
704                 }
705                 else
706                 {
707                     LocalRef< jclass > driverClass(t.env());
708                     LocalRef< jobject > driverClassLoader(t.env());
709 
710                     loadClass(
711                         m_pDriver->getContext().getUNOContext(),
712                         t.env(), _sDriverClassPath, _sDriverClass, &driverClassLoader, &driverClass );
713 
714                     m_pDriverClassLoader.set( driverClassLoader );
715                     pDrvClass.reset( new java_lang_Class( t.pEnv, driverClass.release() ) );
716 
717                     ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
718                 }
719                 if ( pDrvClass.get() )
720                 {
721                     LocalRef< jobject > driverObject( t.env() );
722                     driverObject.set( pDrvClass->newInstanceObject() );
723                     ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
724                     m_pDriverobject = driverObject.release();
725 
726                     if( t.pEnv && m_pDriverobject )
727                         m_pDriverobject = t.pEnv->NewGlobalRef( m_pDriverobject );
728 
729                     {
730                         jclass tempClass = t.pEnv->GetObjectClass(m_pDriverobject);
731                         if ( m_pDriverobject )
732                         {
733                             m_Driver_theClass = (jclass)t.pEnv->NewGlobalRef( tempClass );
734                             t.pEnv->DeleteLocalRef( tempClass );
735                         }
736                     }
737                 }
738                 m_aLogger.log( LogLevel::INFO, STR_LOG_CONN_SUCCESS );
739             }
740         }
741 	}
742     catch( const SQLException& e )
743 	{
744 		throw SQLException(
745             lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
746             *this,
747             ::rtl::OUString(),
748             1000,
749             makeAny(e)
750         );
751 	}
752 	catch( Exception& )
753 	{
754 		::dbtools::throwGenericSQLException(
755             lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
756             *this
757         );
758 	}
759 
760 	enableAutoRetrievingEnabled( bAutoRetrievingEnabled );
761 	setAutoRetrievingStatement( sGeneratedValueStatement );
762 }
763 // -----------------------------------------------------------------------------
impl_getJavaDriverClassPath_nothrow(const::rtl::OUString & _sDriverClass)764 ::rtl::OUString java_sql_Connection::impl_getJavaDriverClassPath_nothrow(const ::rtl::OUString& _sDriverClass)
765 {
766     static const ::rtl::OUString s_sNodeName(RTL_CONSTASCII_USTRINGPARAM("org.openoffice.Office.DataAccess/JDBC/DriverClassPaths"));
767     ::utl::OConfigurationTreeRoot aNamesRoot = ::utl::OConfigurationTreeRoot::createWithServiceFactory(
768         m_pDriver->getContext().getLegacyServiceFactory(), s_sNodeName, -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
769     ::rtl::OUString sURL;
770     if ( aNamesRoot.isValid() && aNamesRoot.hasByName( _sDriverClass ) )
771     {
772         ::utl::OConfigurationNode aRegisterObj = aNamesRoot.openNode( _sDriverClass );
773         OSL_VERIFY( aRegisterObj.getNodeValue( "Path" ) >>= sURL );
774     }
775     return sURL;
776 }
777 // -----------------------------------------------------------------------------
construct(const::rtl::OUString & url,const Sequence<PropertyValue> & info)778 sal_Bool java_sql_Connection::construct(const ::rtl::OUString& url,
779 									const Sequence< PropertyValue >& info)
780 {
781 	{ // initialize the java vm
782 		::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(getORB());
783 		if ( !xTest.is() )
784             throwGenericSQLException(STR_NO_JAVA,*this);
785 	}
786 	SDBThreadAttach t;
787 	t.addRef();		 // will be released in dtor
788 	if ( !t.pEnv )
789 		throwGenericSQLException(STR_NO_JAVA,*this);
790 
791 	::rtl::OUString		sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values
792 	sal_Bool			bAutoRetrievingEnabled = sal_False; // set to <TRUE/> when we should allow to query for generated values
793     ::rtl::OUString sDriverClassPath,sDriverClass;
794     Sequence< NamedValue > aSystemProperties;
795 
796     ::comphelper::NamedValueCollection aSettings( info );
797     sDriverClass = aSettings.getOrDefault( "JavaDriverClass", sDriverClass );
798     sDriverClassPath = aSettings.getOrDefault( "JavaDriverClassPath", sDriverClassPath);
799     if ( !sDriverClassPath.getLength() )
800         sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass);
801     bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled );
802     sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement );
803     m_bParameterSubstitution = aSettings.getOrDefault( "ParameterNameSubstitution", m_bParameterSubstitution );
804     m_bIgnoreDriverPrivileges = aSettings.getOrDefault( "IgnoreDriverPrivileges", m_bIgnoreDriverPrivileges );
805     m_bIgnoreCurrency = aSettings.getOrDefault( "IgnoreCurrency", m_bIgnoreCurrency );
806     aSystemProperties = aSettings.getOrDefault( "SystemProperties", aSystemProperties );
807     m_aCatalogRestriction = aSettings.getOrDefault( "ImplicitCatalogRestriction", Any() );
808     m_aSchemaRestriction = aSettings.getOrDefault( "ImplicitSchemaRestriction", Any() );
809 
810     loadDriverFromProperties( sDriverClass, sDriverClassPath, aSystemProperties );
811 
812 	enableAutoRetrievingEnabled(bAutoRetrievingEnabled);
813 	setAutoRetrievingStatement(sGeneratedValueStatement);
814 
815 	if ( t.pEnv && m_Driver_theClass && m_pDriverobject )
816 	{
817 		// temporaere Variable initialisieren
818 		static const char * cSignature = "(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;";
819 		static const char * cMethodName = "connect";
820 		// Java-Call absetzen
821 		jmethodID mID = NULL;
822         if ( !mID  )
823             mID  = t.pEnv->GetMethodID( m_Driver_theClass, cMethodName, cSignature );
824         if ( mID )
825 		{
826 			jvalue args[2];
827 			// Parameter konvertieren
828 			args[0].l = convertwchar_tToJavaString(t.pEnv,url);
829 			java_util_Properties* pProps = createStringPropertyArray(info);
830 			args[1].l = pProps->getJavaObject();
831 
832             LocalRef< jobject > ensureDelete( t.env(), args[0].l );
833 
834             jobject out = NULL;
835             // In some cases (e.g.,
836             // connectivity/source/drivers/hsqldb/HDriver.cxx:1.24
837             // l. 249) the JavaDriverClassPath contains multiple jars,
838             // as creating the JavaDriverClass instance requires
839             // (reflective) access to those other jars.  Now, if the
840             // JavaDriverClass is actually loaded by some parent class
841             // loader (e.g., because its jar is also on the global
842             // class path), it would still not have access to the
843             // additional jars on the JavaDriverClassPath.  Hence, the
844             // JavaDriverClassPath class loader is pushed as context
845             // class loader around the JavaDriverClass instance
846             // creation:
847             // #i82222# / 2007-10-15
848             {
849                 ContextClassLoaderScope ccl( t.env(), getDriverClassLoader(), getLogger(), *this );
850                 out = t.pEnv->CallObjectMethod( m_pDriverobject, mID, args[0].l,args[1].l );
851                 delete pProps, pProps = NULL;
852                 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
853             }
854 
855             if ( !out )
856                 m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION );
857 
858 			if ( out )
859 				object = t.pEnv->NewGlobalRef( out );
860 
861             if ( object )
862                 m_aLogger.log( LogLevel::INFO, STR_LOG_GOT_JDBC_CONNECTION, url );
863 
864             m_aConnectionInfo = info;
865 		} //mID
866 	} //t.pEnv
867 	 return object != NULL;
868 }
869 // -----------------------------------------------------------------------------
870