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 0 : fileName += "postgresql-sdbc.ini";
153 0 : rtl::Bootstrap bootstrapHandle( fileName );
154 :
155 0 : OUString str;
156 0 : if( bootstrapHandle.getFrom( "PQ_LOGLEVEL", str ) )
157 : {
158 0 : if ( str == "NONE" )
159 0 : loglevel = LogLevel::NONE;
160 0 : else if ( str == "ERROR" )
161 0 : loglevel = LogLevel::ERROR;
162 0 : else if ( str == "SQL" )
163 0 : loglevel = LogLevel::SQL;
164 0 : else if ( str == "INFO" )
165 0 : loglevel = LogLevel::INFO;
166 : else
167 : {
168 : fprintf( stderr, "unknown loglevel %s\n",
169 0 : OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
170 : }
171 : }
172 0 : return loglevel;
173 : }
174 :
175 0 : Connection::Connection(
176 : const rtl::Reference< RefCountedMutex > &refMutex,
177 : const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > & ctx )
178 0 : : ConnectionBase( refMutex->mutex ),
179 : m_ctx( ctx ) ,
180 0 : m_refMutex( refMutex )
181 : {
182 0 : m_settings.loglevel = readLogLevelFromConfiguration();
183 :
184 0 : if( m_settings.loglevel > LogLevel::NONE )
185 : {
186 0 : m_settings.logFile = fopen( "sdbc-pqsql.log", "a" );
187 0 : if( m_settings.logFile )
188 : {
189 0 : setvbuf( m_settings.logFile, 0, _IONBF, 0 );
190 0 : log( &m_settings, m_settings.loglevel , "set this loglevel" );
191 : }
192 : else
193 : {
194 0 : fprintf( stderr, "Couldn't open sdbc-pqsql.log file\n" );
195 : }
196 : }
197 0 : }
198 :
199 0 : Connection::~Connection()
200 : {
201 : POSTGRE_TRACE( "dtor connection" );
202 0 : if( m_settings.pConnection )
203 : {
204 0 : PQfinish( m_settings.pConnection );
205 0 : m_settings.pConnection = 0;
206 : }
207 0 : if( m_settings.logFile )
208 : {
209 0 : fclose( m_settings.logFile );
210 0 : m_settings.logFile = 0;
211 : }
212 0 : }
213 : typedef ::std::list< ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XCloseable > ,
214 : ::pq_sdbc_driver::Allocator < ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XCloseable > > > CloseableList;
215 :
216 : typedef ::std::list< ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > ,
217 : ::pq_sdbc_driver::Allocator < ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > > > DisposeableList;
218 :
219 0 : void Connection::close() throw ( SQLException, RuntimeException, std::exception )
220 : {
221 0 : CloseableList lst;
222 0 : DisposeableList lstDispose;
223 : {
224 0 : MutexGuard guard( m_refMutex->mutex );
225 : // silently ignore, if the connection has been closed already
226 0 : if( m_settings.pConnection )
227 : {
228 0 : log( &m_settings, LogLevel::INFO, "closing connection" );
229 0 : PQfinish( m_settings.pConnection );
230 0 : m_settings.pConnection = 0;
231 : }
232 :
233 0 : lstDispose.push_back( Reference< XComponent > ( m_settings.users, UNO_QUERY ) );
234 0 : lstDispose.push_back( Reference< XComponent > ( m_settings.tables , UNO_QUERY ) );
235 0 : lstDispose.push_back( Reference< XComponent > ( m_meta, UNO_QUERY ) );
236 0 : m_meta.clear();
237 0 : m_settings.tables.clear();
238 0 : m_settings.users.clear();
239 :
240 0 : for( WeakHashMap::iterator ii = m_myStatements.begin() ;
241 0 : ii != m_myStatements.end() ;
242 : ++ii )
243 : {
244 0 : Reference< XCloseable > r = ii->second;
245 0 : if( r.is() )
246 0 : lst.push_back( r );
247 0 : }
248 : }
249 :
250 : // close all created statements
251 0 : for( CloseableList::iterator ii = lst.begin(); ii != lst.end() ; ++ii )
252 0 : ii->get()->close();
253 :
254 : // close all created statements
255 0 : for( DisposeableList::iterator iiDispose = lstDispose.begin();
256 0 : iiDispose != lstDispose.end() ; ++iiDispose )
257 : {
258 0 : if( iiDispose->is() )
259 0 : iiDispose->get()->dispose();
260 0 : }
261 0 : }
262 :
263 :
264 0 : void Connection::removeFromWeakMap( const ::rtl::ByteSequence & id )
265 : {
266 : // shrink the list !
267 0 : MutexGuard guard( m_refMutex->mutex );
268 0 : WeakHashMap::iterator ii = m_myStatements.find( id );
269 0 : if( ii != m_myStatements.end() )
270 0 : m_myStatements.erase( ii );
271 0 : }
272 :
273 0 : Reference< XStatement > Connection::createStatement() throw (SQLException, RuntimeException, std::exception)
274 : {
275 0 : MutexGuard guard( m_refMutex->mutex );
276 0 : checkClosed();
277 :
278 0 : Statement *stmt = new Statement( m_refMutex, this , &m_settings );
279 0 : Reference< XStatement > ret( stmt );
280 0 : ::rtl::ByteSequence id( 16 );
281 0 : rtl_createUuid( (sal_uInt8*) id.getConstArray(), 0 , sal_False );
282 0 : m_myStatements[ id ] = Reference< XCloseable > ( stmt );
283 0 : stmt->queryAdapter()->addReference( new ClosableReference( id, this ) );
284 0 : return ret;
285 : }
286 :
287 0 : Reference< XPreparedStatement > Connection::prepareStatement( const OUString& sql )
288 : throw (SQLException, RuntimeException, std::exception)
289 : {
290 0 : MutexGuard guard( m_refMutex->mutex );
291 0 : checkClosed();
292 :
293 0 : OString byteSql = OUStringToOString( sql, m_settings.encoding );
294 0 : PreparedStatement *stmt = new PreparedStatement( m_refMutex, this, &m_settings, byteSql );
295 0 : Reference< XPreparedStatement > ret = stmt;
296 :
297 0 : ::rtl::ByteSequence id( 16 );
298 0 : rtl_createUuid( (sal_uInt8*) id.getConstArray(), 0 , sal_False );
299 0 : m_myStatements[ id ] = Reference< XCloseable > ( stmt );
300 0 : stmt->queryAdapter()->addReference( new ClosableReference( id, this ) );
301 0 : return ret;
302 : }
303 :
304 0 : Reference< XPreparedStatement > Connection::prepareCall( const OUString& )
305 : throw (SQLException, RuntimeException, std::exception)
306 : {
307 : throw SQLException(
308 : OUString( "pq_driver: Callable statements not supported" ),
309 0 : Reference< XInterface > (), OUString() , 1, Any() );
310 : }
311 :
312 :
313 0 : OUString Connection::nativeSQL( const OUString& sql )
314 : throw (SQLException, RuntimeException, std::exception)
315 : {
316 0 : return sql;
317 : }
318 :
319 0 : void Connection::setAutoCommit( sal_Bool ) throw (SQLException, RuntimeException, std::exception)
320 : {
321 : // UNSUPPORTED
322 0 : }
323 :
324 0 : sal_Bool Connection::getAutoCommit() throw (SQLException, RuntimeException, std::exception)
325 : {
326 : // UNSUPPORTED
327 0 : return sal_True;
328 : }
329 :
330 0 : void Connection::commit() throw (SQLException, RuntimeException, std::exception)
331 : {
332 : // UNSUPPORTED
333 0 : }
334 :
335 0 : void Connection::rollback() throw (SQLException, RuntimeException, std::exception)
336 : {
337 : // UNSUPPORTED
338 0 : }
339 :
340 0 : sal_Bool Connection::isClosed() throw (SQLException, RuntimeException, std::exception)
341 : {
342 0 : return m_settings.pConnection == 0;
343 : }
344 :
345 0 : Reference< XDatabaseMetaData > Connection::getMetaData()
346 : throw (SQLException, RuntimeException, std::exception)
347 : {
348 0 : MutexGuard guard( m_refMutex->mutex );
349 0 : checkClosed();
350 0 : if( ! m_meta.is() )
351 0 : m_meta = new DatabaseMetaData( m_refMutex, this, &m_settings );
352 0 : return m_meta;
353 : }
354 :
355 0 : void Connection::setReadOnly( sal_Bool ) throw (SQLException, RuntimeException, std::exception)
356 : {
357 : // UNSUPPORTED
358 :
359 0 : }
360 :
361 0 : sal_Bool Connection::isReadOnly() throw (SQLException, RuntimeException, std::exception)
362 : {
363 : // UNSUPPORTED
364 0 : return sal_False;
365 : }
366 :
367 0 : void Connection::setCatalog( const OUString& )
368 : throw (SQLException, RuntimeException, std::exception)
369 : {
370 : // UNSUPPORTED
371 0 : }
372 :
373 0 : OUString Connection::getCatalog() throw (SQLException, RuntimeException, std::exception)
374 : {
375 0 : MutexGuard guard( m_refMutex->mutex );
376 0 : if( m_settings.pConnection == 0 )
377 : {
378 : throw SQLException( "pq_connection: connection is closed", *this,
379 0 : OUString(), 1, Any() );
380 : }
381 0 : char * p = PQdb(m_settings.pConnection );
382 0 : return OUString( p, strlen(p) , m_settings.encoding );
383 : }
384 :
385 0 : void Connection::setTransactionIsolation( sal_Int32 )
386 : throw (SQLException, RuntimeException, std::exception)
387 : {
388 : // UNSUPPORTED
389 0 : }
390 :
391 0 : sal_Int32 Connection::getTransactionIsolation() throw (SQLException, RuntimeException, std::exception)
392 : {
393 : // UNSUPPORTED
394 0 : return 0;
395 : }
396 :
397 0 : Reference< XNameAccess > Connection::getTypeMap() throw (SQLException, RuntimeException, std::exception)
398 : {
399 0 : Reference< XNameAccess > t;
400 : {
401 0 : MutexGuard guard( m_refMutex->mutex );
402 0 : t = m_typeMap;
403 : }
404 0 : return t;
405 : }
406 :
407 0 : void Connection::setTypeMap( const Reference< XNameAccess >& typeMap )
408 : throw (SQLException, RuntimeException, std::exception)
409 : {
410 0 : MutexGuard guard( m_refMutex->mutex );
411 0 : m_typeMap = typeMap;
412 0 : }
413 0 : Any Connection::getWarnings() throw (SQLException, RuntimeException, std::exception)
414 : {
415 0 : return Any();
416 : }
417 :
418 0 : void Connection::clearWarnings() throw (SQLException, RuntimeException, std::exception)
419 : {
420 0 : }
421 :
422 : class cstr_vector
423 : {
424 : std::vector<char*> values;
425 : std::vector<bool> acquired;
426 : public:
427 0 : cstr_vector () : values(), acquired() { values.reserve(8); acquired.reserve(8); }
428 0 : ~cstr_vector ()
429 0 : {
430 : OSL_ENSURE(values.size() == acquired.size(), "pq_connection: cstr_vector values and acquired size mismatch");
431 0 : std::vector<char*>::iterator pv = values.begin();
432 0 : std::vector<bool>::iterator pa = acquired.begin();
433 0 : const std::vector<char*>::iterator pve = values.end();
434 0 : for( ; pv < pve ; ++pv, ++pa )
435 0 : if (*pa)
436 0 : free(*pv);
437 0 : }
438 0 : void push_back(const char* s, __sal_NoAcquire)
439 : {
440 0 : values.push_back(const_cast<char*>(s));
441 0 : acquired.push_back(false);
442 0 : }
443 0 : void push_back(char* s)
444 : {
445 0 : values.push_back(s);
446 0 : acquired.push_back(true);
447 0 : }
448 : // This const_cast is there for compatibility with PostgreSQL <= 9.1;
449 : // PostgreSQL >= 9.2 has the right const qualifiers in the headers
450 : // for a return type of "char const*const*".
451 0 : char const** c_array() const { return const_cast <const char**>(&values[0]); }
452 : };
453 :
454 0 : static void properties2arrays( const Sequence< PropertyValue > & args,
455 : const Reference< XTypeConverter> &tc,
456 : rtl_TextEncoding enc,
457 : cstr_vector &keywords,
458 : cstr_vector &values)
459 : {
460 : // LEM TODO: can we just blindly take all properties?
461 : // I.e. they are prefiltered to have only relevant ones?
462 : // Else, at least support all keywords from
463 : // http://www.postgresql.org/docs/9.0/interactive/libpq-connect.html
464 :
465 : static const char* keyword_list[] = {
466 : "password",
467 : "user",
468 : "port",
469 : "dbname",
470 : "connect_timeout",
471 : "options",
472 : "requiressl"
473 : };
474 :
475 0 : for( int i = 0; i < args.getLength() ; ++i )
476 : {
477 0 : bool append = false;
478 0 : for( size_t j = 0; j < SAL_N_ELEMENTS( keyword_list ); j++)
479 : {
480 0 : if( args[i].Name.equalsIgnoreAsciiCaseAscii( keyword_list[j] ))
481 : {
482 0 : keywords.push_back( keyword_list[j], SAL_NO_ACQUIRE );
483 0 : append = true;
484 0 : break;
485 : }
486 : }
487 :
488 0 : if( append )
489 : {
490 0 : OUString value;
491 0 : tc->convertTo( args[i].Value, getCppuType( &value) ) >>= value;
492 0 : char *v = strdup(OUStringToOString(value, enc).getStr());
493 0 : values.push_back ( v );
494 : }
495 : else
496 : {
497 : // ignore for now
498 : OSL_TRACE("sdbc-postgresql: unknown argument '%s'", OUStringToOString( args[i].Name, RTL_TEXTENCODING_UTF8 ).getStr() );
499 : }
500 : }
501 0 : }
502 :
503 0 : void Connection::initialize( const Sequence< Any >& aArguments )
504 : throw (Exception, RuntimeException, std::exception)
505 : {
506 0 : OUString url;
507 0 : Sequence< PropertyValue > args;
508 :
509 0 : Reference< XTypeConverter > tc( Converter::create(m_ctx) );
510 0 : if( ! tc.is() )
511 : {
512 : throw RuntimeException(
513 : OUString("pq_driver: Couldn't instantiate converter service" ),
514 0 : Reference< XInterface > () );
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 : throw RuntimeException("pq_driver: out of memory",
589 0 : Reference< XInterface > () );
590 0 : if( PQstatus( m_settings.pConnection ) == CONNECTION_BAD )
591 : {
592 0 : OUStringBuffer buf( 128 );
593 :
594 0 : const char * error = PQerrorMessage( m_settings.pConnection );
595 0 : OUString errorMessage( error, strlen( error) , RTL_TEXTENCODING_ASCII_US );
596 0 : buf.appendAscii( "Couldn't establish database connection to '" );
597 0 : buf.append( url );
598 0 : buf.appendAscii( "'\n" );
599 0 : buf.append( errorMessage );
600 0 : PQfinish( m_settings.pConnection );
601 0 : m_settings.pConnection = 0;
602 0 : throw SQLException( buf.makeStringAndClear(), *this, errorMessage, CONNECTION_BAD, Any() );
603 : }
604 0 : PQsetClientEncoding( m_settings.pConnection, "UNICODE" );
605 0 : char *p = PQuser( m_settings.pConnection );
606 0 : m_settings.user = OUString( p, strlen(p), RTL_TEXTENCODING_UTF8);
607 0 : p = PQdb( m_settings.pConnection );
608 0 : m_settings.catalog = OUString( p, strlen(p), RTL_TEXTENCODING_UTF8);
609 0 : m_settings.tc = tc;
610 :
611 0 : if( isLog( &m_settings, LogLevel::INFO ) )
612 : {
613 0 : OUStringBuffer buf( 128 );
614 0 : buf.appendAscii( "connection to '" );
615 0 : buf.append( url );
616 0 : buf.appendAscii( "' successfully opened" );
617 0 : log( &m_settings, LogLevel::INFO, buf.makeStringAndClear() );
618 0 : }
619 0 : }
620 :
621 0 : void Connection::disposing()
622 : {
623 0 : close();
624 0 : }
625 :
626 0 : void Connection::checkClosed() throw ( SQLException, RuntimeException )
627 : {
628 0 : if( !m_settings.pConnection )
629 : throw SQLException( "pq_connection: Connection already closed",
630 0 : *this, OUString(), 1, Any() );
631 0 : }
632 :
633 0 : Reference< XNameAccess > Connection::getTables()
634 : throw (::com::sun::star::uno::RuntimeException, std::exception)
635 : {
636 0 : if( isLog( &m_settings, LogLevel::INFO ) )
637 : {
638 0 : log( &m_settings, LogLevel::INFO, "Connection::getTables() got called" );
639 : }
640 0 : MutexGuard guard( m_refMutex->mutex );
641 0 : if( !m_settings.tables.is() )
642 0 : m_settings.tables = Tables::create( m_refMutex, this, &m_settings , &m_settings.pTablesImpl);
643 : else
644 : // TODO: how to overcome the performance problem ?
645 0 : Reference< com::sun::star::util::XRefreshable > ( m_settings.tables, UNO_QUERY )->refresh();
646 0 : return m_settings.tables;
647 : }
648 :
649 0 : Reference< XNameAccess > Connection::getViews()
650 : throw (::com::sun::star::uno::RuntimeException, std::exception)
651 : {
652 0 : if( isLog( &m_settings, LogLevel::INFO ) )
653 : {
654 0 : log( &m_settings, LogLevel::INFO, "Connection::getViews() got called" );
655 : }
656 0 : MutexGuard guard( m_refMutex->mutex );
657 0 : if( !m_settings.views.is() )
658 0 : m_settings.views = Views::create( m_refMutex, this, &m_settings, &(m_settings.pViewsImpl) );
659 : else
660 : // TODO: how to overcome the performance problem ?
661 0 : Reference< com::sun::star::util::XRefreshable > ( m_settings.views, UNO_QUERY )->refresh();
662 0 : return m_settings.views;
663 : }
664 :
665 :
666 :
667 0 : Reference< XNameAccess > Connection::getUsers()
668 : throw (::com::sun::star::uno::RuntimeException, std::exception)
669 : {
670 0 : if( isLog( &m_settings, LogLevel::INFO ) )
671 : {
672 0 : log( &m_settings, LogLevel::INFO, "Connection::getUsers() got called" );
673 : }
674 :
675 0 : MutexGuard guard( m_refMutex->mutex );
676 0 : if( !m_settings.users.is() )
677 0 : m_settings.users = Users::create( m_refMutex, this, &m_settings );
678 0 : return m_settings.users;
679 : }
680 :
681 :
682 0 : Reference< XInterface > ConnectionCreateInstance(
683 : const Reference< XComponentContext > & ctx ) throw (Exception)
684 : {
685 0 : ::rtl::Reference< RefCountedMutex > ref = new RefCountedMutex();
686 0 : return * new Connection( ref, ctx );
687 : }
688 :
689 :
690 :
691 0 : bool isLog( ConnectionSettings *settings, int loglevel )
692 : {
693 0 : return settings->loglevel >= loglevel && settings->logFile;
694 : }
695 :
696 0 : void log( ConnectionSettings *settings, sal_Int32 level, const OUString &logString )
697 : {
698 0 : log( settings, level, OUStringToOString( logString, settings->encoding ).getStr() );
699 0 : }
700 0 : void log( ConnectionSettings *settings, sal_Int32 level, const char *str )
701 : {
702 0 : if( isLog( settings, level ) )
703 : {
704 : static const char *strLevel[] = { "NONE", "ERROR", "SQL", "INFO", "DATA" };
705 :
706 0 : time_t t = ::time( 0 );
707 : char *pString;
708 : #ifdef SAL_W32
709 : pString = asctime( localtime( &t ) );
710 : #else
711 : struct tm timestruc;
712 : char timestr[50];
713 0 : memset( timestr, 0 , 50);
714 0 : pString = timestr;
715 0 : ::localtime_r( &t , ×truc );
716 0 : asctime_r( ×truc, timestr );
717 : #endif
718 0 : for( int i = 0 ; pString[i] ; i ++ )
719 : {
720 0 : if( pString[i] <= 13 )
721 : {
722 0 : pString[i] = 0;
723 0 : break;
724 : }
725 : }
726 0 : fprintf( settings->logFile, "%s [%s]: %s\n", pString, strLevel[level], str );
727 : }
728 0 : }
729 :
730 :
731 : }
732 :
733 :
734 :
735 : static const struct cppu::ImplementationEntry g_entries[] =
736 : {
737 : {
738 : pq_sdbc_driver::ConnectionCreateInstance, pq_sdbc_driver::ConnectionGetImplementationName,
739 : pq_sdbc_driver::ConnectionGetSupportedServiceNames, cppu::createSingleComponentFactory,
740 : 0 , 0
741 : },
742 : { 0, 0, 0, 0, 0, 0 }
743 : };
744 :
745 :
746 : extern "C"
747 : {
748 :
749 0 : SAL_DLLPUBLIC_EXPORT void * SAL_CALL postgresql_sdbc_impl_component_getFactory(
750 : const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
751 : {
752 0 : return cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries );
753 : }
754 :
755 : }
756 :
757 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|