Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * Effective License of whole file:
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License version 2.1, as published by the Free Software Foundation.
9 : : *
10 : : * This library is distributed in the hope that it will be useful,
11 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : : * Lesser General Public License for more details.
14 : : *
15 : : * You should have received a copy of the GNU Lesser General Public
16 : : * License along with this library; if not, write to the Free Software
17 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18 : : * MA 02111-1307 USA
19 : : *
20 : : * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
21 : : *
22 : : * The Contents of this file are made available subject to the terms of
23 : : * the GNU Lesser General Public License Version 2.1
24 : : *
25 : : * Copyright: 2000 by Sun Microsystems, Inc.
26 : : *
27 : : * Contributor(s): Joerg Budischewski
28 : : *
29 : : * All parts contributed on or after August 2011:
30 : : *
31 : : * Version: MPL 1.1 / GPLv3+ / LGPLv2.1+
32 : : *
33 : : * The contents of this file are subject to the Mozilla Public License Version
34 : : * 1.1 (the "License"); you may not use this file except in compliance with
35 : : * the License or as specified alternatively below. You may obtain a copy of
36 : : * the License at http://www.mozilla.org/MPL/
37 : : *
38 : : * Software distributed under the License is distributed on an "AS IS" basis,
39 : : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
40 : : * for the specific language governing rights and limitations under the
41 : : * License.
42 : : *
43 : : * Major Contributor(s):
44 : : * [ Copyright (C) 2011 Lionel Elie Mamane <lionel@mamane.lu> ]
45 : : *
46 : : * All Rights Reserved.
47 : : *
48 : : * For minor contributions see the git repository.
49 : : *
50 : : * Alternatively, the contents of this file may be used under the terms of
51 : : * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
52 : : * the GNU Lesser General Public License Version 2.1 or later (the "LGPLv2.1+"),
53 : : * in which case the provisions of the GPLv3+ or the LGPLv2.1+ are applicable
54 : : * instead of those above.
55 : : *
56 : : ************************************************************************/
57 : :
58 : : #include <list>
59 : : #include <stdio.h>
60 : : #include <time.h>
61 : : #include <string.h>
62 : :
63 : : #include <boost/shared_ptr.hpp>
64 : :
65 : : #include "pq_connection.hxx"
66 : : #include "pq_statement.hxx"
67 : : #include "pq_preparedstatement.hxx"
68 : : #include "pq_databasemetadata.hxx"
69 : : #include "pq_xcontainer.hxx"
70 : : #include "pq_statics.hxx"
71 : : #include "pq_xtables.hxx"
72 : : #include "pq_xviews.hxx"
73 : : #include "pq_xusers.hxx"
74 : :
75 : : #include <rtl/ustrbuf.hxx>
76 : : #include <rtl/strbuf.hxx>
77 : : #include <rtl/uuid.h>
78 : : #include <rtl/bootstrap.hxx>
79 : : #include <osl/module.h>
80 : :
81 : : #include <cppuhelper/implementationentry.hxx>
82 : : #include <cppuhelper/implbase1.hxx>
83 : :
84 : : #include <com/sun/star/beans/PropertyValue.hpp>
85 : : #include <com/sun/star/sdbc/XRow.hpp>
86 : :
87 : : using rtl::OUStringBuffer;
88 : : using rtl::OUString;
89 : : using rtl::OString;
90 : : using rtl::OStringBuffer;
91 : : using rtl::OUStringToOString;
92 : : using osl::MutexGuard;
93 : :
94 : : using com::sun::star::container::XNameAccess;
95 : :
96 : : using com::sun::star::lang::XComponent;
97 : : using com::sun::star::lang::XInitialization;
98 : : using com::sun::star::lang::IllegalArgumentException;
99 : :
100 : : using com::sun::star::script::XTypeConverter;
101 : :
102 : : using com::sun::star::uno::RuntimeException;
103 : : using com::sun::star::uno::Exception;
104 : : using com::sun::star::uno::Sequence;
105 : : using com::sun::star::uno::Reference;
106 : : using com::sun::star::uno::XInterface;
107 : : using com::sun::star::uno::UNO_QUERY;
108 : : using com::sun::star::uno::XComponentContext;
109 : : using com::sun::star::uno::Any;
110 : : using com::sun::star::uno::makeAny;
111 : :
112 : : using com::sun::star::beans::PropertyValue;
113 : : using com::sun::star::beans::XPropertySet;
114 : :
115 : : using com::sun::star::sdbc::XConnection;
116 : : using com::sun::star::sdbc::XResultSet;
117 : : using com::sun::star::sdbc::XRow;
118 : : using com::sun::star::sdbc::XCloseable;
119 : : using com::sun::star::sdbc::SQLException;
120 : : using com::sun::star::sdbc::XWarningsSupplier;
121 : : using com::sun::star::sdbc::XPreparedStatement;
122 : : using com::sun::star::sdbc::XStatement;
123 : : using com::sun::star::sdbc::XDatabaseMetaData;
124 : :
125 : : namespace pq_sdbc_driver
126 : : {
127 : :
128 : : #define ASCII_STR(x) OUString( RTL_CONSTASCII_USTRINGPARAM( x ) )
129 : :
130 : :
131 : : // ______________________________________________________________________________
132 : : // Helper class for statement lifetime management
133 : : class ClosableReference : public cppu::WeakImplHelper1< com::sun::star::uno::XReference >
134 : : {
135 : : Connection *m_conn;
136 : : ::rtl::ByteSequence m_id;
137 : : public:
138 : 0 : ClosableReference( const ::rtl::ByteSequence & id , Connection *that )
139 : 0 : : m_conn( that ), m_id( id )
140 : : {
141 : 0 : that->acquire();
142 : 0 : }
143 : :
144 : 0 : virtual ~ClosableReference()
145 : 0 : {
146 : 0 : if( m_conn )
147 : 0 : m_conn->release();
148 : 0 : }
149 : :
150 : 0 : virtual void SAL_CALL dispose() throw ()
151 : : {
152 : 0 : if( m_conn )
153 : : {
154 : 0 : m_conn->removeFromWeakMap(m_id);
155 : 0 : m_conn->release();
156 : 0 : m_conn = 0;
157 : : }
158 : 0 : }
159 : : };
160 : :
161 : 0 : OUString ConnectionGetImplementationName()
162 : : {
163 : 0 : return OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.connectivity.pq.Connection.noext" ) );
164 : : }
165 : 0 : com::sun::star::uno::Sequence<rtl::OUString> ConnectionGetSupportedServiceNames(void)
166 : : {
167 : 0 : OUString serv( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdbc.Connection" ) );
168 : 0 : return Sequence< OUString> (&serv,1);
169 : : }
170 : :
171 : 0 : static sal_Int32 readLogLevelFromConfiguration()
172 : : {
173 : 0 : sal_Int32 loglevel = LogLevel::NONE;
174 : 0 : OUString fileName;
175 : : osl_getModuleURLFromAddress(
176 : 0 : (void*) readLogLevelFromConfiguration, (rtl_uString **) &fileName );
177 : 0 : fileName = OUString( fileName.getStr(), fileName.lastIndexOf( '/' )+1 );
178 : 0 : fileName += OUString::createFromAscii( "postgresql-sdbc.ini" );
179 : 0 : rtl::Bootstrap bootstrapHandle( fileName );
180 : :
181 : 0 : OUString str;
182 : 0 : if( bootstrapHandle.getFrom( ASCII_STR( "PQ_LOGLEVEL" ), str ) )
183 : : {
184 : 0 : if ( str == "NONE" )
185 : 0 : loglevel = LogLevel::NONE;
186 : 0 : else if ( str == "ERROR" )
187 : 0 : loglevel = LogLevel::ERROR;
188 : 0 : else if ( str == "SQL" )
189 : 0 : loglevel = LogLevel::SQL;
190 : 0 : else if ( str == "INFO" )
191 : 0 : loglevel = LogLevel::INFO;
192 : : else
193 : : {
194 : : fprintf( stderr, "unknown loglevel %s\n",
195 : 0 : OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
196 : : }
197 : : }
198 : 0 : return loglevel;
199 : : }
200 : :
201 : 0 : Connection::Connection(
202 : : const rtl::Reference< RefCountedMutex > &refMutex,
203 : : const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > & ctx )
204 : 0 : : ConnectionBase( refMutex->mutex ),
205 : : m_ctx( ctx ) ,
206 : 0 : m_refMutex( refMutex )
207 : : {
208 : 0 : m_settings.loglevel = readLogLevelFromConfiguration();
209 : :
210 : 0 : if( m_settings.loglevel > LogLevel::NONE )
211 : : {
212 : 0 : m_settings.logFile = fopen( "sdbc-pqsql.log", "a" );
213 : 0 : if( m_settings.logFile )
214 : : {
215 : 0 : setvbuf( m_settings.logFile, 0, _IONBF, 0 );
216 : 0 : log( &m_settings, m_settings.loglevel , "set this loglevel" );
217 : : }
218 : : else
219 : : {
220 : 0 : fprintf( stderr, "Couldn't open sdbc-pqsql.log file\n" );
221 : : }
222 : : }
223 : 0 : }
224 : :
225 : 0 : Connection::~Connection()
226 : : {
227 : : POSTGRE_TRACE( "dtor connection" );
228 : 0 : if( m_settings.pConnection )
229 : : {
230 : 0 : PQfinish( m_settings.pConnection );
231 : 0 : m_settings.pConnection = 0;
232 : : }
233 : 0 : if( m_settings.logFile )
234 : : {
235 : 0 : fclose( m_settings.logFile );
236 : 0 : m_settings.logFile = 0;
237 : : }
238 : 0 : }
239 : : typedef ::std::list< ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XCloseable > ,
240 : : ::pq_sdbc_driver::Allocator < ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XCloseable > > > CloseableList;
241 : :
242 : : typedef ::std::list< ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > ,
243 : : ::pq_sdbc_driver::Allocator < ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > > > DisposeableList;
244 : :
245 : 0 : void Connection::close() throw ( SQLException, RuntimeException )
246 : : {
247 : 0 : CloseableList lst;
248 : 0 : DisposeableList lstDispose;
249 : : {
250 : 0 : MutexGuard guard( m_refMutex->mutex );
251 : : // silently ignore, if the connection has been closed already
252 : 0 : if( m_settings.pConnection )
253 : : {
254 : 0 : log( &m_settings, LogLevel::INFO, "closing connection" );
255 : 0 : PQfinish( m_settings.pConnection );
256 : 0 : m_settings.pConnection = 0;
257 : : }
258 : :
259 : 0 : lstDispose.push_back( Reference< XComponent > ( m_settings.users, UNO_QUERY ) );
260 : 0 : lstDispose.push_back( Reference< XComponent > ( m_settings.tables , UNO_QUERY ) );
261 : 0 : lstDispose.push_back( Reference< XComponent > ( m_meta, UNO_QUERY ) );
262 : 0 : m_meta.clear();
263 : 0 : m_settings.tables.clear();
264 : 0 : m_settings.users.clear();
265 : :
266 : 0 : for( WeakHashMap::iterator ii = m_myStatements.begin() ;
267 : 0 : ii != m_myStatements.end() ;
268 : : ++ii )
269 : : {
270 : 0 : Reference< XCloseable > r = ii->second;
271 : 0 : if( r.is() )
272 : 0 : lst.push_back( r );
273 : 0 : }
274 : : }
275 : :
276 : : // close all created statements
277 : 0 : for( CloseableList::iterator ii = lst.begin(); ii != lst.end() ; ++ii )
278 : 0 : ii->get()->close();
279 : :
280 : : // close all created statements
281 : 0 : for( DisposeableList::iterator iiDispose = lstDispose.begin();
282 : 0 : iiDispose != lstDispose.end() ; ++iiDispose )
283 : : {
284 : 0 : if( iiDispose->is() )
285 : 0 : iiDispose->get()->dispose();
286 : 0 : }
287 : 0 : }
288 : :
289 : :
290 : 0 : void Connection::removeFromWeakMap( const ::rtl::ByteSequence & id )
291 : : {
292 : : // shrink the list !
293 : 0 : MutexGuard guard( m_refMutex->mutex );
294 : 0 : WeakHashMap::iterator ii = m_myStatements.find( id );
295 : 0 : if( ii != m_myStatements.end() )
296 : 0 : m_myStatements.erase( ii );
297 : 0 : }
298 : :
299 : 0 : Reference< XStatement > Connection::createStatement() throw (SQLException, RuntimeException)
300 : : {
301 : 0 : MutexGuard guard( m_refMutex->mutex );
302 : 0 : checkClosed();
303 : :
304 : 0 : Statement *stmt = new Statement( m_refMutex, this , &m_settings );
305 : 0 : Reference< XStatement > ret( stmt );
306 : 0 : ::rtl::ByteSequence id( 16 );
307 : 0 : rtl_createUuid( (sal_uInt8*) id.getConstArray(), 0 , sal_False );
308 : 0 : m_myStatements[ id ] = Reference< XCloseable > ( stmt );
309 : 0 : stmt->queryAdapter()->addReference( new ClosableReference( id, this ) );
310 : 0 : return ret;
311 : : }
312 : :
313 : 0 : Reference< XPreparedStatement > Connection::prepareStatement( const ::rtl::OUString& sql )
314 : : throw (SQLException, RuntimeException)
315 : : {
316 : 0 : MutexGuard guard( m_refMutex->mutex );
317 : 0 : checkClosed();
318 : :
319 : 0 : rtl::OString byteSql = OUStringToOString( sql, m_settings.encoding );
320 : 0 : PreparedStatement *stmt = new PreparedStatement( m_refMutex, this, &m_settings, byteSql );
321 : 0 : Reference< XPreparedStatement > ret = stmt;
322 : :
323 : 0 : ::rtl::ByteSequence id( 16 );
324 : 0 : rtl_createUuid( (sal_uInt8*) id.getConstArray(), 0 , sal_False );
325 : 0 : m_myStatements[ id ] = Reference< XCloseable > ( stmt );
326 : 0 : stmt->queryAdapter()->addReference( new ClosableReference( id, this ) );
327 : 0 : return ret;
328 : : }
329 : :
330 : 0 : Reference< XPreparedStatement > Connection::prepareCall( const ::rtl::OUString& )
331 : : throw (SQLException, RuntimeException)
332 : : {
333 : : throw SQLException(
334 : : OUString(
335 : : RTL_CONSTASCII_USTRINGPARAM( "pq_driver: Callable statements not supported" ) ),
336 : 0 : Reference< XInterface > (), OUString() , 1, Any() );
337 : : }
338 : :
339 : :
340 : 0 : ::rtl::OUString Connection::nativeSQL( const ::rtl::OUString& sql )
341 : : throw (SQLException, RuntimeException)
342 : : {
343 : 0 : return sql;
344 : : }
345 : :
346 : 0 : void Connection::setAutoCommit( sal_Bool ) throw (SQLException, RuntimeException)
347 : : {
348 : : // UNSUPPORTED
349 : 0 : }
350 : :
351 : 0 : sal_Bool Connection::getAutoCommit() throw (SQLException, RuntimeException)
352 : : {
353 : : // UNSUPPORTED
354 : 0 : return sal_True;
355 : : }
356 : :
357 : 0 : void Connection::commit() throw (SQLException, RuntimeException)
358 : : {
359 : : // UNSUPPORTED
360 : 0 : }
361 : :
362 : 0 : void Connection::rollback() throw (SQLException, RuntimeException)
363 : : {
364 : : // UNSUPPORTED
365 : 0 : }
366 : :
367 : 0 : sal_Bool Connection::isClosed() throw (SQLException, RuntimeException)
368 : : {
369 : 0 : return m_settings.pConnection == 0;
370 : : }
371 : :
372 : 0 : Reference< XDatabaseMetaData > Connection::getMetaData()
373 : : throw (SQLException, RuntimeException)
374 : : {
375 : 0 : MutexGuard guard( m_refMutex->mutex );
376 : 0 : checkClosed();
377 : 0 : if( ! m_meta.is() )
378 : 0 : m_meta = new DatabaseMetaData( m_refMutex, this, &m_settings );
379 : 0 : return m_meta;
380 : : }
381 : :
382 : 0 : void Connection::setReadOnly( sal_Bool ) throw (SQLException, RuntimeException)
383 : : {
384 : : // UNSUPPORTED
385 : :
386 : 0 : }
387 : :
388 : 0 : sal_Bool Connection::isReadOnly() throw (SQLException, RuntimeException)
389 : : {
390 : : // UNSUPPORTED
391 : 0 : return sal_False;
392 : : }
393 : :
394 : 0 : void Connection::setCatalog( const ::rtl::OUString& )
395 : : throw (SQLException, RuntimeException)
396 : : {
397 : : // UNSUPPORTED
398 : 0 : }
399 : :
400 : 0 : ::rtl::OUString Connection::getCatalog() throw (SQLException, RuntimeException)
401 : : {
402 : 0 : OUString ret;
403 : 0 : MutexGuard ( m_refMutex->mutex );
404 : 0 : if( m_settings.pConnection == 0 )
405 : : {
406 : : throw SQLException( ASCII_STR( "pq_connection: connection is closed" ), *this,
407 : 0 : OUString(), 1, Any() );
408 : : }
409 : 0 : char * p = PQdb(m_settings.pConnection );
410 : 0 : return OUString( p, strlen(p) , m_settings.encoding );
411 : : }
412 : :
413 : 0 : void Connection::setTransactionIsolation( sal_Int32 )
414 : : throw (SQLException, RuntimeException)
415 : : {
416 : : // UNSUPPORTED
417 : 0 : }
418 : :
419 : 0 : sal_Int32 Connection::getTransactionIsolation() throw (SQLException, RuntimeException)
420 : : {
421 : : // UNSUPPORTED
422 : 0 : return 0;
423 : : }
424 : :
425 : 0 : Reference< XNameAccess > Connection::getTypeMap() throw (SQLException, RuntimeException)
426 : : {
427 : 0 : Reference< XNameAccess > t;
428 : : {
429 : 0 : MutexGuard guard( m_refMutex->mutex );
430 : 0 : t = m_typeMap;
431 : : }
432 : 0 : return t;
433 : : }
434 : :
435 : 0 : void Connection::setTypeMap( const Reference< XNameAccess >& typeMap )
436 : : throw (SQLException, RuntimeException)
437 : : {
438 : 0 : MutexGuard guard( m_refMutex->mutex );
439 : 0 : m_typeMap = typeMap;
440 : 0 : }
441 : 0 : Any Connection::getWarnings() throw (SQLException, RuntimeException)
442 : : {
443 : 0 : return Any();
444 : : }
445 : :
446 : 0 : void Connection::clearWarnings() throw (SQLException, RuntimeException)
447 : : {
448 : 0 : }
449 : :
450 : : class cstr_vector
451 : : {
452 : : std::vector<char*> values;
453 : : std::vector<bool> acquired;
454 : : public:
455 : 0 : cstr_vector () : values(), acquired() { values.reserve(8); acquired.reserve(8); }
456 : 0 : ~cstr_vector ()
457 : 0 : {
458 : : OSL_ENSURE(values.size() == acquired.size(), "pq_connection: cstr_vector values and acquired size mismatch");
459 : 0 : std::vector<char*>::iterator pv = values.begin();
460 : 0 : std::vector<bool>::iterator pa = acquired.begin();
461 : 0 : const std::vector<char*>::iterator pve = values.end();
462 : 0 : for( ; pv < pve ; ++pv, ++pa )
463 : 0 : if (*pa)
464 : 0 : free(*pv);
465 : 0 : }
466 : 0 : void push_back(const char* s, __sal_NoAcquire)
467 : : {
468 : 0 : values.push_back(const_cast<char*>(s));
469 : 0 : acquired.push_back(false);
470 : 0 : }
471 : 0 : void push_back(char* s)
472 : : {
473 : 0 : values.push_back(s);
474 : 0 : acquired.push_back(true);
475 : 0 : }
476 : : // This const_cast is there for compatibility with PostgreSQL <= 9.1;
477 : : // PostgreSQL >= 9.2 has the right const qualifiers in the headers
478 : : // for a return type of "char const*const*".
479 : 0 : char const** c_array() const { return const_cast <const char**>(&values[0]); }
480 : : };
481 : :
482 : 0 : static void properties2arrays( const Sequence< PropertyValue > & args,
483 : : const Reference< XTypeConverter> &tc,
484 : : rtl_TextEncoding enc,
485 : : cstr_vector &keywords,
486 : : cstr_vector &values)
487 : : {
488 : : // LEM TODO: can we just blindly take all properties?
489 : : // I.e. they are prefiltered to have only relevant ones?
490 : : // Else, at least support all keywords from
491 : : // http://www.postgresql.org/docs/9.0/interactive/libpq-connect.html
492 : 0 : for( int i = 0; i < args.getLength() ; ++i )
493 : : {
494 : 0 : bool append = true;
495 : : // TODO: rewrite this as a static table of keywords, and a loop over these keywords.
496 : 0 : if( args[i].Name.matchIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "password" ) ) )
497 : : {
498 : 0 : keywords.push_back( "password", SAL_NO_ACQUIRE );
499 : : }
500 : 0 : else if( args[i].Name.matchIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "user" ) ) )
501 : : {
502 : 0 : keywords.push_back( "user", SAL_NO_ACQUIRE );
503 : : }
504 : 0 : else if( args[i].Name.matchIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "port" ) ) )
505 : : {
506 : 0 : keywords.push_back( "port", SAL_NO_ACQUIRE );
507 : : }
508 : 0 : else if( args[i].Name.matchIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "dbname" ) ) )
509 : : {
510 : 0 : keywords.push_back( "dbname", SAL_NO_ACQUIRE );
511 : : }
512 : 0 : else if( args[i].Name.matchIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "connect_timeout" ) ) )
513 : : {
514 : 0 : keywords.push_back( "connect_timeout", SAL_NO_ACQUIRE );
515 : : }
516 : 0 : else if( args[i].Name.matchIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "options" ) ) )
517 : : {
518 : 0 : keywords.push_back( "options", SAL_NO_ACQUIRE );
519 : : }
520 : 0 : else if( args[i].Name.matchIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "requiressl" ) ) )
521 : : {
522 : 0 : keywords.push_back( "requiressl", SAL_NO_ACQUIRE );
523 : : }
524 : : else
525 : : {
526 : 0 : append = false;
527 : : // ignore for now
528 : : OSL_TRACE("sdbc-postgresql: unknown argument '%s'", ::rtl::OUStringToOString( args[i].Name, RTL_TEXTENCODING_UTF8 ).getStr() );
529 : : }
530 : 0 : if( append )
531 : : {
532 : 0 : OUString value;
533 : 0 : tc->convertTo( args[i].Value, getCppuType( &value) ) >>= value;
534 : 0 : char *v = strdup(rtl::OUStringToOString(value, enc).getStr());
535 : 0 : values.push_back ( v );
536 : : }
537 : : }
538 : 0 : }
539 : :
540 : 0 : void Connection::initialize( const Sequence< Any >& aArguments )
541 : : throw (Exception, RuntimeException)
542 : : {
543 : 0 : OUString url;
544 : 0 : Sequence< PropertyValue > args;
545 : :
546 : 0 : Reference< XTypeConverter > tc( m_ctx->getServiceManager()->createInstanceWithContext(
547 : 0 : OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.script.Converter" ) ), m_ctx ),
548 : 0 : UNO_QUERY);
549 : 0 : if( ! tc.is() )
550 : : {
551 : : throw RuntimeException(
552 : : OUString( RTL_CONSTASCII_USTRINGPARAM("pq_driver: Couldn't instantiate converter service" )),
553 : 0 : Reference< XInterface > () );
554 : : }
555 : 0 : if( aArguments.getLength() != 2 )
556 : : {
557 : 0 : OUStringBuffer buf(128);
558 : 0 : buf.appendAscii( "pq_driver: expected 2 arguments, got " );
559 : 0 : buf.append( aArguments.getLength( ) );
560 : 0 : throw IllegalArgumentException(buf.makeStringAndClear(), Reference< XInterface > () , 0 );
561 : : }
562 : :
563 : 0 : if( ! (aArguments[0] >>= url) )
564 : : {
565 : 0 : OUStringBuffer buf(128);
566 : 0 : buf.appendAscii( "pq_driver: expected string as first argument, got " );
567 : 0 : buf.append( aArguments[0].getValueType().getTypeName() );
568 : 0 : throw IllegalArgumentException( buf.makeStringAndClear() , *this, 0 );
569 : : }
570 : :
571 : 0 : tc->convertTo( aArguments[1], getCppuType( &args ) ) >>= args;
572 : :
573 : 0 : OString o;
574 : 0 : int nColon = url.indexOf( ':' );
575 : 0 : if( nColon != -1 )
576 : : {
577 : 0 : nColon = url.indexOf( ':' , 1+ nColon );
578 : 0 : if( nColon != -1 )
579 : : {
580 : 0 : o = OUStringToOString( url.getStr()+nColon+1, m_settings.encoding );
581 : : }
582 : : }
583 : : {
584 : 0 : cstr_vector keywords;
585 : 0 : cstr_vector values;
586 : :
587 : 0 : if ( o.getLength() > 0 )
588 : : {
589 : : char *err;
590 : 0 : boost::shared_ptr<PQconninfoOption> oOpts(PQconninfoParse(o.getStr(), &err), PQconninfoFree);
591 : 0 : if ( oOpts.get() == NULL )
592 : : {
593 : 0 : OUString errorMessage;
594 : 0 : if ( err != NULL)
595 : : {
596 : 0 : errorMessage = OUString( err, strlen(err), m_settings.encoding );
597 : 0 : free(err);
598 : : }
599 : : else
600 : 0 : errorMessage = OUString(RTL_CONSTASCII_USTRINGPARAM("#no error message#"));
601 : 0 : OUStringBuffer buf( 128 );
602 : 0 : buf.appendAscii( "Error in database URL '" );
603 : 0 : buf.append( url );
604 : 0 : buf.appendAscii( "':\n" );
605 : 0 : buf.append( errorMessage );
606 : : // HY092 is "Invalid attribute/option identifier."
607 : : // Just the most likely error; the error might be HY024 "Invalid attribute value".
608 : 0 : throw SQLException( buf.makeStringAndClear(), *this, OUString(RTL_CONSTASCII_USTRINGPARAM("HY092")), 5, Any() );
609 : : }
610 : :
611 : 0 : for ( PQconninfoOption * opt = oOpts.get(); opt->keyword != NULL; ++opt)
612 : : {
613 : 0 : if ( opt->val != NULL )
614 : : {
615 : 0 : keywords.push_back(strdup(opt->keyword));
616 : 0 : values.push_back(strdup(opt->val));
617 : : }
618 : 0 : }
619 : : }
620 : 0 : properties2arrays( args , tc, m_settings.encoding, keywords, values );
621 : 0 : keywords.push_back(NULL, SAL_NO_ACQUIRE);
622 : 0 : values.push_back(NULL, SAL_NO_ACQUIRE);
623 : :
624 : 0 : m_settings.pConnection = PQconnectdbParams( keywords.c_array(), values.c_array(), 0 );
625 : : }
626 : 0 : if( ! m_settings.pConnection )
627 : : throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM( "pq_driver: out of memory" ) ),
628 : 0 : Reference< XInterface > () );
629 : 0 : if( PQstatus( m_settings.pConnection ) == CONNECTION_BAD )
630 : : {
631 : 0 : OUStringBuffer buf( 128 );
632 : :
633 : 0 : const char * error = PQerrorMessage( m_settings.pConnection );
634 : 0 : OUString errorMessage( error, strlen( error) , RTL_TEXTENCODING_ASCII_US );
635 : 0 : buf.appendAscii( "Couldn't establish database connection to '" );
636 : 0 : buf.append( url );
637 : 0 : buf.appendAscii( "'\n" );
638 : 0 : buf.append( errorMessage );
639 : 0 : PQfinish( m_settings.pConnection );
640 : 0 : m_settings.pConnection = 0;
641 : 0 : throw SQLException( buf.makeStringAndClear(), *this, errorMessage, CONNECTION_BAD, Any() );
642 : : }
643 : 0 : PQsetClientEncoding( m_settings.pConnection, "UNICODE" );
644 : 0 : char *p = PQuser( m_settings.pConnection );
645 : 0 : m_settings.user = OUString( p, strlen(p), RTL_TEXTENCODING_UTF8);
646 : 0 : p = PQdb( m_settings.pConnection );
647 : 0 : m_settings.catalog = OUString( p, strlen(p), RTL_TEXTENCODING_UTF8);
648 : 0 : m_settings.tc = tc;
649 : :
650 : 0 : if( isLog( &m_settings, LogLevel::INFO ) )
651 : : {
652 : 0 : OUStringBuffer buf( 128 );
653 : 0 : buf.appendAscii( "connection to '" );
654 : 0 : buf.append( url );
655 : 0 : buf.appendAscii( "' successfully opened" );
656 : 0 : log( &m_settings, LogLevel::INFO, buf.makeStringAndClear() );
657 : 0 : }
658 : 0 : }
659 : :
660 : 0 : void Connection::disposing()
661 : : {
662 : 0 : close();
663 : 0 : }
664 : :
665 : 0 : void Connection::checkClosed() throw ( SQLException, RuntimeException )
666 : : {
667 : 0 : if( !m_settings.pConnection )
668 : : throw SQLException( ASCII_STR( "pq_connection: Connection already closed" ),
669 : 0 : *this, OUString(), 1, Any() );
670 : 0 : }
671 : :
672 : 0 : Reference< XNameAccess > Connection::getTables()
673 : : throw (::com::sun::star::uno::RuntimeException)
674 : : {
675 : 0 : if( isLog( &m_settings, LogLevel::INFO ) )
676 : : {
677 : 0 : log( &m_settings, LogLevel::INFO, "Connection::getTables() got called" );
678 : : }
679 : 0 : MutexGuard guard( m_refMutex->mutex );
680 : 0 : if( !m_settings.tables.is() )
681 : 0 : m_settings.tables = Tables::create( m_refMutex, this, &m_settings , &m_settings.pTablesImpl);
682 : : else
683 : : // TODO: how to overcome the performance problem ?
684 : 0 : Reference< com::sun::star::util::XRefreshable > ( m_settings.tables, UNO_QUERY )->refresh();
685 : 0 : return m_settings.tables;
686 : : }
687 : :
688 : 0 : Reference< XNameAccess > Connection::getViews()
689 : : throw (::com::sun::star::uno::RuntimeException)
690 : : {
691 : 0 : if( isLog( &m_settings, LogLevel::INFO ) )
692 : : {
693 : 0 : log( &m_settings, LogLevel::INFO, "Connection::getViews() got called" );
694 : : }
695 : 0 : MutexGuard guard( m_refMutex->mutex );
696 : 0 : if( !m_settings.views.is() )
697 : 0 : m_settings.views = Views::create( m_refMutex, this, &m_settings, &(m_settings.pViewsImpl) );
698 : : else
699 : : // TODO: how to overcome the performance problem ?
700 : 0 : Reference< com::sun::star::util::XRefreshable > ( m_settings.views, UNO_QUERY )->refresh();
701 : 0 : return m_settings.views;
702 : : }
703 : :
704 : :
705 : :
706 : 0 : Reference< XNameAccess > Connection::getUsers()
707 : : throw (::com::sun::star::uno::RuntimeException)
708 : : {
709 : 0 : if( isLog( &m_settings, LogLevel::INFO ) )
710 : : {
711 : 0 : log( &m_settings, LogLevel::INFO, "Connection::getUsers() got called" );
712 : : }
713 : :
714 : 0 : MutexGuard guard( m_refMutex->mutex );
715 : 0 : if( !m_settings.users.is() )
716 : 0 : m_settings.users = Users::create( m_refMutex, this, &m_settings );
717 : 0 : return m_settings.users;
718 : : }
719 : :
720 : :
721 : 0 : Reference< XInterface > ConnectionCreateInstance(
722 : : const Reference< XComponentContext > & ctx ) throw (Exception)
723 : : {
724 : 0 : ::rtl::Reference< RefCountedMutex > ref = new RefCountedMutex();
725 : 0 : return * new Connection( ref, ctx );
726 : : }
727 : :
728 : :
729 : :
730 : 0 : bool isLog( ConnectionSettings *settings, int loglevel )
731 : : {
732 : 0 : return settings->loglevel >= loglevel && settings->logFile;
733 : : }
734 : :
735 : 0 : void log( ConnectionSettings *settings, sal_Int32 level, const OUString &logString )
736 : : {
737 : 0 : log( settings, level, OUStringToOString( logString, settings->encoding ).getStr() );
738 : 0 : }
739 : 0 : void log( ConnectionSettings *settings, sal_Int32 level, const char *str )
740 : : {
741 : 0 : if( isLog( settings, level ) )
742 : : {
743 : : static const char *strLevel[] = { "NONE", "ERROR", "SQL", "INFO", "DATA" };
744 : :
745 : 0 : time_t t = ::time( 0 );
746 : : char *pString;
747 : : #ifdef SAL_W32
748 : : pString = asctime( localtime( &t ) );
749 : : #else
750 : : struct tm timestruc;
751 : : char timestr[50];
752 : 0 : memset( timestr, 0 , 50);
753 : 0 : pString = timestr;
754 : 0 : ::localtime_r( &t , ×truc );
755 : 0 : asctime_r( ×truc, timestr );
756 : : #endif
757 : 0 : for( int i = 0 ; pString[i] ; i ++ )
758 : : {
759 : 0 : if( pString[i] <= 13 )
760 : : {
761 : 0 : pString[i] = 0;
762 : 0 : break;
763 : : }
764 : : }
765 : 0 : fprintf( settings->logFile, "%s [%s]: %s\n", pString, strLevel[level], str );
766 : : }
767 : 0 : }
768 : :
769 : :
770 : : }
771 : :
772 : :
773 : :
774 : : static struct cppu::ImplementationEntry g_entries[] =
775 : : {
776 : : {
777 : : pq_sdbc_driver::ConnectionCreateInstance, pq_sdbc_driver::ConnectionGetImplementationName,
778 : : pq_sdbc_driver::ConnectionGetSupportedServiceNames, cppu::createSingleComponentFactory,
779 : : 0 , 0
780 : : },
781 : : { 0, 0, 0, 0, 0, 0 }
782 : : };
783 : :
784 : :
785 : : extern "C"
786 : : {
787 : :
788 : 0 : SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory(
789 : : const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
790 : : {
791 : 0 : return cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries );
792 : : }
793 : :
794 : : }
|