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 #include "SConnection.hxx"
25
26 #include "SDatabaseMetaData.hxx"
27 #include "SDriver.hxx"
28 #include "SStatement.hxx"
29 #include "SPreparedStatement.hxx"
30 #include <com/sun/star/sdbc/ColumnValue.hpp>
31 #include <com/sun/star/sdbc/XRow.hpp>
32 #include <com/sun/star/sdbc/TransactionIsolation.hpp>
33 #include <com/sun/star/lang/DisposedException.hpp>
34
35 using namespace connectivity::skeleton;
36
37 //------------------------------------------------------------------------------
38 using namespace com::sun::star::uno;
39 using namespace com::sun::star::lang;
40 using namespace com::sun::star::beans;
41 using namespace com::sun::star::sdbc;
42 // --------------------------------------------------------------------------------
OConnection(SkeletonDriver * _pDriver)43 OConnection::OConnection(SkeletonDriver* _pDriver)
44 : OSubComponent<OConnection, OConnection_BASE>((::cppu::OWeakObject*)_pDriver, this),
45 OMetaConnection_BASE(m_aMutex),
46 m_pDriver(_pDriver),
47 m_bClosed(sal_False),
48 m_xMetaData(NULL),
49 m_bUseCatalog(sal_False),
50 m_bUseOldDateFormat(sal_False)
51 {
52 m_pDriver->acquire();
53 }
54 //-----------------------------------------------------------------------------
~OConnection()55 OConnection::~OConnection()
56 {
57 if(!isClosed())
58 close();
59 m_pDriver->release();
60 m_pDriver = NULL;
61 }
62 //-----------------------------------------------------------------------------
release()63 void SAL_CALL OConnection::release() throw()
64 {
65 relase_ChildImpl();
66 }
67 // -----------------------------------------------------------------------------
68 //-----------------------------------------------------------------------------
construct(const::rtl::OUString & url,const Sequence<PropertyValue> & info)69 void OConnection::construct(const ::rtl::OUString& url,const Sequence< PropertyValue >& info) throw(SQLException)
70 {
71 osl_incrementInterlockedCount( &m_refCount );
72
73 // some example code how to get the information out of the sequence
74
75 sal_Int32 nLen = url.indexOf(':');
76 nLen = url.indexOf(':',nLen+1);
77 ::rtl::OUString aDSN(RTL_CONSTASCII_USTRINGPARAM("DSN=")), aUID, aPWD, aSysDrvSettings;
78 aDSN += url.copy(nLen+1);
79
80 const char* pUser = "user";
81 const char* pTimeout = "Timeout";
82 const char* pSilent = "Silent";
83 const char* pPwd = "password";
84 const char* pUseCatalog = "UseCatalog";
85 const char* pSysDrv = "SystemDriverSettings";
86
87 sal_Int32 nTimeout = 20;
88 sal_Bool bSilent = sal_True;
89 const PropertyValue *pBegin = info.getConstArray();
90 const PropertyValue *pEnd = pBegin + info.getLength();
91 for(;pBegin != pEnd;++pBegin)
92 {
93 if(!pBegin->Name.compareToAscii(pTimeout))
94 pBegin->Value >>= nTimeout;
95 else if(!pBegin->Name.compareToAscii(pSilent))
96 pBegin->Value >>= bSilent;
97 else if(!pBegin->Name.compareToAscii(pUser))
98 {
99 pBegin->Value >>= aUID;
100 aDSN = aDSN + ::rtl::OUString::createFromAscii(";UID=") + aUID;
101 }
102 else if(!pBegin->Name.compareToAscii(pPwd))
103 {
104 pBegin->Value >>= aPWD;
105 aDSN = aDSN + ::rtl::OUString::createFromAscii(";PWD=") + aPWD;
106 }
107 else if(!pBegin->Name.compareToAscii(pUseCatalog))
108 {
109 pBegin->Value >>= m_bUseCatalog;
110 }
111 else if(!pBegin->Name.compareToAscii(pSysDrv))
112 {
113 pBegin->Value >>= aSysDrvSettings;
114 aDSN += ::rtl::OUString::createFromAscii(";");
115 aDSN += aSysDrvSettings;
116 }
117 }
118 m_sUser = aUID;
119
120 osl_decrementInterlockedCount( &m_refCount );
121 }
122 // XServiceInfo
123 // --------------------------------------------------------------------------------
124 IMPLEMENT_SERVICE_INFO(OConnection, "com.sun.star.sdbc.drivers.skeleton.OConnection", "com.sun.star.sdbc.Connection")
125
126 // --------------------------------------------------------------------------------
createStatement()127 Reference< XStatement > SAL_CALL OConnection::createStatement( ) throw(SQLException, RuntimeException)
128 {
129 ::osl::MutexGuard aGuard( m_aMutex );
130 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
131
132 // create a statement
133 // the statement can only be executed once
134 Reference< XStatement > xReturn = new OStatement(this);
135 m_aStatements.push_back(WeakReferenceHelper(xReturn));
136 return xReturn;
137 }
138 // --------------------------------------------------------------------------------
prepareStatement(const::rtl::OUString & _sSql)139 Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const ::rtl::OUString& _sSql ) throw(SQLException, RuntimeException)
140 {
141 ::osl::MutexGuard aGuard( m_aMutex );
142 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
143
144 // the pre
145 if(m_aTypeInfo.empty())
146 buildTypeInfo();
147
148 // create a statement
149 // the statement can only be executed more than once
150 Reference< XPreparedStatement > xReturn = new OPreparedStatement(this,m_aTypeInfo,_sSql);
151 m_aStatements.push_back(WeakReferenceHelper(xReturn));
152 return xReturn;
153 }
154 // --------------------------------------------------------------------------------
prepareCall(const::rtl::OUString & _sSql)155 Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const ::rtl::OUString& _sSql ) throw(SQLException, RuntimeException)
156 {
157 ::osl::MutexGuard aGuard( m_aMutex );
158 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
159
160 // not implemented yet :-) a task to do
161 return NULL;
162 }
163 // --------------------------------------------------------------------------------
nativeSQL(const::rtl::OUString & _sSql)164 ::rtl::OUString SAL_CALL OConnection::nativeSQL( const ::rtl::OUString& _sSql ) throw(SQLException, RuntimeException)
165 {
166 ::osl::MutexGuard aGuard( m_aMutex );
167 // when you need to transform SQL92 to you driver specific you can do it here
168
169 return _sSql;
170 }
171 // --------------------------------------------------------------------------------
setAutoCommit(sal_Bool autoCommit)172 void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit ) throw(SQLException, RuntimeException)
173 {
174 ::osl::MutexGuard aGuard( m_aMutex );
175 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
176 // here you have to set your commit mode please have a look at the jdbc documentation to get a clear explanation
177 }
178 // --------------------------------------------------------------------------------
getAutoCommit()179 sal_Bool SAL_CALL OConnection::getAutoCommit( ) throw(SQLException, RuntimeException)
180 {
181 ::osl::MutexGuard aGuard( m_aMutex );
182 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
183 // you have to distinguish which if you are in autocommit mode or not
184 // at normal case true should be fine here
185
186 return sal_True;
187 }
188 // --------------------------------------------------------------------------------
commit()189 void SAL_CALL OConnection::commit( ) throw(SQLException, RuntimeException)
190 {
191 ::osl::MutexGuard aGuard( m_aMutex );
192 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
193
194 // when you database does support transactions you should commit here
195 }
196 // --------------------------------------------------------------------------------
rollback()197 void SAL_CALL OConnection::rollback( ) throw(SQLException, RuntimeException)
198 {
199 ::osl::MutexGuard aGuard( m_aMutex );
200 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
201
202
203 // same as commit but for the other case
204 }
205 // --------------------------------------------------------------------------------
isClosed()206 sal_Bool SAL_CALL OConnection::isClosed( ) throw(SQLException, RuntimeException)
207 {
208 ::osl::MutexGuard aGuard( m_aMutex );
209
210 // just simple -> we are close when we are disposed taht means someone called dispose(); (XComponent)
211 return OConnection_BASE::rBHelper.bDisposed;
212 }
213 // --------------------------------------------------------------------------------
getMetaData()214 Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData( ) throw(SQLException, RuntimeException)
215 {
216 ::osl::MutexGuard aGuard( m_aMutex );
217 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
218
219 // here we have to create the class with biggest interface
220 // The answer is 42 :-)
221 Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
222 if(!xMetaData.is())
223 {
224 xMetaData = new ODatabaseMetaData(this); // need the connection because it can return it
225 m_xMetaData = xMetaData;
226 }
227
228 return xMetaData;
229 }
230 // --------------------------------------------------------------------------------
setReadOnly(sal_Bool readOnly)231 void SAL_CALL OConnection::setReadOnly( sal_Bool readOnly ) throw(SQLException, RuntimeException)
232 {
233 ::osl::MutexGuard aGuard( m_aMutex );
234 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
235
236 // set you connection to readonly
237 }
238 // --------------------------------------------------------------------------------
isReadOnly()239 sal_Bool SAL_CALL OConnection::isReadOnly( ) throw(SQLException, RuntimeException)
240 {
241 ::osl::MutexGuard aGuard( m_aMutex );
242 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
243
244 // return if your connection to readonly
245 return sal_False;
246 }
247 // --------------------------------------------------------------------------------
setCatalog(const::rtl::OUString & catalog)248 void SAL_CALL OConnection::setCatalog( const ::rtl::OUString& catalog ) throw(SQLException, RuntimeException)
249 {
250 ::osl::MutexGuard aGuard( m_aMutex );
251 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
252
253 // if your database doesn't work with catalogs you go to next method otherwise you kjnow what to do
254 }
255 // --------------------------------------------------------------------------------
getCatalog()256 ::rtl::OUString SAL_CALL OConnection::getCatalog( ) throw(SQLException, RuntimeException)
257 {
258 ::osl::MutexGuard aGuard( m_aMutex );
259 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
260
261
262 // return your current catalog
263 return ::rtl::OUString();
264 }
265 // --------------------------------------------------------------------------------
setTransactionIsolation(sal_Int32 level)266 void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 level ) throw(SQLException, RuntimeException)
267 {
268 ::osl::MutexGuard aGuard( m_aMutex );
269 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
270
271 // set your isolation level
272 // please have a look at @see com.sun.star.sdbc.TransactionIsolation
273 }
274 // --------------------------------------------------------------------------------
getTransactionIsolation()275 sal_Int32 SAL_CALL OConnection::getTransactionIsolation( ) throw(SQLException, RuntimeException)
276 {
277 ::osl::MutexGuard aGuard( m_aMutex );
278 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
279
280
281 // please have a look at @see com.sun.star.sdbc.TransactionIsolation
282 return TransactionIsolation::NONE;
283 }
284 // --------------------------------------------------------------------------------
getTypeMap()285 Reference< ::com::sun::star::container::XNameAccess > SAL_CALL OConnection::getTypeMap( ) throw(SQLException, RuntimeException)
286 {
287 ::osl::MutexGuard aGuard( m_aMutex );
288 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
289
290 // if your driver has special database types you can return it here
291
292 return NULL;
293 }
294 // --------------------------------------------------------------------------------
setTypeMap(const Reference<::com::sun::star::container::XNameAccess> & typeMap)295 void SAL_CALL OConnection::setTypeMap( const Reference< ::com::sun::star::container::XNameAccess >& typeMap ) throw(SQLException, RuntimeException)
296 {
297 // the other way around
298 }
299 // --------------------------------------------------------------------------------
300 // XCloseable
close()301 void SAL_CALL OConnection::close( ) throw(SQLException, RuntimeException)
302 {
303 // we just dispose us
304 {
305 ::osl::MutexGuard aGuard( m_aMutex );
306 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
307
308 }
309 dispose();
310 }
311 // --------------------------------------------------------------------------------
312 // XWarningsSupplier
getWarnings()313 Any SAL_CALL OConnection::getWarnings( ) throw(SQLException, RuntimeException)
314 {
315 // when you collected some warnings -> return it
316 return Any();
317 }
318 // --------------------------------------------------------------------------------
clearWarnings()319 void SAL_CALL OConnection::clearWarnings( ) throw(SQLException, RuntimeException)
320 {
321 // you should clear your collected warnings here
322 }
323 //--------------------------------------------------------------------
buildTypeInfo()324 void OConnection::buildTypeInfo() throw( SQLException)
325 {
326 ::osl::MutexGuard aGuard( m_aMutex );
327
328 Reference< XResultSet> xRs = getMetaData ()->getTypeInfo ();
329 Reference< XRow> xRow(xRs,UNO_QUERY);
330 // Information for a single SQL type
331
332 // Loop on the result set until we reach end of file
333
334 while (xRs->next ())
335 {
336 OTypeInfo aInfo;
337 aInfo.aTypeName = xRow->getString (1);
338 aInfo.nType = xRow->getShort (2);
339 aInfo.nPrecision = xRow->getInt (3);
340 aInfo.aLiteralPrefix = xRow->getString (4);
341 aInfo.aLiteralSuffix = xRow->getString (5);
342 aInfo.aCreateParams = xRow->getString (6);
343 aInfo.bNullable = xRow->getBoolean (7) == ColumnValue::NULLABLE;
344 aInfo.bCaseSensitive = xRow->getBoolean (8);
345 aInfo.nSearchType = xRow->getShort (9);
346 aInfo.bUnsigned = xRow->getBoolean (10);
347 aInfo.bCurrency = xRow->getBoolean (11);
348 aInfo.bAutoIncrement = xRow->getBoolean (12);
349 aInfo.aLocalTypeName = xRow->getString (13);
350 aInfo.nMinimumScale = xRow->getShort (14);
351 aInfo.nMaximumScale = xRow->getShort (15);
352 aInfo.nNumPrecRadix = (sal_Int16)xRow->getInt(18);
353
354
355
356 // Now that we have the type info, save it
357 // in the Hashtable if we don't already have an
358 // entry for this SQL type.
359
360 m_aTypeInfo.push_back(aInfo);
361 }
362
363 // Close the result set/statement.
364
365 Reference< XCloseable> xClose(xRs,UNO_QUERY);
366 xClose->close();
367 }
368 //------------------------------------------------------------------------------
disposing()369 void OConnection::disposing()
370 {
371 // we noticed that we should be destroied in near future so we have to dispose our statements
372 ::osl::MutexGuard aGuard(m_aMutex);
373
374 for (OWeakRefArray::iterator i = m_aStatements.begin(); m_aStatements.end() != i; ++i)
375 {
376 Reference< XComponent > xComp(i->get(), UNO_QUERY);
377 if (xComp.is())
378 xComp->dispose();
379 }
380 m_aStatements.clear();
381
382 m_bClosed = sal_True;
383 m_xMetaData = ::com::sun::star::uno::WeakReference< ::com::sun::star::sdbc::XDatabaseMetaData>();
384
385 dispose_ChildImpl();
386 OConnection_BASE::disposing();
387 }
388 // -----------------------------------------------------------------------------
389
390
391
392