1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_connectivity.hxx"
30 #include <cppuhelper/typeprovider.hxx>
31 #include "file/FConnection.hxx"
32 #include "file/FDatabaseMetaData.hxx"
33 #include "file/FDriver.hxx"
34 #include "file/FStatement.hxx"
35 #include "file/FPreparedStatement.hxx"
36 #include <com/sun/star/sdbc/ColumnValue.hpp>
37 #include <com/sun/star/sdbc/XRow.hpp>
38 #include <com/sun/star/lang/DisposedException.hpp>
39 #include <com/sun/star/container/XChild.hpp>
40 #include <com/sun/star/ucb/XContent.hpp>
41 #include <com/sun/star/ucb/XContentIdentifier.hpp>
42 #include <tools/urlobj.hxx>
43 #include "file/FCatalog.hxx"
44 #include <unotools/pathoptions.hxx>
45 #include <ucbhelper/content.hxx>
46 #include <connectivity/dbcharset.hxx>
47 #include <connectivity/dbexception.hxx>
48 #include <osl/thread.h>
49 #include <osl/nlsupport.h>
50 #include "resource/file_res.hrc"
51 
52 using namespace connectivity::file;
53 using namespace dbtools;
54 //------------------------------------------------------------------------------
55 using namespace com::sun::star::uno;
56 using namespace com::sun::star::lang;
57 using namespace com::sun::star::beans;
58 using namespace com::sun::star::sdbc;
59 using namespace com::sun::star::sdbcx;
60 using namespace com::sun::star::container;
61 using namespace com::sun::star::ucb;
62 using namespace ::ucbhelper;
63 using rtl::OUString;
64 typedef connectivity::OMetaConnection OConnection_BASE;
65 // --------------------------------------------------------------------------------
66 OConnection::OConnection(OFileDriver*	_pDriver)
67 						 : OSubComponent<OConnection, OConnection_BASE>((::cppu::OWeakObject*)_pDriver, this)
68 						 ,m_pDriver(_pDriver)
69 						 ,m_bClosed(sal_False)
70 						 ,m_bShowDeleted(sal_False)
71 						 ,m_bCaseSensitiveExtension( sal_True )
72 						 ,m_bCheckSQL92(sal_False)
73                          ,m_bDefaultTextEncoding(false)
74 {
75 	m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW;
76 }
77 //-----------------------------------------------------------------------------
78 OConnection::~OConnection()
79 {
80 	if(!isClosed(  ))
81 		close();
82 }
83 //-----------------------------------------------------------------------------
84 void SAL_CALL OConnection::release() throw()
85 {
86 	relase_ChildImpl();
87 }
88 
89 //-----------------------------------------------------------------------------
90 sal_Bool OConnection::matchesExtension( const String& _rExt ) const
91 {
92 	if ( isCaseSensitveExtension() )
93 		return ( getExtension() == _rExt );
94 
95 	String sMyExtension( getExtension() );
96 	sMyExtension.ToLowerAscii();
97 	String sExt( _rExt );
98 	sExt.ToLowerAscii();
99 
100 	return sMyExtension == sExt;
101 }
102 
103 //-----------------------------------------------------------------------------
104 void OConnection::construct(const ::rtl::OUString& url,const Sequence< PropertyValue >& info)  throw(SQLException)
105 {
106 	osl_incrementInterlockedCount( &m_refCount );
107 
108 	::rtl::OUString aExt;
109 	const PropertyValue *pIter  = info.getConstArray();
110 	const PropertyValue *pEnd    = pIter + info.getLength();
111 	for(;pIter != pEnd;++pIter)
112 	{
113 		if(0 == pIter->Name.compareToAscii("Extension"))
114 			OSL_VERIFY( pIter->Value >>= aExt );
115 		else if(0 == pIter->Name.compareToAscii("CharSet"))
116 		{
117 			::rtl::OUString sIanaName;
118 			OSL_VERIFY( pIter->Value >>= sIanaName );
119 
120 			::dbtools::OCharsetMap aLookupIanaName;
121 			::dbtools::OCharsetMap::const_iterator aLookup = aLookupIanaName.find(sIanaName, ::dbtools::OCharsetMap::IANA());
122 			if (aLookup != aLookupIanaName.end())
123 				m_nTextEncoding = (*aLookup).getEncoding();
124 			else
125 				m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW;
126 		}
127 		else if (0 == pIter->Name.compareToAscii("ShowDeleted"))
128 		{
129 			OSL_VERIFY( pIter->Value >>= m_bShowDeleted );
130 		}
131 		else if (0 == pIter->Name.compareToAscii("EnableSQL92Check"))
132 		{
133 			pIter->Value >>= m_bCheckSQL92;
134 		}
135 	} // for(;pIter != pEnd;++pIter)
136 
137     {
138 		sal_Int32 nLen = url.indexOf(':');
139 		nLen = url.indexOf(':',nLen+1);
140 		::rtl::OUString aDSN(url.copy(nLen+1)),aUID,aPWD;
141 
142         String aFileName = aDSN;
143         INetURLObject aURL;
144         aURL.SetSmartProtocol(INET_PROT_FILE);
145 		{
146 			SvtPathOptions aPathOptions;
147 			aFileName = aPathOptions.SubstituteVariable(aFileName);
148 		}
149 
150 		aURL.SetSmartURL(aFileName);
151 
152 		setURL(aURL.GetMainURL(INetURLObject::NO_DECODE));
153 	}
154 
155 	if ( m_nTextEncoding == RTL_TEXTENCODING_DONTKNOW )
156 	{
157 		//m_nTextEncoding = osl_getTextEncodingFromLocale(NULL);
158 		m_nTextEncoding = osl_getThreadTextEncoding();
159         m_bDefaultTextEncoding = true;
160 	}
161 
162 	if ( aExt.getLength() )
163 		m_aFilenameExtension = aExt;
164 
165 	try
166 	{
167 		::ucbhelper::Content aFile;
168 		try
169 		{
170 			aFile = ::ucbhelper::Content(getURL(),Reference< XCommandEnvironment >());
171 		}
172 		catch(ContentCreationException& e)
173 		{
174 			throwUrlNotValid(getURL(),e.Message);
175 		}
176 
177 		// set fields to fetch
178 		Sequence< OUString > aProps(1);
179 		OUString* pProps = aProps.getArray();
180 		pProps[ 0 ] = OUString::createFromAscii( "Title" );
181 
182 		try
183 		{
184 			if (aFile.isFolder())
185 			{
186 				m_xDir = aFile.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
187 				m_xContent = aFile.get();
188 			}
189 			else if (aFile.isDocument())
190 			{
191 				Reference<XContent> xParent(Reference<XChild>(aFile.get(),UNO_QUERY)->getParent(),UNO_QUERY);
192 				Reference<XContentIdentifier> xIdent = xParent->getIdentifier();
193 				m_xContent = xParent;
194 
195 				::ucbhelper::Content aParent(xIdent->getContentIdentifier(),Reference< XCommandEnvironment >());
196 				m_xDir = aParent.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
197 			}
198 			else
199 			{
200 				OSL_ENSURE(0,"OConnection::construct: ::ucbhelper::Content isn't a folde nor a document! How that?!");
201 				throw SQLException();
202 			}
203 		}
204 		catch(Exception& e) // a execption is thrown when no file exists
205 		{
206 			throwUrlNotValid(getURL(),e.Message);
207 		}
208 		if(!m_xDir.is() || !m_xContent.is())
209 			throwUrlNotValid(getURL(),::rtl::OUString());
210 
211 		if (m_aFilenameExtension.Search('*') != STRING_NOTFOUND || m_aFilenameExtension.Search('?') != STRING_NOTFOUND)
212 			throw SQLException();
213 	}
214 	catch(const Exception&)
215 	{
216 		osl_decrementInterlockedCount( &m_refCount );
217 		throw;
218 	}
219 
220 	osl_decrementInterlockedCount( &m_refCount );
221 }
222 // XServiceInfo
223 // --------------------------------------------------------------------------------
224 IMPLEMENT_SERVICE_INFO(OConnection, "com.sun.star.sdbc.drivers.file.Connection", "com.sun.star.sdbc.Connection")
225 
226 // --------------------------------------------------------------------------------
227 Reference< XStatement > SAL_CALL OConnection::createStatement(  ) throw(SQLException, RuntimeException)
228 {
229 	::osl::MutexGuard aGuard( m_aMutex );
230 	checkDisposed(OConnection_BASE::rBHelper.bDisposed);
231 
232 
233 	Reference< XStatement > xReturn = new OStatement(this);
234     m_aStatements.push_back(WeakReferenceHelper(xReturn));
235 	return xReturn;
236 }
237 // --------------------------------------------------------------------------------
238 Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
239 {
240 	::osl::MutexGuard aGuard( m_aMutex );
241 	checkDisposed(OConnection_BASE::rBHelper.bDisposed);
242 
243 
244 	OPreparedStatement* pStmt = new OPreparedStatement(this);
245 	Reference< XPreparedStatement > xHoldAlive = pStmt;
246 	pStmt->construct(sql);
247     m_aStatements.push_back(WeakReferenceHelper(*pStmt));
248 	return pStmt;
249 }
250 // --------------------------------------------------------------------------------
251 Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const ::rtl::OUString& /*sql*/ ) throw(SQLException, RuntimeException)
252 {
253     throwFeatureNotImplementedException( "XConnection::prepareCall", *this );
254     return NULL;
255 }
256 // --------------------------------------------------------------------------------
257 ::rtl::OUString SAL_CALL OConnection::nativeSQL( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
258 {
259 	return sql;
260 }
261 // --------------------------------------------------------------------------------
262 void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit ) throw(SQLException, RuntimeException)
263 {
264 	::osl::MutexGuard aGuard( m_aMutex );
265 	checkDisposed(OConnection_BASE::rBHelper.bDisposed);
266 
267 	m_bAutoCommit = autoCommit;
268 }
269 // --------------------------------------------------------------------------------
270 sal_Bool SAL_CALL OConnection::getAutoCommit(  ) throw(SQLException, RuntimeException)
271 {
272 	::osl::MutexGuard aGuard( m_aMutex );
273 	checkDisposed(OConnection_BASE::rBHelper.bDisposed);
274 
275 	return m_bAutoCommit;
276 }
277 // --------------------------------------------------------------------------------
278 void SAL_CALL OConnection::commit(  ) throw(SQLException, RuntimeException)
279 {
280 }
281 // --------------------------------------------------------------------------------
282 void SAL_CALL OConnection::rollback(  ) throw(SQLException, RuntimeException)
283 {
284 }
285 // --------------------------------------------------------------------------------
286 sal_Bool SAL_CALL OConnection::isClosed(  ) throw(SQLException, RuntimeException)
287 {
288 	::osl::MutexGuard aGuard( m_aMutex );
289 
290 	return OConnection_BASE::rBHelper.bDisposed;
291 }
292 // --------------------------------------------------------------------------------
293 Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData(  ) throw(SQLException, RuntimeException)
294 {
295 	::osl::MutexGuard aGuard( m_aMutex );
296 	checkDisposed(OConnection_BASE::rBHelper.bDisposed);
297 
298 
299 	Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
300 	if(!xMetaData.is())
301 	{
302 		xMetaData = new ODatabaseMetaData(this);
303 		m_xMetaData = xMetaData;
304 	}
305 
306 	return xMetaData;
307 }
308 // --------------------------------------------------------------------------------
309 void SAL_CALL OConnection::setReadOnly( sal_Bool readOnly ) throw(SQLException, RuntimeException)
310 {
311 	::osl::MutexGuard aGuard( m_aMutex );
312 	checkDisposed(OConnection_BASE::rBHelper.bDisposed);
313 
314 
315 	m_bReadOnly = readOnly;
316 }
317 // --------------------------------------------------------------------------------
318 sal_Bool SAL_CALL OConnection::isReadOnly(  ) throw(SQLException, RuntimeException)
319 {
320 	::osl::MutexGuard aGuard( m_aMutex );
321 	checkDisposed(OConnection_BASE::rBHelper.bDisposed);
322 
323 
324 	return m_bReadOnly;
325 }
326 // --------------------------------------------------------------------------------
327 void SAL_CALL OConnection::setCatalog( const ::rtl::OUString& /*catalog*/ ) throw(SQLException, RuntimeException)
328 {
329     throwFeatureNotImplementedException( "XConnection::setCatalog", *this );
330 }
331 // --------------------------------------------------------------------------------
332 ::rtl::OUString SAL_CALL OConnection::getCatalog(  ) throw(SQLException, RuntimeException)
333 {
334 	return ::rtl::OUString();
335 }
336 // --------------------------------------------------------------------------------
337 void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 /*level*/ ) throw(SQLException, RuntimeException)
338 {
339     throwFeatureNotImplementedException( "XConnection::setTransactionIsolation", *this );
340 }
341 // --------------------------------------------------------------------------------
342 sal_Int32 SAL_CALL OConnection::getTransactionIsolation(  ) throw(SQLException, RuntimeException)
343 {
344 	return 0;
345 }
346 // --------------------------------------------------------------------------------
347 Reference< XNameAccess > SAL_CALL OConnection::getTypeMap(  ) throw(SQLException, RuntimeException)
348 {
349 	return NULL;
350 }
351 // --------------------------------------------------------------------------------
352 void SAL_CALL OConnection::setTypeMap( const Reference< XNameAccess >& /*typeMap*/ ) throw(SQLException, RuntimeException)
353 {
354 }
355 // --------------------------------------------------------------------------------
356 // XCloseable
357 void SAL_CALL OConnection::close(  ) throw(SQLException, RuntimeException)
358 {
359 	{
360 		::osl::MutexGuard aGuard( m_aMutex );
361 		checkDisposed(OConnection_BASE::rBHelper.bDisposed);
362 
363 	}
364 	dispose();
365 }
366 // --------------------------------------------------------------------------------
367 // XWarningsSupplier
368 Any SAL_CALL OConnection::getWarnings(  ) throw(SQLException, RuntimeException)
369 {
370 	return Any();
371 }
372 // --------------------------------------------------------------------------------
373 void SAL_CALL OConnection::clearWarnings(  ) throw(SQLException, RuntimeException)
374 {
375 }
376 //------------------------------------------------------------------------------
377 void OConnection::disposing()
378 {
379 	::osl::MutexGuard aGuard(m_aMutex);
380     OConnection_BASE::disposing();
381 
382 	m_bClosed	= sal_True;
383 m_xDir.clear();
384 m_xContent.clear();
385 	m_xCatalog	= WeakReference< XTablesSupplier>();
386 
387 	dispose_ChildImpl();
388 }
389 //------------------------------------------------------------------------------
390 Reference< XTablesSupplier > OConnection::createCatalog()
391 {
392 	::osl::MutexGuard aGuard( m_aMutex );
393     Reference< XTablesSupplier > xTab = m_xCatalog;
394 	if(!xTab.is())
395 	{
396 		xTab = new OFileCatalog(this);
397 		m_xCatalog = xTab;
398 	}
399 	return xTab;
400 }
401 // -----------------------------------------------------------------------------
402 Reference< XDynamicResultSet > OConnection::getDir() const
403 {
404 	Reference<XDynamicResultSet> xContent;
405 	Sequence< ::rtl::OUString > aProps(1);
406 	::rtl::OUString* pProps = aProps.getArray();
407 	pProps[ 0 ] = ::rtl::OUString::createFromAscii( "Title" );
408 	try
409 	{
410 		Reference<XContentIdentifier> xIdent = getContent()->getIdentifier();
411 		::ucbhelper::Content aParent(xIdent->getContentIdentifier(),Reference< XCommandEnvironment >());
412 		xContent = aParent.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
413 	}
414 	catch(Exception&)
415 	{
416 	}
417 	return xContent;
418 }
419 // -----------------------------------------------------------------------------
420 sal_Int64 SAL_CALL OConnection::getSomething( const Sequence< sal_Int8 >& rId ) throw (RuntimeException)
421 {
422 	return (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(),  rId.getConstArray(), 16 ) )
423 		? reinterpret_cast< sal_Int64 >( this )
424 		: (sal_Int64)0;
425 }
426 // -----------------------------------------------------------------------------
427 Sequence< sal_Int8 > OConnection::getUnoTunnelImplementationId()
428 {
429 	static ::cppu::OImplementationId * pId = 0;
430 	if (! pId)
431 	{
432 		::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
433 		if (! pId)
434 		{
435 			static ::cppu::OImplementationId aId;
436 			pId = &aId;
437 		}
438 	}
439 	return pId->getImplementationId();
440 }
441 // -----------------------------------------------------------------------------
442 void OConnection::throwUrlNotValid(const ::rtl::OUString & _rsUrl,const ::rtl::OUString & _rsMessage)
443 {
444     SQLException aError;
445 	aError.Message = getResources().getResourceStringWithSubstitution(
446                 STR_NO_VALID_FILE_URL,
447                 "$URL$", _rsUrl
448             );
449 
450 	aError.SQLState = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("S1000"));
451 	aError.ErrorCode = 0;
452 	aError.Context = static_cast< XConnection* >(this);
453 	if (_rsMessage.getLength())
454 		aError.NextException <<= SQLException(_rsMessage, aError.Context, ::rtl::OUString(), 0, Any());
455 
456 	throw aError;
457 }
458 // -----------------------------------------------------------------------------
459 
460 
461 
462