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