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