LCOV - code coverage report
Current view: top level - connectivity/source/drivers/postgresql - pq_connection.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 0 323 0.0 %
Date: 2014-04-11 Functions: 0 49 0.0 %
Legend: Lines: hit not hit

          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 , &timestruc );
     716           0 :         asctime_r( &timestruc, 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: */

Generated by: LCOV version 1.10