diff options
Diffstat (limited to 'connectivity/source/drivers/postgresql')
68 files changed, 18151 insertions, 0 deletions
diff --git a/connectivity/source/drivers/postgresql/postgresql-sdbc-impl.component b/connectivity/source/drivers/postgresql/postgresql-sdbc-impl.component new file mode 100644 index 000000000..8c5a6ff05 --- /dev/null +++ b/connectivity/source/drivers/postgresql/postgresql-sdbc-impl.component @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="org.openoffice.comp.connectivity.pq.Connection.noext" + constructor="connectivity_postgresql_Connection_get_implementation"> + <service name="com.sun.star.sdbc.Connection"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/postgresql/postgresql-sdbc.component b/connectivity/source/drivers/postgresql/postgresql-sdbc.component new file mode 100644 index 000000000..a14ab2c96 --- /dev/null +++ b/connectivity/source/drivers/postgresql/postgresql-sdbc.component @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="org.openoffice.comp.connectivity.pq.Driver.noext" + constructor="connectivity_pq_sdbc_driver_get_implementation" single-instance="true"> + <service name="com.sun.star.sdbc.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/postgresql/pq_array.cxx b/connectivity/source/drivers/postgresql/pq_array.cxx new file mode 100644 index 000000000..841ed70c6 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_array.cxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <comphelper/sequence.hxx> + + +#include "pq_array.hxx" +#include "pq_statics.hxx" +#include "pq_sequenceresultset.hxx" + + +using com::sun::star::sdbc::SQLException; +using com::sun::star::uno::Any; + +using com::sun::star::uno::Sequence; +namespace pq_sdbc_driver +{ + + +OUString Array::getBaseTypeName( ) +{ + return "varchar"; +} + +sal_Int32 Array::getBaseType( ) +{ + return css::sdbc::DataType::VARCHAR; +} + +css::uno::Sequence< css::uno::Any > Array::getArray( + const css::uno::Reference< css::container::XNameAccess >& /* typeMap */ ) +{ + return comphelper::containerToSequence(m_data); +} + +css::uno::Sequence< css::uno::Any > Array::getArrayAtIndex( + sal_Int32 index, + sal_Int32 count, + const css::uno::Reference< css::container::XNameAccess >& /* typeMap */ ) +{ + checkRange( index, count ); + return Sequence< Any > ( &m_data[index-1], count ); +} + +css::uno::Reference< css::sdbc::XResultSet > Array::getResultSet( + const css::uno::Reference< css::container::XNameAccess >& typeMap ) +{ + return getResultSetAtIndex( 0 , m_data.size() , typeMap ); +} + +css::uno::Reference< css::sdbc::XResultSet > Array::getResultSetAtIndex( + sal_Int32 index, + sal_Int32 count, + const css::uno::Reference< css::container::XNameAccess >& /* typeMap */ ) +{ + checkRange( index, count ); + std::vector< std::vector< Any > > ret( count ); + + for( int i = 0 ; i < count ; i ++ ) + { + std::vector< Any > row( 2 ); + row[0] <<= static_cast<sal_Int32>( i + index ); + row[1] = m_data[i+index-1]; + ret[i] = row; + } + + return new SequenceResultSet( + m_xMutex, m_owner, std::vector(getStatics().resultSetArrayColumnNames), std::move(ret), m_tc ); +} + + +void Array::checkRange( sal_Int32 index, sal_Int32 count ) +{ + if( index >= 1 && index -1 + count <= static_cast<sal_Int32>(m_data.size()) ) + return; + throw SQLException( + "Array::getArrayAtIndex(): allowed range for index + count " + + OUString::number( m_data.size() ) + + ", got " + OUString::number( index ) + + " + " + OUString::number( count ), + *this, OUString(), 1, Any()); + +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_array.hxx b/connectivity/source/drivers/postgresql/pq_array.hxx new file mode 100644 index 000000000..b847d646a --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_array.hxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/sdbc/XArray.hpp> + +#include "pq_connection.hxx" +#include <vector> + +namespace pq_sdbc_driver +{ + +class Array : public cppu::WeakImplHelper< css::sdbc::XArray > +{ + std::vector< css::uno::Any > m_data; + css::uno::Reference< css::uno::XInterface > m_owner; + css::uno::Reference< css::script::XTypeConverter > m_tc; + rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + +public: + Array( + const rtl::Reference< comphelper::RefCountedMutex > & mutex, + std::vector< css::uno::Any > && data, + const css::uno::Reference< css::uno::XInterface > & owner, + const css::uno::Reference< css::script::XTypeConverter > &tc) : + m_data( std::move(data) ), + m_owner( owner ), + m_tc( tc ), + m_xMutex( mutex ) + {} + +public: // XArray + + // Methods + virtual OUString SAL_CALL getBaseTypeName( ) override; + + virtual sal_Int32 SAL_CALL getBaseType( ) override; + + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getArray( + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getArrayAtIndex( + sal_Int32 index, + sal_Int32 count, + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL + getResultSet( + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSetAtIndex( + sal_Int32 index, + sal_Int32 count, + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + +private: + void checkRange( sal_Int32 index, sal_Int32 count ); +}; + + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_baseresultset.cxx b/connectivity/source/drivers/postgresql/pq_baseresultset.cxx new file mode 100644 index 000000000..9ff5e01e0 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_baseresultset.cxx @@ -0,0 +1,613 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <comphelper/sequence.hxx> + +#include "pq_tools.hxx" +#include "pq_array.hxx" +#include "pq_baseresultset.hxx" + +#include <com/sun/star/script/CannotConvertException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <connectivity/dbconversion.hxx> + +using osl::MutexGuard; + + +using com::sun::star::beans::XPropertySetInfo; + +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; + +using com::sun::star::lang::IllegalArgumentException; + +using com::sun::star::sdbc::SQLException; + + +using com::sun::star::beans::Property; + +using namespace dbtools; + +namespace pq_sdbc_driver +{ +static ::cppu::IPropertyArrayHelper & getResultSetPropertyArrayHelper() +{ + // LEM TODO: this needs to be kept in sync with other, e.g. pq_statics.css:508 + // Should really share! + // At least use for the handles the #define'd values in .hxx file... + static ::cppu::OPropertyArrayHelper arrayHelper( + Sequence<Property>{ + Property( + "CursorName", 0, + ::cppu::UnoType<OUString>::get() , 0 ), + Property( + "EscapeProcessing", 1, + cppu::UnoType<bool>::get() , 0 ), + Property( + "FetchDirection", 2, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "FetchSize", 3, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "IsBookmarkable", 4, + cppu::UnoType<bool>::get() , 0 ), + Property( + "ResultSetConcurrency", 5, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "ResultSetType", 6, + ::cppu::UnoType<sal_Int32>::get() , 0 )}, + true ); + return arrayHelper; +} + +BaseResultSet::BaseResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< XInterface > & owner, + sal_Int32 rowCount, + sal_Int32 colCount, + const Reference< css::script::XTypeConverter > & tc ) + : BaseResultSet_BASE( refMutex->GetMutex() ) + , OPropertySetHelper( BaseResultSet_BASE::rBHelper ) + , m_owner( owner ) + , m_tc( tc ) + , m_xMutex( refMutex ) + , m_row( -1 ) + , m_rowCount( rowCount ) + , m_fieldCount( colCount ) + , m_wasNull(false) +{ +} + +// LEM TODO: refMutex->GetMutex() should live longer than OComponentHelper, +// but calling OComponentHelper::dispose explicitly here calls +// BaseResultSet::~BaseResultSet in an infinite loop :( +BaseResultSet::~BaseResultSet() +{ +} + +Any BaseResultSet::queryInterface( const Type & rType ) +{ + Any aRet = BaseResultSet_BASE::queryInterface(rType); + return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType); +} + +// void BaseResultSet::close( ) throw (SQLException, RuntimeException) +// { +// Reference< XInterface > owner; +// { +// ResultSetGuard guard(*this); +// if( m_result ) +// { +// PQclear(m_result ); +// m_result = 0; +// m_row = -1; +// } +// owner = m_owner; +// m_owner.clear(); +// } +// } + +Sequence<Type > BaseResultSet::getTypes() +{ + static Sequence< Type > collection( + ::comphelper::concatSequences( + OPropertySetHelper::getTypes(), + BaseResultSet_BASE::getTypes())); + return collection; +} + +Sequence< sal_Int8> BaseResultSet::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// Reference< XResultSetMetaData > BaseResultSet::getMetaData( ) throw (SQLException, RuntimeException) +// { +// ResultSetGuard guard(*this); +// checkClosed(); +// return new ResultSetMetaData( m_xMutex, this, &m_result ); +// } + +sal_Bool BaseResultSet::next( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + m_row ++; + return m_row < m_rowCount; +} + +sal_Bool BaseResultSet::isBeforeFirst( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return m_row == -1; +} + +sal_Bool BaseResultSet::isAfterLast( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return m_row >= m_rowCount; +} + +sal_Bool BaseResultSet::isFirst( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return m_row == 0 && m_rowCount; +} + +sal_Bool BaseResultSet::isLast( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return m_row >= 0 && m_row + 1 == m_rowCount; +} + +void BaseResultSet::beforeFirst( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + m_row = -1; +} + +void BaseResultSet::afterLast( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + m_row = m_rowCount; +} + +sal_Bool BaseResultSet::first( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + bool bRet = ( m_rowCount > 0 ); + if( bRet ) + m_row = 0; + return bRet; +} + +sal_Bool BaseResultSet::last( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + bool bRet = ( m_rowCount > 0 ); + if( bRet ) + m_row = m_rowCount -1; + return bRet; +} + +sal_Int32 BaseResultSet::getRow( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return m_row +1; +} + +sal_Bool BaseResultSet::absolute( sal_Int32 row ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + if( row > 0 ) + { + m_row = row -1; + if( m_row > m_rowCount ) + m_row = m_rowCount; + } + else + { + m_row = m_rowCount + row; + if( m_row < -1 ) + m_row = -1; + } + return true; +} + +sal_Bool BaseResultSet::relative( sal_Int32 rows ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + m_row += rows; + + if( m_row > m_rowCount ) + m_row = m_rowCount; + else if ( m_row < -1 ) + m_row = -1; + return true; +} + +sal_Bool BaseResultSet::previous( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + bool bRet = ( m_row != -1 ); + if( bRet ) + m_row --; + return bRet; +} + +void BaseResultSet::refreshRow( ) +{ + // TODO: not supported for now +} + +sal_Bool BaseResultSet::rowUpdated( ) +{ + return false; +} + +sal_Bool BaseResultSet::rowInserted( ) +{ + return false; +} + +sal_Bool BaseResultSet::rowDeleted( ) +{ + return false; +} + +Reference< XInterface > BaseResultSet::getStatement() +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return m_owner; +} + + +//----------------- XRow interface ---------------------------------------------------- + +sal_Bool BaseResultSet::wasNull( ) +{ + return m_wasNull; +} + +Any BaseResultSet::convertTo( const Any & val , const Type & type ) +{ + Any aRet; + try + { + aRet = m_tc->convertTo( val , type ); + } + catch( css::lang::IllegalArgumentException & ) + {} + catch( css::script::CannotConvertException & ) + {} + return aRet; +} + +sal_Bool BaseResultSet::getBoolean( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + + OUString str = getString( columnIndex ); + + if( str.getLength() > 0 ) + { + switch(str[0]) + { + case '1': + case 't': + case 'T': + case 'y': + case 'Y': + + return true; + } + } + return false; +} + +sal_Int8 BaseResultSet::getByte( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + sal_Int8 b = 0; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(b)>::get()) >>= b; + return b; +} + +sal_Int16 BaseResultSet::getShort( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + sal_Int16 i = 0; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(i)>::get()) >>= i; + return i; +} + +OUString BaseResultSet::getString( sal_Int32 columnIndex ) +{ + MutexGuard guard(m_xMutex->GetMutex()); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + OUString ret; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(ret)>::get() ) >>= ret; +// printf( "BaseResultSet::getString() %s\n" , OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ).getStr() ); + return ret; +} + +sal_Int32 BaseResultSet::getInt( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + sal_Int32 i = 0; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(i)>::get()) >>= i; + return i; +} + +sal_Int64 BaseResultSet::getLong( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + sal_Int64 i = 0; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(i)>::get()) >>= i; + return i; +} + +float BaseResultSet::getFloat( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + float f = 0.; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(f)>::get()) >>= f; + return f; +} + +double BaseResultSet::getDouble( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + double d = 0.; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(d)>::get()) >>= d; + return d; +} + +Sequence< sal_Int8 > BaseResultSet::getBytes( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + + Sequence< sal_Int8 > ret; + OUString ustr; + if( ! (getValue( columnIndex ) >>= ustr) ) + m_wasNull = true; + else + { + // if this is a binary, it must contain escaped data ! + OString val = OUStringToOString( ustr, RTL_TEXTENCODING_ASCII_US ); + + size_t length; + char * res = reinterpret_cast<char*>(PQunescapeBytea( reinterpret_cast<unsigned char const *>(val.getStr()), &length)); + ret = Sequence< sal_Int8 > ( reinterpret_cast<sal_Int8*>(res), length ); + if( res ) + PQfreemem( res ); + } + return ret; +} + + +css::util::Date BaseResultSet::getDate( sal_Int32 columnIndex ) +{ + return DBTypeConversion::toDate( getString( columnIndex ) ); +} + +css::util::Time BaseResultSet::getTime( sal_Int32 columnIndex ) +{ + return DBTypeConversion::toTime( getString( columnIndex ) ); +} + +css::util::DateTime BaseResultSet::getTimestamp( sal_Int32 columnIndex ) +{ + return DBTypeConversion::toDateTime( getString( columnIndex ) ); +} + + // LEM TODO: these look like they are missing an actual implementation +Reference< css::io::XInputStream > BaseResultSet::getBinaryStream( sal_Int32 /* columnIndex */ ) +{ + return nullptr; +} + +Reference< css::io::XInputStream > BaseResultSet::getCharacterStream( sal_Int32 /* columnIndex */ ) +{ + return nullptr; +} + +Any BaseResultSet::getObject( + sal_Int32 /* columnIndex */, + const Reference< css::container::XNameAccess >& /* typeMap */ ) +{ + return Any(); +} + +Reference< css::sdbc::XRef > BaseResultSet::getRef( sal_Int32 /* columnIndex */ ) +{ + return Reference< css::sdbc::XRef > (); +} + +Reference< css::sdbc::XBlob > BaseResultSet::getBlob( sal_Int32 /* columnIndex */ ) +{ + return Reference< css::sdbc::XBlob > (); +} + +Reference< css::sdbc::XClob > BaseResultSet::getClob( sal_Int32 /* columnIndex */ ) +{ + return Reference< css::sdbc::XClob > (); +} + +Reference< css::sdbc::XArray > BaseResultSet::getArray( sal_Int32 columnIndex ) +{ + return new Array( m_xMutex, parseArray( getString( columnIndex ) ), *this, m_tc ); +} + +::cppu::IPropertyArrayHelper & BaseResultSet::getInfoHelper() +{ + return getResultSetPropertyArrayHelper(); +} + +sal_Bool BaseResultSet::convertFastPropertyValue( + Any & /* rConvertedValue */, Any & /* rOldValue */, sal_Int32 nHandle, const Any& rValue ) +{ + bool bRet; + switch( nHandle ) + { + case BASERESULTSET_CURSOR_NAME: + { + OUString val; + bRet = ( rValue >>= val ); + m_props[nHandle] <<= val; + break; + } + case BASERESULTSET_ESCAPE_PROCESSING: + case BASERESULTSET_IS_BOOKMARKABLE: + { + bool val(false); + bRet = ( rValue >>= val ); + m_props[nHandle] <<= val; + break; + } + case BASERESULTSET_FETCH_DIRECTION: + case BASERESULTSET_FETCH_SIZE: + case BASERESULTSET_RESULT_SET_CONCURRENCY: + case BASERESULTSET_RESULT_SET_TYPE: + { + sal_Int32 val; + bRet = ( rValue >>= val ); + m_props[nHandle] <<= val; + break; + } + default: + { + throw IllegalArgumentException( + "pq_resultset: Invalid property handle (" + OUString::number( nHandle ) + ")", + *this, 2 ); + } + } + return bRet; +} + + +void BaseResultSet::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle,const Any& rValue ) +{ + m_props[nHandle] = rValue; +} + +void BaseResultSet::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + rValue = m_props[nHandle]; +} + +Reference < XPropertySetInfo > BaseResultSet::getPropertySetInfo() +{ + return OPropertySetHelper::createPropertySetInfo( getResultSetPropertyArrayHelper() ); +} + +void BaseResultSet::disposing() +{ + close(); +} + +void BaseResultSet::checkColumnIndex(sal_Int32 index ) +{ + if( index < 1 || index > m_fieldCount ) + { + throw SQLException( + "pq_resultset: index out of range (" + + OUString::number( index ) + + ", allowed range is 1 to " + OUString::number( m_fieldCount ) + + ")", + *this, OUString(), 1, Any() ); + } + +} + +void BaseResultSet::checkRowIndex() +{ + if( m_row < 0 || m_row >= m_rowCount ) + { + throw SQLException( + "pq_baseresultset: row index out of range, allowed is 0 to " + OUString::number( m_rowCount -1 ) + + ", got " + OUString::number( m_row ), + *this, OUString(),1, Any() ); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_baseresultset.hxx b/connectivity/source/drivers/postgresql/pq_baseresultset.hxx new file mode 100644 index 000000000..90e6609a0 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_baseresultset.hxx @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/component.hxx> + +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include "pq_connection.hxx" + +namespace pq_sdbc_driver +{ + +const sal_Int32 BASERESULTSET_CURSOR_NAME = 0; +const sal_Int32 BASERESULTSET_ESCAPE_PROCESSING = 1; +const sal_Int32 BASERESULTSET_FETCH_DIRECTION = 2; +const sal_Int32 BASERESULTSET_FETCH_SIZE = 3; +const sal_Int32 BASERESULTSET_IS_BOOKMARKABLE = 4; +const sal_Int32 BASERESULTSET_RESULT_SET_CONCURRENCY = 5; +const sal_Int32 BASERESULTSET_RESULT_SET_TYPE = 6; + +#define BASERESULTSET_SIZE 7 + +typedef ::cppu::WeakComponentImplHelper< css::sdbc::XCloseable, + css::sdbc::XResultSetMetaDataSupplier, + css::sdbc::XResultSet, + css::sdbc::XRow, + css::sdbc::XColumnLocate + > BaseResultSet_BASE; +class BaseResultSet : public BaseResultSet_BASE, + public cppu::OPropertySetHelper +{ +protected: + css::uno::Any m_props[BASERESULTSET_SIZE]; + css::uno::Reference< css::uno::XInterface > m_owner; + css::uno::Reference< css::script::XTypeConverter > m_tc; + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + sal_Int32 m_row; + sal_Int32 m_rowCount; + sal_Int32 m_fieldCount; + bool m_wasNull; + +protected: + /** mutex should be locked before called + + @throws css::sdbc::SQLException + @throws css::uno::RuntimeException + */ + virtual void checkClosed() = 0; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkColumnIndex( sal_Int32 index ); + void checkRowIndex(); + + virtual css::uno::Any getValue( sal_Int32 columnIndex ) = 0; + css::uno::Any convertTo( + const css::uno::Any &str, const css::uno::Type &type ); + +protected: + BaseResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + sal_Int32 rowCount, + sal_Int32 columnCount, + const css::uno::Reference< css::script::XTypeConverter > &tc ); + virtual ~BaseResultSet() override; + +public: // XInterface + virtual void SAL_CALL acquire() noexcept override { BaseResultSet_BASE::acquire(); } + virtual void SAL_CALL release() noexcept override { BaseResultSet_BASE::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XCloseable +// virtual void SAL_CALL close( ) +// throw (css::sdbc::SQLException, css::uno::RuntimeException) = 0; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XResultSetMetaDataSupplier +// virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) +// throw (css::sdbc::SQLException, css::uno::RuntimeException) = 0; + +public: // XResultSet + // Methods + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement() override; + + +public: // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( + sal_Int32 columnIndex, + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + +public: // XColumnLocate +// virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) +// throw (css::sdbc::SQLException, css::uno::RuntimeException) = 0; + +public: // OPropertySetHelper + virtual cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + using ::cppu::OPropertySetHelper::getFastPropertyValue; + + void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle ) const override; + + // XPropertySet + css::uno::Reference < css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + +public: // OComponentHelper + virtual void SAL_CALL disposing() override; + + +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_connection.cxx b/connectivity/source/drivers/postgresql/pq_connection.cxx new file mode 100644 index 000000000..6661a97d5 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_connection.cxx @@ -0,0 +1,571 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <vector> +#include <string.h> + +#include <memory> + +#include "pq_connection.hxx" +#include "pq_statement.hxx" +#include "pq_tools.hxx" +#include "pq_preparedstatement.hxx" +#include "pq_databasemetadata.hxx" +#include "pq_xtables.hxx" +#include "pq_xviews.hxx" +#include "pq_xusers.hxx" + +#include <rtl/ref.hxx> +#include <rtl/uuid.h> +#include <sal/log.hxx> + +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/script/Converter.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +using osl::MutexGuard; + +using com::sun::star::container::XNameAccess; + +using com::sun::star::lang::XComponent; +using com::sun::star::lang::IllegalArgumentException; + +using com::sun::star::script::Converter; +using com::sun::star::script::XTypeConverter; + +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::Any; + +using com::sun::star::beans::PropertyValue; + +using com::sun::star::sdbc::XCloseable; +using com::sun::star::sdbc::SQLException; +using com::sun::star::sdbc::XPreparedStatement; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XDatabaseMetaData; + +namespace pq_sdbc_driver +{ + +namespace { + +// Helper class for statement lifetime management +class ClosableReference : public cppu::WeakImplHelper< css::uno::XReference > +{ + rtl::Reference<Connection> m_conn; + ::rtl::ByteSequence m_id; +public: + ClosableReference( const ::rtl::ByteSequence & id , Connection *that ) + : m_conn( that ), m_id( id ) + { + } + + virtual void SAL_CALL dispose() override + { + if( m_conn.is() ) + { + m_conn->removeFromWeakMap(m_id); + m_conn.clear(); + } + } +}; + +} + +Connection::Connection( + const rtl::Reference< comphelper::RefCountedMutex > &refMutex, + const css::uno::Reference< css::uno::XComponentContext > & ctx ) + : ConnectionBase( refMutex->GetMutex() ), + m_ctx( ctx ) , + m_xMutex( refMutex ) +{ +} + +Connection::~Connection() +{ + if( m_settings.pConnection ) + { + PQfinish( m_settings.pConnection ); + m_settings.pConnection = nullptr; + } +} + +void Connection::close() +{ + std::vector< css::uno::Reference< css::sdbc::XCloseable > > vectorCloseable; + std::vector< css::uno::Reference< css::lang::XComponent > > vectorDispose; + { + MutexGuard guard( m_xMutex->GetMutex() ); + // silently ignore, if the connection has been closed already + if( m_settings.pConnection ) + { + SAL_INFO("connectivity.postgresql", "closing connection"); + PQfinish( m_settings.pConnection ); + m_settings.pConnection = nullptr; + } + + vectorDispose.push_back( Reference< XComponent > ( m_settings.users, UNO_QUERY ) ); + vectorDispose.push_back( Reference< XComponent > ( m_settings.tables , UNO_QUERY ) ); + vectorDispose.push_back( Reference< XComponent > ( m_meta, UNO_QUERY ) ); + m_meta.clear(); + m_settings.tables.clear(); + m_settings.users.clear(); + + for (auto const& statement : m_myStatements) + { + Reference< XCloseable > r = statement.second; + if( r.is() ) + vectorCloseable.push_back( r ); + } + } + + // close all created statements + for (auto const& elem : vectorCloseable) + elem->close(); + + // close all created statements + for (auto const& elem : vectorDispose) + { + if( elem.is() ) + elem->dispose(); + } +} + + +void Connection::removeFromWeakMap( const ::rtl::ByteSequence & id ) +{ + // shrink the list ! + MutexGuard guard( m_xMutex->GetMutex() ); + WeakHashMap::iterator ii = m_myStatements.find( id ); + if( ii != m_myStatements.end() ) + m_myStatements.erase( ii ); +} + +Reference< XStatement > Connection::createStatement() +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + + rtl::Reference<Statement> stmt = new Statement( m_xMutex, this , &m_settings ); + ::rtl::ByteSequence id( 16 ); + rtl_createUuid( reinterpret_cast<sal_uInt8*>(id.getArray()), nullptr, false ); + m_myStatements[ id ] = Reference< XCloseable > ( stmt ); + stmt->queryAdapter()->addReference( new ClosableReference( id, this ) ); + return stmt; +} + +Reference< XPreparedStatement > Connection::prepareStatement( const OUString& sql ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + + OString byteSql = OUStringToOString( sql, ConnectionSettings::encoding ); + rtl::Reference<PreparedStatement> stmt + = new PreparedStatement( m_xMutex, this, &m_settings, byteSql ); + + ::rtl::ByteSequence id( 16 ); + rtl_createUuid( reinterpret_cast<sal_uInt8*>(id.getArray()), nullptr, false ); + m_myStatements[ id ] = Reference< XCloseable > ( stmt ); + stmt->queryAdapter()->addReference( new ClosableReference( id, this ) ); + return stmt; +} + +Reference< XPreparedStatement > Connection::prepareCall( const OUString& ) +{ + throw SQLException( + "pq_driver: Callable statements not supported", + Reference< XInterface > (), OUString() , 1, Any() ); +} + + +OUString Connection::nativeSQL( const OUString& sql ) +{ + return sql; +} + +void Connection::setAutoCommit( sal_Bool ) +{ + // UNSUPPORTED +} + +sal_Bool Connection::getAutoCommit() +{ + // UNSUPPORTED + return true; +} + +void Connection::commit() +{ + // UNSUPPORTED +} + +void Connection::rollback() +{ + // UNSUPPORTED +} + +sal_Bool Connection::isClosed() +{ + return m_settings.pConnection == nullptr; +} + +Reference< XDatabaseMetaData > Connection::getMetaData() +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + if( ! m_meta.is() ) + m_meta = new DatabaseMetaData( m_xMutex, this, &m_settings ); + return m_meta; +} + +void Connection::setReadOnly( sal_Bool ) +{ + // UNSUPPORTED + +} + +sal_Bool Connection::isReadOnly() +{ + // UNSUPPORTED + return false; +} + +void Connection::setCatalog( const OUString& ) +{ + // UNSUPPORTED +} + +OUString Connection::getCatalog() +{ + MutexGuard guard( m_xMutex->GetMutex() ); + if( m_settings.pConnection == nullptr ) + { + throw SQLException( "pq_connection: connection is closed", *this, + OUString(), 1, Any() ); + } + char * p = PQdb(m_settings.pConnection ); + return OUString( p, strlen(p) , ConnectionSettings::encoding ); +} + +void Connection::setTransactionIsolation( sal_Int32 ) +{ + // UNSUPPORTED +} + +sal_Int32 Connection::getTransactionIsolation() +{ + // UNSUPPORTED + return 0; +} + +Reference< XNameAccess > Connection::getTypeMap() +{ + Reference< XNameAccess > t; + { + MutexGuard guard( m_xMutex->GetMutex() ); + t = m_typeMap; + } + return t; +} + +void Connection::setTypeMap( const Reference< XNameAccess >& typeMap ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + m_typeMap = typeMap; +} +Any Connection::getWarnings() +{ + return Any(); +} + +void Connection::clearWarnings() +{ +} + +namespace { + +class cstr_vector +{ + std::vector<char*> values; + std::vector<bool> acquired; +public: + cstr_vector () { values.reserve(8); acquired.reserve(8); } + ~cstr_vector () + { + OSL_ENSURE(values.size() == acquired.size(), "pq_connection: cstr_vector values and acquired size mismatch"); + std::vector<bool>::const_iterator pa = acquired.begin(); + for( const auto& v : values ) + { + if (*pa) + free(v); + ++pa; + } + } + void push_back(const char* s, __sal_NoAcquire) + { + values.push_back(const_cast<char*>(s)); + acquired.push_back(false); + } + void push_back(char* s) + { + values.push_back(s); + acquired.push_back(true); + } + // This const_cast is there for compatibility with PostgreSQL <= 9.1; + // PostgreSQL >= 9.2 has the right const qualifiers in the headers + // for a return type of "char const*const*". + char const** c_array() const { return const_cast <const char**>(values.data()); } +}; + +} + +static void properties2arrays( const Sequence< PropertyValue > & args, + const Reference< XTypeConverter> &tc, + rtl_TextEncoding enc, + cstr_vector &keywords, + cstr_vector &values) +{ + // LEM TODO: can we just blindly take all properties? + // I.e. they are prefiltered to have only relevant ones? + // Else, at least support all keywords from + // http://www.postgresql.org/docs/9.0/interactive/libpq-connect.html + + static const char* keyword_list[] = { + "password", + "user", + "port", + "dbname", + "connect_timeout", + "options", + "requiressl" + }; + + for( PropertyValue const & prop : args ) + { + bool append = false; + for(const char* j : keyword_list) + { + if( prop.Name.equalsIgnoreAsciiCaseAscii( j )) + { + keywords.push_back( j, SAL_NO_ACQUIRE ); + append = true; + break; + } + } + + if( append ) + { + OUString value; + tc->convertTo( prop.Value, cppu::UnoType<decltype(value)>::get() ) >>= value; + char *v = strdup(OUStringToOString(value, enc).getStr()); + values.push_back ( v ); + } + else + { + // ignore for now + SAL_WARN("connectivity.postgresql", "sdbc-postgresql: unknown argument '" << prop.Name << "' having value: " << prop.Value ); + } + } +} + +void Connection::initialize( const Sequence< Any >& aArguments ) +{ + OUString url; + Sequence< PropertyValue > args; + + Reference< XTypeConverter > tc( Converter::create(m_ctx) ); + if( ! tc.is() ) + { + throw RuntimeException( + "pq_driver: Couldn't instantiate converter service" ); + } + if( aArguments.getLength() != 2 ) + { + throw IllegalArgumentException( + "pq_driver: expected 2 arguments, got " + OUString::number( aArguments.getLength( ) ), + Reference< XInterface > () , 0 ); + } + + if( ! (aArguments[0] >>= url) ) + { + throw IllegalArgumentException( + "pq_driver: expected string as first argument, got " + + aArguments[0].getValueType().getTypeName(), + *this, 0 ); + } + + tc->convertTo( aArguments[1], cppu::UnoType<decltype(args)>::get() ) >>= args; + + OString o; + int nColon = url.indexOf( ':' ); + if( nColon != -1 ) + { + nColon = url.indexOf( ':' , 1+ nColon ); + if( nColon != -1 ) + { + o = rtl::OUStringToOString( url.subView(nColon+1), ConnectionSettings::encoding ); + } + } + { + cstr_vector keywords; + cstr_vector values; + + if ( o.getLength() > 0 ) + { + char *err; + const std::unique_ptr<PQconninfoOption, deleter_from_fn<PQconninfoFree>> + oOpts(PQconninfoParse(o.getStr(), &err)); + if (oOpts == nullptr) + { + OUString errorMessage; + if ( err != nullptr) + { + errorMessage = OUString( err, strlen(err), ConnectionSettings::encoding ); + PQfreemem(err); + } + else + errorMessage = "#no error message#"; + // HY092 is "Invalid attribute/option identifier." + // Just the most likely error; the error might be HY024 "Invalid attribute value". + throw SQLException( + "Error in database URL '" + url + "':\n" + errorMessage, + *this, "HY092", 5, Any() ); + } + + for ( PQconninfoOption * opt = oOpts.get(); opt->keyword != nullptr; ++opt) + { + if ( opt->val != nullptr ) + { + keywords.push_back(strdup(opt->keyword)); + values.push_back(strdup(opt->val)); + } + } + } + properties2arrays( args , tc, ConnectionSettings::encoding, keywords, values ); + keywords.push_back(nullptr, SAL_NO_ACQUIRE); + values.push_back(nullptr, SAL_NO_ACQUIRE); + + m_settings.pConnection = PQconnectdbParams( keywords.c_array(), values.c_array(), 0 ); + } + if( ! m_settings.pConnection ) + throw RuntimeException("pq_driver: out of memory" ); + if( PQstatus( m_settings.pConnection ) == CONNECTION_BAD ) + { + const char * error = PQerrorMessage( m_settings.pConnection ); + OUString errorMessage( error, strlen( error) , RTL_TEXTENCODING_ASCII_US ); + PQfinish( m_settings.pConnection ); + m_settings.pConnection = nullptr; + throw SQLException( + "Couldn't establish database connection to '" + url + "'\n" + + errorMessage, + *this, errorMessage, CONNECTION_BAD, Any() ); + } + PQsetClientEncoding( m_settings.pConnection, "UNICODE" ); + char *p = PQuser( m_settings.pConnection ); + m_settings.user = OUString( p, strlen(p), RTL_TEXTENCODING_UTF8); + p = PQdb( m_settings.pConnection ); + m_settings.catalog = OUString( p, strlen(p), RTL_TEXTENCODING_UTF8); + m_settings.tc = tc; + + SAL_INFO("connectivity.postgresql", "connection to '" << url << "' successfully opened"); +} + +void Connection::disposing() +{ + close(); +} + +void Connection::checkClosed() +{ + if( !m_settings.pConnection ) + throw SQLException( "pq_connection: Connection already closed", + *this, OUString(), 1, Any() ); +} + +Reference< XNameAccess > Connection::getTables() +{ + SAL_INFO("connectivity.postgresql", "Connection::getTables() got called"); + MutexGuard guard( m_xMutex->GetMutex() ); + if( !m_settings.tables.is() ) + m_settings.tables = Tables::create( m_xMutex, this, &m_settings , &m_settings.pTablesImpl); + else + // TODO: how to overcome the performance problem ? + Reference< css::util::XRefreshable > ( m_settings.tables, UNO_QUERY_THROW )->refresh(); + return m_settings.tables; +} + +Reference< XNameAccess > Connection::getViews() +{ + SAL_INFO("connectivity.postgresql", "Connection::getViews() got called"); + MutexGuard guard( m_xMutex->GetMutex() ); + if( !m_settings.views.is() ) + m_settings.views = Views::create( m_xMutex, this, &m_settings, &(m_settings.pViewsImpl) ); + else + // TODO: how to overcome the performance problem ? + Reference< css::util::XRefreshable > ( m_settings.views, UNO_QUERY_THROW )->refresh(); + return m_settings.views; +} + + +Reference< XNameAccess > Connection::getUsers() +{ + SAL_INFO("connectivity.postgresql", "Connection::getUsers() got called"); + + MutexGuard guard( m_xMutex->GetMutex() ); + if( !m_settings.users.is() ) + m_settings.users = Users::create( m_xMutex, this, &m_settings ); + return m_settings.users; +} + +} // end namespace + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +connectivity_postgresql_Connection_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&) +{ + ::rtl::Reference< comphelper::RefCountedMutex > ref = new comphelper::RefCountedMutex; + return cppu::acquire(new pq_sdbc_driver::Connection( ref, context )); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_connection.hxx b/connectivity/source/drivers/postgresql/pq_connection.hxx new file mode 100644 index 000000000..f30483f70 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_connection.hxx @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <config_lgpl.h> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XUsersSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> + +#include <com/sun/star/container/XNameAccess.hpp> + +#include <rtl/ref.hxx> +#include <rtl/byteseq.hxx> + +#include <comphelper/refcountedmutex.hxx> + +#include <cppuhelper/weakref.hxx> +#include <cppuhelper/compbase.hxx> +#include <functional> + +#include <libpq-fe.h> +#include <unordered_map> + +#include "pq_xtables.hxx" +#include "pq_xviews.hxx" + +namespace pq_sdbc_driver +{ +struct ConnectionSettings; +struct ConnectionSettings +{ + ConnectionSettings() : + pConnection(nullptr), + maxNameLen(0), + maxIndexKeys(0) + {} + static const rtl_TextEncoding encoding = RTL_TEXTENCODING_UTF8; + PGconn *pConnection; + sal_Int32 maxNameLen; + sal_Int32 maxIndexKeys; + css::uno::Reference< css::script::XTypeConverter > tc; + css::uno::Reference< css::container::XNameAccess > tables; + css::uno::Reference< css::container::XNameAccess > users; + css::uno::Reference< css::container::XNameAccess > views; + rtl::Reference<Tables> pTablesImpl; // needed to implement renaming of tables / views + rtl::Reference<Views> pViewsImpl; // needed to implement renaming of tables / views + OUString user; + OUString catalog; +}; + + +typedef cppu::WeakComponentImplHelper< + css::sdbc::XConnection, + css::sdbc::XWarningsSupplier, + css::lang::XInitialization, + css::sdbcx::XTablesSupplier, + css::sdbcx::XViewsSupplier, + css::sdbcx::XUsersSupplier > ConnectionBase; + +// some types +struct HashByteSequence +{ + sal_Int32 operator () ( const ::rtl::ByteSequence & seq ) const + { + return *reinterpret_cast<sal_Int32 const *>(seq.getConstArray()); + } +}; + +typedef std::unordered_map< + ::rtl::ByteSequence, + css::uno::WeakReference< css::sdbc::XCloseable >, + HashByteSequence > WeakHashMap; + + +typedef std::unordered_map +< + sal_Int32, + OUString +> Int2StringMap; + +class Connection : public ConnectionBase +{ + css::uno::Reference< css::uno::XComponentContext > m_ctx; + css::uno::Reference< css::container::XNameAccess > m_typeMap; + ConnectionSettings m_settings; + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_meta; + WeakHashMap m_myStatements; + +private: + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkClosed(); + +public: + Connection( + const rtl::Reference< comphelper::RefCountedMutex > &refMutex, + const css::uno::Reference< css::uno::XComponentContext > & ctx ); + + virtual ~Connection( ) override; + +public: // XCloseable + virtual void SAL_CALL close() override; + +public: // XConnection + + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override ; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( + const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( + const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual void SAL_CALL setCatalog( const OUString& catalog ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + virtual void SAL_CALL setTypeMap( + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + +public: // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + +public: // XInitialization + virtual void SAL_CALL initialize( + const css::uno::Sequence< css::uno::Any >& aArguments ) override; + +public: // XTablesSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override; + +public: // XUsersSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getUsers( ) override; + +public: // XViewsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getViews( ) override; + +public: + virtual void SAL_CALL disposing() override; + +public: // helper function + void removeFromWeakMap( const ::rtl::ByteSequence & seq ); +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_databasemetadata.cxx b/connectivity/source/drivers/postgresql/pq_databasemetadata.cxx new file mode 100644 index 000000000..7da57d1b6 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_databasemetadata.cxx @@ -0,0 +1,2511 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Some portions were adapted from JDBC PostgreSQL driver: + * + * Copyright (c) 2004-2008, PostgreSQL Global Development Group + * + * Licence of original JDBC driver code: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the PostgreSQL Global Development Group nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************/ + +#include <algorithm> +#include <string_view> + +#include <sal/log.hxx> +#include "pq_databasemetadata.hxx" +#include "pq_driver.hxx" +#include "pq_sequenceresultset.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +#include <o3tl/string_view.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/macros.h> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/IndexType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/ColumnSearch.hpp> + +using ::osl::MutexGuard; + + +using namespace com::sun::star::sdbc; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; + +namespace pq_sdbc_driver +{ +// These are pre-processor versions of KeyRule.idl declarations +// These are inherited from JDBC, and thus won't change anytime soon. +// Having them as pre-processor definitions allows to include them +// into compile-time strings (through SAL_STRINGIFY), which can be passed to ASCII_STR. +// That is without resorting to horrendous hacks in template meta-programming. +#define KEYRULE_CASCADE 0 +#define KEYRULE_RESTRICT 1 +#define KEYRULE_SET_NULL 2 +#define KEYRULE_NO_ACTION 4 +#define KEYRULE_SET_DEFAULT 4 +// Ditto for Deferrability.idl +#define DEFERRABILITY_INITIALLY_DEFERRED 5 +#define DEFERRABILITY_INITIALLY_IMMEDIATE 6 +#define DEFERRABILITY_NONE 7 + +DatabaseMetaData::DatabaseMetaData( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) + : m_xMutex( refMutex ), + m_pSettings( pSettings ), + m_origin( origin ), + m_getIntSetting_stmt ( m_origin->prepareStatement("SELECT setting FROM pg_catalog.pg_settings WHERE name=?") ) +{ + init_getReferences_stmt(); + init_getPrivs_stmt(); +} + +sal_Bool DatabaseMetaData::allProceduresAreCallable( ) +{ + // TODO + return false; +} + +sal_Bool DatabaseMetaData::allTablesAreSelectable( ) +{ + return true; +} + +OUString DatabaseMetaData::getURL( ) +{ + // TODO + // LEM TODO: implement + return OUString(); +} + +OUString DatabaseMetaData::getUserName( ) +{ + return m_pSettings->user; +} + +sal_Bool DatabaseMetaData::isReadOnly( ) +{ + return false; +} + + +sal_Bool DatabaseMetaData::nullsAreSortedHigh( ) +{ + // Whether NULL values are considered, for sorting purposes, LARGER than any other value. + // Specification: http://download.oracle.com/javase/6/docs/api/java/sql/DatabaseMetaData.html#nullsAreSortedHigh() + // PostgreSQL behaviour: http://www.postgresql.org/docs/9.1/static/queries-order.html + return true; +} + +sal_Bool DatabaseMetaData::nullsAreSortedLow( ) +{ + return ! nullsAreSortedHigh(); +} + +sal_Bool DatabaseMetaData::nullsAreSortedAtStart( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::nullsAreSortedAtEnd( ) +{ + return false; +} + +OUString DatabaseMetaData::getDatabaseProductName( ) +{ + return "PostgreSQL"; +} + +OUString DatabaseMetaData::getDatabaseProductVersion( ) +{ + return OUString::createFromAscii( PQparameterStatus( m_pSettings->pConnection, "server_version" ) ); +} +OUString DatabaseMetaData::getDriverName( ) +{ + return "postgresql-sdbc"; +} + +OUString DatabaseMetaData::getDriverVersion( ) +{ + return PQ_SDBC_DRIVER_VERSION; +} + +sal_Int32 DatabaseMetaData::getDriverMajorVersion( ) +{ + return PQ_SDBC_MAJOR; +} + +sal_Int32 DatabaseMetaData::getDriverMinorVersion( ) +{ + return PQ_SDBC_MINOR; +} + +sal_Bool DatabaseMetaData::usesLocalFiles( ) +{ + // LEM TODO: + // https://wiki.documentfoundation.org/Documentation/DevGuide/Database_Access#XDatabaseMetaData_Interface + // says "Returns true when the catalog name of the + // database should not appear in the DatasourceBrowser + // of LibreOffice API, otherwise false is returned." + // So, hmmm, think about it. + return false; +} + +sal_Bool DatabaseMetaData::usesLocalFilePerTable( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsMixedCaseIdentifiers( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::storesUpperCaseIdentifiers( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::storesLowerCaseIdentifiers( ) +{ + return true; +} + + +sal_Bool DatabaseMetaData::storesMixedCaseIdentifiers( ) +{ + return false; +} + + +sal_Bool DatabaseMetaData::supportsMixedCaseQuotedIdentifiers( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::storesUpperCaseQuotedIdentifiers( ) +{ + return false; +} + + +sal_Bool DatabaseMetaData::storesLowerCaseQuotedIdentifiers( ) +{ + return false; +} + + +sal_Bool DatabaseMetaData::storesMixedCaseQuotedIdentifiers( ) +{ + return false; +} + + +OUString DatabaseMetaData::getIdentifierQuoteString( ) +{ + return "\""; +} + +OUString DatabaseMetaData::getSQLKeywords( ) +{ + // In Java 6, this is all keywords that are not SQL:2003 + // In Java 2 v1.4 and as per LibreOffice SDK doc, this is all keywords that are not SQL92 + // I understand this to mean "reserved keywords" only. + // See http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html + // LEM TODO: consider using pg_get_keywords(), filter on catcode + return + "ANALYSE," + "ANALYZE," + "ARRAY," //SQL:1999 + "ASYMMETRIC," //SQL:2003 + "BINARY," //SQL:1999 + "CONCURRENTLY," + "CURRENT_CATALOG," //SQL:2008 + "CURRENT_ROLE," //SQL:1999 + "CURRENT_SCHEMA," //SQL:2008 + "DO," + "FREEZE," + "ILIKE," + "ISNULL," + "LIMIT," //SQL:1999; non-reserved in SQL:2003 + "LOCALTIME," //SQL:1999 + "LOCALTIMESTAMP," //SQL:1999 + "NOTNULL," + "OFFSET," //SQL:2008 + "OVER," //SQL:2003 + "PLACING," //non-reserved in SQL:2003 + "RETURNING," //non-reserved in SQL:2008 + "SIMILAR," //SQL:2003 + "VARIADIC," + "VERBOSE," + "WINDOW" //SQL:2003 + ; +} +OUString DatabaseMetaData::getNumericFunctions( ) +{ + // See https://www.postgresql.org/docs/9.1/static/functions-math.html + // LEM TODO: Err... https://wiki.documentfoundation.org/Documentation/DevGuide/Database_Access#Support_Scalar_Functions + // says this should be "Open Group CLI" names, not PostgreSQL names. + // Currently this is just a list of supported functions in PostgreSQL, with PostgreSQL names. + // And it is my job to map from Open Group CLI names/syntax to PostgreSQL names/syntax. Where? By parsing the SQL??? + // Should look at what the JDBC driver is doing. + return + "abs," + "cbrt," + "ceil," + "ceiling," + "degrees," + "div," + "exp," + "floor," + "ln," + "log," + "mod," + "pi," + "power," + "radians," + "random," + "round," + "setseed," + "sign," + "sqrt," + "trunc," + "width_bucket," + "acos," + "asin," + "atan," + "atan2," + "cos," + "cot," + "sin," + "tan" + ; +} + +OUString DatabaseMetaData::getStringFunctions( ) +{ + // See http://www.postgresql.org/docs/9.1/static/functions-string.html + return + "bit_length," + "char_length," + "character_length," + "lower," + "octet_length," + "overlay," + "position," + "substring," + "trim," + "upper," + "ascii," + "btrim," + "chr," + "concat," + "concat_ws," + "convert," + "convert_from," + "convert_to," + "decode," + "encode," + "format," + "initcap," + "left," + "length," + "lpad," + "ltrim," + "md5," + "pg_client_encoding," + "quote_ident," + "quote_literal," + "quote_nullable," + "regexp_matches," + "regexp_replace," + "regexp_split_to_array," + "regexp_split_to_table," + "repeat," + "replace," + "reverse," + "right," + "rpad," + "rtrim," + "split_part," + "strpos," + "substr," + "to_ascii," + "to_hex," + "translate" + ; +} + +OUString DatabaseMetaData::getSystemFunctions( ) +{ + // See http://www.postgresql.org/docs/9.1/static/functions-info.html + // and http://www.postgresql.org/docs/9.1/static/functions-admin.html + return + "current_catalog," + "current_database," + "current_query," + "current_schema," + "current_schemas," + "current_user," + "inet_client_addr," + "inet_client_port," + "inet_server_addr," + "inet_server_port," + "pg_backend_pid," + "pg_conf_load_time," + "pg_is_other_temp_schema," + "pg_listening_channels," + "pg_my_temp_schema," + "pg_postmaster_start_time," + "session_user," + "user," + "version," + "has_any_column_privilege," + "has_any_column_privilege," + "has_any_column_privilege," + "has_column_privilege," + "has_database_privilege," + "has_foreign_data_wrapper_privilege," + "has_function_privilege," + "has_language_privilege," + "has_schema_privilege," + "has_sequence_privilege," + "has_server_privilege," + "has_table_privilege," + "has_tablespace_privilege," + "pg_has_role," + "pg_collation_is_visible," + "pg_conversion_is_visible," + "pg_function_is_visible," + "pg_opclass_is_visible," + "pg_operator_is_visible," + "pg_table_is_visible," + "pg_ts_config_is_visible," + "pg_ts_dict_is_visible," + "pg_ts_parser_is_visible," + "pg_ts_template_is_visible," + "pg_type_is_visible," + "format_type," + "pg_describe_object," + "pg_get_constraintdef," + "pg_get_expr," + "pg_get_functiondef," + "pg_get_function_arguments," + "pg_get_function_identity_arguments," + "pg_get_function_result," + "pg_get_indexdef," + "pg_get_keywords," + "pg_get_ruledef," + "pg_get_serial_sequence," + "pg_get_triggerdef," + "pg_get_userbyid," + "pg_get_viewdef," + "pg_options_to_table," + "pg_tablespace_databases," + "pg_typeof," + "col_description," + "obj_description," + "shobj_description," + "txid_current," + "txid_current_snapshot," + "txid_snapshot_xip," + "txid_snapshot_xmax," + "txid_snapshot_xmin," + "txid_visible_in_snapshot," + "xmin," + "xmax," + "xip_list," + "current_setting," + "set_config," + "pg_cancel_backend," + "pg_reload_conf," + "pg_rotate_logfile," + "pg_terminate_backend," + "pg_create_restore_point," + "pg_current_xlog_insert_location," + "pg_current_xlog_location," + "pg_start_backup," + "pg_stop_backup," + "pg_switch_xlog," + "pg_xlogfile_name," + "pg_xlogfile_name_offset," + "pg_is_in_recovery," + "pg_last_xlog_receive_location," + "pg_last_xlog_replay_location," + "pg_last_xact_replay_timestamp," + "pg_is_xlog_replay_paused," + "pg_xlog_replay_pause," + "pg_xlog_replay_resume," + "pg_column_size," + "pg_database_size," + "pg_indexes_size," + "pg_relation_size," + "pg_size_pretty," + "pg_table_size," + "pg_tablespace_size," + "pg_tablespace_size," + "pg_total_relation_size," + "pg_relation_filenode," + "pg_relation_filepath," + "pg_ls_dir," + "pg_read_file," + "pg_read_binary_file," + "pg_stat_file," + "pg_advisory_lock," + "pg_advisory_lock_shared," + "pg_advisory_unlock," + "pg_advisory_unlock_all," + "pg_advisory_unlock_shared," + "pg_advisory_xact_lock," + "pg_advisory_xact_lock_shared," + "pg_try_advisory_lock," + "pg_try_advisory_lock_shared," + "pg_try_advisory_xact_lock," + "pg_try_advisory_xact_lock_shared," + "pg_sleep" + ; +} +OUString DatabaseMetaData::getTimeDateFunctions( ) +{ + // TODO + return + "age," + "age," + "clock_timestamp," + "current_date," + "current_time," + "current_timestamp," + "date_part," + "date_part," + "date_trunc," + "extract," + "extract," + "isfinite," + "isfinite," + "isfinite," + "justify_days," + "justify_hours," + "justify_interval," + "localtime," + "localtimestamp," + "now," + "statement_timestamp," + "timeofday," + "transaction_timestamp," + ; +} +OUString DatabaseMetaData::getSearchStringEscape( ) +{ + return "\\"; +} +OUString DatabaseMetaData::getExtraNameCharacters( ) +{ + return "$"; +} + +sal_Bool DatabaseMetaData::supportsAlterTableWithAddColumn( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsAlterTableWithDropColumn( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsColumnAliasing( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::nullPlusNonNullIsNull( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsTypeConversion( ) +{ + // LEM: this is specifically whether the "CONVERT" function is supported + // It seems that in PostgreSQL, that function is only for string encoding, so no. + return false; +} + +sal_Bool DatabaseMetaData::supportsConvert( sal_Int32, sal_Int32 ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsTableCorrelationNames( ) +{ + // LEM: A correlation name is "bar" in "SELECT foo FROM qux [AS] bar WHERE ..." + return true; +} + + +sal_Bool DatabaseMetaData::supportsDifferentTableCorrelationNames( ) +{ + return false; +} +sal_Bool DatabaseMetaData::supportsExpressionsInOrderBy( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsOrderByUnrelated( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsGroupBy( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsGroupByUnrelated( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsGroupByBeyondSelect( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsLikeEscapeClause( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsMultipleResultSets( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsMultipleTransactions( ) +{ + // Allows multiple transactions open at once (on different connections!) + return true; +} + +sal_Bool DatabaseMetaData::supportsNonNullableColumns( ) +{ + return true; +} + + +sal_Bool DatabaseMetaData::supportsMinimumSQLGrammar( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsCoreSQLGrammar( ) +{ + // LEM: jdbc driver says not, although the comments in it seem old + // fdo#45249 Base query design won't use any aggregate function + // (except COUNT(*) unless we say yes, so say yes. + // Actually, Base assumes *also* support for aggregate functions "collect, fusion, intersection" + // as soon as supportsCoreSQLGrammar() returns true. + // Those are *not* Core SQL, though. They are in optional feature S271 "Basic multiset support" + return true; +} + +sal_Bool DatabaseMetaData::supportsExtendedSQLGrammar( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsANSI92EntryLevelSQL( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsANSI92IntermediateSQL( ) +{ + // LEM: jdbc driver says not, although the comments in it seem old + return false; +} + +sal_Bool DatabaseMetaData::supportsANSI92FullSQL( ) +{ + // LEM: jdbc driver says not, although the comments in it seem old + return false; +} + +sal_Bool DatabaseMetaData::supportsIntegrityEnhancementFacility( ) +{ + // LEM: jdbc driver says yes, although comment says they are not sure what this means... + return true; +} + +sal_Bool DatabaseMetaData::supportsOuterJoins( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsFullOuterJoins( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsLimitedOuterJoins( ) +{ + return true; +} + + +OUString DatabaseMetaData::getSchemaTerm( ) +{ + return "SCHEMA"; +} + +OUString DatabaseMetaData::getProcedureTerm( ) +{ + return "function"; +} + +OUString DatabaseMetaData::getCatalogTerm( ) +{ + return "DATABASE"; +} + +sal_Bool DatabaseMetaData::isCatalogAtStart( ) +{ + return true; +} + +OUString DatabaseMetaData::getCatalogSeparator( ) +{ + return "."; +} + +sal_Bool DatabaseMetaData::supportsSchemasInDataManipulation( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSchemasInProcedureCalls( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSchemasInTableDefinitions( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSchemasInIndexDefinitions( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSchemasInPrivilegeDefinitions( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsCatalogsInDataManipulation( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsCatalogsInProcedureCalls( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsCatalogsInTableDefinitions( ) +{ + return false; +} + + +sal_Bool DatabaseMetaData::supportsCatalogsInIndexDefinitions( ) +{ + return false; +} + + +sal_Bool DatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( ) +{ + return false; +} + + +// LEM TODO: positioned (through cursor) updates and deletes seem +// to be supported; see {UPDATE,DELETE} /table/ (...) WHERE CURRENT OF /cursor_name/" syntax +// and http://www.postgresql.org/docs/9.1/static/view-pg-cursors.html +// http://www.postgresql.org/docs/9.1/static/libpq-example.html actually uses a cursor :) +sal_Bool DatabaseMetaData::supportsPositionedDelete( ) +{ + // LEM: jdbc driver says not, although the comments in it seem old + return false; +} + +sal_Bool DatabaseMetaData::supportsPositionedUpdate( ) +{ + // LEM: jdbc driver says not, although the comments in it seem old + return false; +} + + +sal_Bool DatabaseMetaData::supportsSelectForUpdate( ) +{ + return true; +} + + +sal_Bool DatabaseMetaData::supportsStoredProcedures( ) +{ + return true; +} + + +sal_Bool DatabaseMetaData::supportsSubqueriesInComparisons( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSubqueriesInExists( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSubqueriesInIns( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSubqueriesInQuantifieds( ) +{ + // LEM: jdbc driver says yes, although comment says they don't know what this means... + return true; +} + +sal_Bool DatabaseMetaData::supportsCorrelatedSubqueries( ) +{ + return true; +} +sal_Bool DatabaseMetaData::supportsUnion( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsUnionAll( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossCommit( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossRollback( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossCommit( ) +{ + return true; +} +sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossRollback( ) +{ + return true; +} + +sal_Int32 DatabaseMetaData::getMaxBinaryLiteralLength( ) +{ + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxCharLiteralLength( ) +{ + return 0; +} + +// Copied / adapted / simplified from JDBC driver +sal_Int32 DatabaseMetaData::getIntSetting(const OUString& settingName) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + + Reference< XParameters > params(m_getIntSetting_stmt, UNO_QUERY_THROW ); + params->setString(1, settingName ); + Reference< XResultSet > rs = m_getIntSetting_stmt->executeQuery(); + Reference< XRow > xRow( rs , UNO_QUERY_THROW ); + OSL_VERIFY(rs->next()); + OSL_ENSURE(rs->isFirst(), "postgresql-sdbc DatabaseMetaData getIntSetting not on first row"); + OSL_ENSURE(rs->isLast(), "postgresql-sdbc DatabaseMetaData getIntSetting not on last row"); + return xRow->getInt(1); +} + +sal_Int32 DatabaseMetaData::getMaxNameLength() +{ + if ( m_pSettings->maxNameLen == 0) + m_pSettings->maxNameLen = getIntSetting( "max_identifier_length" ); + OSL_ENSURE(m_pSettings->maxNameLen, "postgresql-sdbc: maxNameLen is zero"); + return m_pSettings->maxNameLen; +} + +sal_Int32 DatabaseMetaData::getMaxIndexKeys() +{ + if ( m_pSettings->maxIndexKeys == 0) + m_pSettings->maxIndexKeys = getIntSetting("max_index_keys"); + OSL_ENSURE(m_pSettings->maxIndexKeys, "postgresql-sdbc: maxIndexKeys is zero"); + return m_pSettings->maxIndexKeys; +} + +sal_Int32 DatabaseMetaData::getMaxColumnNameLength( ) +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getMaxColumnsInGroupBy( ) +{ + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxColumnsInIndex( ) +{ + return getMaxIndexKeys(); +} + +sal_Int32 DatabaseMetaData::getMaxColumnsInOrderBy( ) +{ + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxColumnsInSelect( ) +{ + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxColumnsInTable( ) +{ + return 1600; +} + +sal_Int32 DatabaseMetaData::getMaxConnections( ) +{ + // LEM: The JDBC driver returns an arbitrary 8192; truth is as much as OS / hardware supports + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxCursorNameLength( ) //TODO, don't know +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getMaxIndexLength( ) //TODO, don't know +{ + // LEM: that's the index itself, not its name + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxSchemaNameLength( ) +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getMaxProcedureNameLength( ) +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getMaxCatalogNameLength( ) +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getMaxRowSize( ) +{ + // jdbc driver says 1GB, but http://www.postgresql.org/about/ says 1.6TB + // and that 1GB is the maximum _field_ size + // The row limit does not fit into a sal_Int32 + return 0; +} + +sal_Bool DatabaseMetaData::doesMaxRowSizeIncludeBlobs( ) +{ + // LEM: Err... PostgreSQL basically does not do BLOBs well + // In any case, BLOBs do not change the maximal row length AFAIK + return true; +} + +sal_Int32 DatabaseMetaData::getMaxStatementLength( ) +{ + // LEM: actually, that would be 2^sizeof(size_t)-1 + // on the server? on the client (because of libpq)? minimum of the two? not sure + // Anyway, big, so say unlimited. + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxStatements( ) //TODO, don't know +{ + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxTableNameLength( ) +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getMaxTablesInSelect( ) +{ + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxUserNameLength( ) +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getDefaultTransactionIsolation( ) +{ + return css::sdbc::TransactionIsolation::READ_COMMITTED; +} + +sal_Bool DatabaseMetaData::supportsTransactions( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level ) +{ + if ( level == css::sdbc::TransactionIsolation::READ_COMMITTED + || level == css::sdbc::TransactionIsolation::SERIALIZABLE + || level == css::sdbc::TransactionIsolation::READ_UNCOMMITTED + || level == css::sdbc::TransactionIsolation::REPEATABLE_READ) + return true; + else + return false; +} + +sal_Bool DatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsDataManipulationTransactionsOnly( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::dataDefinitionCausesTransactionCommit( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::dataDefinitionIgnoredInTransactions( ) +{ + return false; +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getProcedures( + const css::uno::Any&, + const OUString&, + const OUString& ) +{ +// 1. PROCEDURE_CAT string => procedure catalog (may be NULL ) +// 2. PROCEDURE_SCHEM string => procedure schema (may be NULL ) +// 3. PROCEDURE_NAME string => procedure name +// 4. reserved for future use +// 5. reserved for future use +// 6. reserved for future use +// 7. REMARKS string => explanatory comment on the procedure +// 8. PROCEDURE_TYPE short => kind of procedure: +// * UNKNOWN - May return a result +// * NO - Does not return a result +// * RETURN - Returns a result + +// LEM TODO: implement +// LEM TODO: at least fake the columns, even if no row. + MutexGuard guard( m_xMutex->GetMutex() ); + return new SequenceResultSet( + m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > > (), m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getProcedureColumns( + const css::uno::Any&, + const OUString&, + const OUString&, + const OUString& ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); +// LEM TODO: implement +// LEM TODO: at least fake the columns, even if no row. + return new SequenceResultSet( + m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getTables( + const css::uno::Any&, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const css::uno::Sequence< OUString >& ) +{ + Statics &statics = getStatics(); + + MutexGuard guard( m_xMutex->GetMutex() ); + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTables() got called with " << schemaPattern << "." << tableNamePattern); + + // ignore catalog, as a single pq connection does not support multiple catalogs + + // LEM TODO: this does not give the right column names, not the right number of columns, etc. + // Take "inspiration" from JDBC driver + // Ah, this is used to create a XResultSet manually... Try to do it directly in SQL + Reference< XPreparedStatement > statement = m_origin->prepareStatement( + "SELECT " + "DISTINCT ON (pg_namespace.nspname, relname ) " // avoid duplicates (pg_settings !) + "pg_namespace.nspname, relname, relkind, pg_description.description " + "FROM pg_namespace, pg_class LEFT JOIN pg_description ON pg_class.oid = pg_description.objoid " + "WHERE relnamespace = pg_namespace.oid " + "AND ( relkind = 'r' OR relkind = 'v') " + "AND pg_namespace.nspname LIKE ? " + "AND relname LIKE ? " +// "ORDER BY pg_namespace.nspname || relname" + ); + + Reference< XParameters > parameters( statement, UNO_QUERY_THROW ); + parameters->setString( 1 , schemaPattern ); + parameters->setString( 2 , tableNamePattern ); + + Reference< XResultSet > rs = statement->executeQuery(); + Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + std::vector< std::vector<Any> > vec; + + while( rs->next() ) + { + std::vector< Any > row( 5 ); + + row[0] <<= m_pSettings->catalog; + row[1] <<= xRow->getString( 1 ); + row[2] <<= xRow->getString( 2 ); + OUString type = xRow->getString(3); + if( type == "r" ) + { + if( xRow->getString(1) == "pg_catalog" ) + { + row[3] <<= statics.SYSTEM_TABLE; + } + else + { + row[3] <<= statics.TABLE; + } + } + else if( type == "v" ) + { + row[3] <<= statics.VIEW; + } + else + { + row[3] <<= statics.UNKNOWN; + } + row[4] <<= xRow->getString(4); + + // no description in postgresql AFAIK + vec.push_back( row ); + } + Reference< XCloseable > closeable( statement, UNO_QUERY ); + if( closeable.is() ) + closeable->close(); + + return new SequenceResultSet( + m_xMutex, *this, std::vector(statics.tablesRowNames), std::move(vec), m_pSettings->tc ); +} + +namespace +{ + // sort no schema first, then "public", then normal schemas, then internal schemas + int compare_schema(std::u16string_view nsA, std::u16string_view nsB) + { + if (nsA.empty()) + { + return nsB.empty() ? 0 : -1; + } + else if (nsB.empty()) + { + assert(!nsA.empty()); + return 1; + } + else if(nsA == u"public") + { + return (nsB == u"public") ? 0 : -1; + } + else if(nsB == u"public") + { + assert(nsA != u"public"); + return 1; + } + else if(o3tl::starts_with(nsA, u"pg_")) + { + if(o3tl::starts_with(nsB, u"pg_")) + return nsA.compare(nsB); + else + return 1; + } + else if(o3tl::starts_with(nsB, u"pg_")) + { + return -1; + } + else + { + return nsA.compare(nsB); + } + } + + struct SortInternalSchemasLastAndPublicFirst + { + bool operator () ( const std::vector< Any > & a, const std::vector< Any > & b ) + { + OUString valueA; + OUString valueB; + a[0] >>= valueA; + b[0] >>= valueB; + return compare_schema(valueA, valueB) < 0; + } + }; +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getSchemas( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getSchemas() got called"); + + // <b>TABLE_SCHEM</b> string =&gt; schema name + Reference< XStatement > statement = m_origin->createStatement(); + Reference< XResultSet > rs = statement->executeQuery( + "SELECT nspname from pg_namespace" ); + // LEM TODO: look at JDBC driver and consider doing the same + // in particular, excluding temporary schemas, but maybe better through pg_is_other_temp_schema(oid) OR == pg_my_temp_schema() + + Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + std::vector< std::vector<Any> > vec; + while( rs->next() ) + { + vec.push_back( { Any(xRow->getString(1)) } ); + } + + // sort public first, sort internal schemas last, sort rest in alphabetic order + std::sort( vec.begin(), vec.end(), SortInternalSchemasLastAndPublicFirst() ); + + Reference< XCloseable > closeable( statement, UNO_QUERY ); + if( closeable.is() ) + closeable->close(); + return new SequenceResultSet( + m_xMutex, *this, std::vector(getStatics().schemaNames), std::move(vec), m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getCatalogs( ) +{ + // LEM TODO: return the current catalog like JDBC driver? + // at least fake the columns, even if no content + MutexGuard guard( m_xMutex->GetMutex() ); + return new SequenceResultSet( + m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getTableTypes( ) +{ + // LEM TODO: this can be made dynamic, see JDBC driver + MutexGuard guard( m_xMutex->GetMutex() ); + return new SequenceResultSet( + m_xMutex, *this, std::vector(getStatics().tableTypeNames), std::vector(getStatics().tableTypeData), + m_pSettings->tc ); +} + + +/** returns the constant from sdbc.DataType + */ +sal_Int32 typeNameToDataType( const OUString &typeName, std::u16string_view typtype ) +{ +// sal_Int32 ret = css::sdbc::DataType::DISTINCT; + // map all unknown types to memo (longvarchar). This allows to show them in + // string representation. Additionally, the edit-table-type-selection-box + // is not so unusable anymore. + sal_Int32 ret = css::sdbc::DataType::LONGVARCHAR; + if( typtype == u"b" ) + { + // as long as the OOo framework does not support arrays, + // the user is better of with interpreting arrays as strings ! +// if( typeName.getLength() && '_' == typeName[0] ) +// { +// it's just a naming convention, but as long as we don't have anything better, +// we take it as granted +// ret = css::sdbc::DataType::ARRAY; +// } + // base type + Statics &statics = getStatics(); + BaseTypeMap::const_iterator ii = statics.baseTypeMap.find( typeName ); + if( ii != statics.baseTypeMap.end() ) + { + ret = ii->second; + } + } + else if( typtype == u"c" ) + { + ret = css::sdbc::DataType::STRUCT; + } + else if( typtype == u"d" ) + { + ret = css::sdbc::DataType::LONGVARCHAR; + } + return ret; +} + +namespace { + bool isSystemColumn( sal_Int16 attnum ) + { + return attnum <= 0; + } + + // is not exported by the postgres header + const int PQ_VARHDRSZ = sizeof( sal_Int32 ); + + // Oh, quelle horreur + // LEM TODO: Need to severely rewrite that! + // should probably just "do the same" as ODBC or JDBC drivers... + void extractPrecisionAndScale( + sal_Int32 dataType, sal_Int32 atttypmod, sal_Int32 *precision, sal_Int32 *scale ) + { + if( atttypmod < PQ_VARHDRSZ ) + { + *precision = 0; + *scale = 0; + } + else + { + switch( dataType ) + { + case css::sdbc::DataType::NUMERIC: + case css::sdbc::DataType::DECIMAL: + { + *precision = ( ( atttypmod - PQ_VARHDRSZ ) >> 16 ) & 0xffff; + *scale = (atttypmod - PQ_VARHDRSZ ) & 0xffff; + break; + } + default: + *precision = atttypmod - PQ_VARHDRSZ; + *scale = 0; + } + } + } + + struct DatabaseTypeDescription + { + DatabaseTypeDescription() + {} + DatabaseTypeDescription( const OUString &name, const OUString & type ) : + typeName( name ), + typeType( type ) + {} + DatabaseTypeDescription( const DatabaseTypeDescription &source ) : + typeName( source.typeName ), + typeType( source.typeType ) + {} + DatabaseTypeDescription & operator = ( const DatabaseTypeDescription & source ) + { + typeName = source.typeName; + typeType = source.typeType; + return *this; + } + OUString typeName; + OUString typeType; + }; +} + +typedef std::unordered_map +< + sal_Int32, + DatabaseTypeDescription +> Oid2DatabaseTypeDescriptionMap; + +static void columnMetaData2DatabaseTypeDescription( + Oid2DatabaseTypeDescriptionMap &oidMap, + const Reference< XResultSet > &rs, + const Reference< XStatement > &stmt ) +{ + Reference< XRow > row( rs, UNO_QUERY_THROW ); + int domains = 0; + OUStringBuffer queryBuf(128); + queryBuf.append( "SELECT oid,typtype,typname FROM pg_TYPE WHERE " ); + while( rs->next() ) + { + if( row->getString( 9 ) == "d" && oidMap.find( row->getInt( 12 ) ) == oidMap.end() ) + { + oidMap[row->getInt(12)] = DatabaseTypeDescription(); + if( domains ) + queryBuf.append( " OR " ); + queryBuf.append( "oid = " ); + queryBuf.append( row->getInt(12 ) ); + domains ++; + } + } + rs->beforeFirst(); + + if( domains ) + { + Reference< XResultSet > rsDomain = stmt->executeQuery( queryBuf.makeStringAndClear() ); + row.set( rsDomain, UNO_QUERY_THROW ); + while( rsDomain->next() ) + { + oidMap[row->getInt(1)] = DatabaseTypeDescription(row->getString(3), row->getString(2) ); + } + disposeNoThrow( stmt ); + } + +} + + +css::uno::Reference< XResultSet > DatabaseMetaData::getColumns( + const css::uno::Any&, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const OUString& columnNamePattern ) +{ + // LEM TODO: review in comparison with JDBC driver + Statics &statics = getStatics(); + + // continue ! + MutexGuard guard( m_xMutex->GetMutex() ); + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getColumns() got called with " + << schemaPattern << "." << tableNamePattern << "." << columnNamePattern); + + // ignore catalog, as a single pq connection + // does not support multiple catalogs anyway + // We don't use information_schema.columns because it contains + // only the columns the current user has any privilege over. + + // 1. TABLE_CAT string => table catalog (may be NULL) + // => not supported + // 2. TABLE_SCHEM string => table schema (may be NULL) + // => pg_namespace.nspname + // 3. TABLE_NAME string => table name + // => pg_class.relname + // 4. COLUMN_NAME string => column name + // => pg_attribute.attname + // 5. DATA_TYPE short => SQL type from java.sql.Types + // => pg_type.typname => sdbc.DataType + // 6. TYPE_NAME string => Data source dependent type name, for a UDT the + // type name is fully qualified + // => pg_type.typname + // 7. COLUMN_SIZE long => column size. For char or date types this is + // the maximum number of characters, for numeric + // or decimal types this is precision. + // => pg_attribute.atttypmod + // 8. BUFFER_LENGTH is not used. + // => not used + // 9. DECIMAL_DIGITS long => the number of fractional digits + // => don't know ! TODO ! + // 10. NUM_PREC_RADIX long => Radix (typically either 10 or 2) + // => TODO ?? + // 11. NULLABLE long => is NULL allowed? + // NO_NULLS - might not allow NULL values + // NULABLE - definitely allows NULL values + // NULLABLE_UNKNOWN - nullability unknown + // => pg_attribute.attnotnull + // 12. REMARKS string => comment describing column (may be NULL ) + // => pg_description.description + // 13. COLUMN_DEF string => default value (may be NULL) + // => pg_type.typdefault + // 14. SQL_DATA_TYPE long => unused + // => empty + // 15. SQL_DATETIME_SUB long => unused + // => empty + // 16. CHAR_OCTET_LENGTH long => for char types the maximum number of + // bytes in the column + // => pg_type.typlen + // 17. ORDINAL_POSITION int => index of column in table (starting at 1) + // pg_attribute.attnum + // 18. IS_NULLABLE string => "NO" means column definitely does not allow + // NULL values; "YES" means the column might + // allow NULL values. An empty string means + // nobody knows. + // => pg_attribute.attnotnull + OUString strDefaultValue = getColExprForDefaultSettingVal(m_pSettings); + Reference< XPreparedStatement > statement = m_origin->prepareStatement( + "SELECT pg_namespace.nspname, " // 1 + "pg_class.relname, " // 2 + "pg_attribute.attname, " // 3 + "pg_type.typname, " // 4 + "pg_attribute.atttypmod, " // 5 + "pg_attribute.attnotnull, " // 6 + "pg_type.typdefault, " // 7 + "pg_type.typtype, " // 8 + + strDefaultValue + // 9 + ",pg_description.description, " // 10 + "pg_type.typbasetype, " // 11 + "pg_attribute.attnum " // 12 + "FROM pg_class, " + "pg_attribute LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND pg_attribute.attnum = pg_attrdef.adnum " + "LEFT JOIN pg_description ON pg_attribute.attrelid = pg_description.objoid AND pg_attribute.attnum=pg_description.objsubid," + " pg_type, pg_namespace " + "WHERE pg_attribute.attrelid = pg_class.oid " + "AND pg_attribute.atttypid = pg_type.oid " + "AND pg_class.relnamespace = pg_namespace.oid " + "AND NOT pg_attribute.attisdropped " + "AND pg_namespace.nspname LIKE ? " + "AND pg_class.relname LIKE ? " + "AND pg_attribute.attname LIKE ? " + "ORDER BY pg_namespace.nspname, pg_class.relname, pg_attribute.attnum" + ); + + Reference< XParameters > parameters( statement, UNO_QUERY_THROW ); + parameters->setString( 1 , schemaPattern ); + parameters->setString( 2 , tableNamePattern ); + parameters->setString( 3 , columnNamePattern ); + + Reference< XResultSet > rs = statement->executeQuery(); + Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + std::vector< std::vector<Any> > vec; + + Oid2DatabaseTypeDescriptionMap domainMap; + Reference< XStatement > domainTypeStmt = m_origin->createStatement(); + columnMetaData2DatabaseTypeDescription( domainMap, rs, domainTypeStmt ); + + sal_uInt32 colNum(0); + OUString sSchema( "#invalid#" ); + OUString sTable( "#invalid#" ); + + while( rs->next() ) + { + if( ! isSystemColumn( xRow->getShort( 12 ) ) ) + { + OUString sNewSchema( xRow->getString(1) ); + OUString sNewTable( xRow->getString(2) ); + if ( sNewSchema != sSchema || sNewTable != sTable ) + { + colNum = 1; + sSchema = sNewSchema; + sTable = sNewTable; + } + else + ++colNum; + sal_Int32 precision, scale, type; + std::vector< Any > row( 18 ); + row[0] <<= m_pSettings->catalog; + row[1] <<= sNewSchema; + row[2] <<= sNewTable; + row[3] <<= xRow->getString(3); + if( xRow->getString(8) == "d" ) + { + DatabaseTypeDescription desc( domainMap[xRow->getInt(11)] ); + type = typeNameToDataType( desc.typeName, desc.typeType ); + } + else + { + type = typeNameToDataType( xRow->getString(4), xRow->getString(8) ); + } + extractPrecisionAndScale( type, xRow->getInt(5) , &precision, &scale ); + row[4] <<= type; + row[5] <<= xRow->getString(4); + row[6] <<= precision; + // row[7] BUFFER_LENGTH not used + row[8] <<= scale; + // row[9] RADIX TODO + if( xRow->getBoolean( 6 ) && ! isSystemColumn(xRow->getInt( 12 )) ) + { + row[10] <<= OUString::number(css::sdbc::ColumnValue::NO_NULLS); + row[17] <<= statics.NO; + } + else + { + row[10] <<= OUString::number(css::sdbc::ColumnValue::NULLABLE); + row[17] <<= statics.YES; + } + + row[11] <<= xRow->getString( 10 ); // comment + row[12] <<= xRow->getString( 9 ); // COLUMN_DEF = pg_type.typdefault + // row[13] SQL_DATA_TYPE not used + // row[14] SQL_DATETIME_SUB not used + row[15] <<= precision; + row[16] <<= colNum ; + + vec.push_back( row ); + } + } + Reference< XCloseable > closeable( statement, UNO_QUERY ); + if( closeable.is() ) + closeable->close(); + + return new SequenceResultSet( + m_xMutex, *this, std::vector(statics.columnRowNames), std::move(vec), m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getColumnPrivileges( + const css::uno::Any&, + const OUString& schema, + const OUString& table, + const OUString& columnNamePattern ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getColumnPrivileges() got called with " + << schema << "." << table << "." << columnNamePattern); + + Reference< XParameters > parameters( m_getColumnPrivs_stmt, UNO_QUERY_THROW ); + parameters->setString( 1 , schema ); + parameters->setString( 2 , table ); + parameters->setString( 3 , columnNamePattern ); + + Reference< XResultSet > rs = m_getColumnPrivs_stmt->executeQuery(); + + return rs; +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getTablePrivileges( + const css::uno::Any&, + const OUString& schemaPattern, + const OUString& tableNamePattern ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTablePrivileges() got called with " + << schemaPattern << "." << tableNamePattern); + + Reference< XParameters > parameters( m_getTablePrivs_stmt, UNO_QUERY_THROW ); + parameters->setString( 1 , schemaPattern ); + parameters->setString( 2 , tableNamePattern ); + + Reference< XResultSet > rs = m_getTablePrivs_stmt->executeQuery(); + + return rs; +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getBestRowIdentifier( + const css::uno::Any&, + const OUString&, + const OUString&, + sal_Int32, + sal_Bool ) +{ + //LEM TODO: implement! See JDBC driver + MutexGuard guard( m_xMutex->GetMutex() ); + return new SequenceResultSet( + m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getVersionColumns( + const css::uno::Any&, + const OUString&, + const OUString& ) +{ + //LEM TODO: implement! See JDBC driver + MutexGuard guard( m_xMutex->GetMutex() ); + return new SequenceResultSet( + m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getPrimaryKeys( + const css::uno::Any&, + const OUString& schema, + const OUString& table ) +{ + //LEM TODO: review + MutexGuard guard( m_xMutex->GetMutex() ); + +// 1. TABLE_CAT string => table catalog (may be NULL ) +// 2. TABLE_SCHEM string => table schema (may be NULL ) +// 3. TABLE_NAME string => table name +// 4. COLUMN_NAME string => column name +// 5. KEY_SEQ short => sequence number within primary key +// 6. PK_NAME string => primary key name (may be NULL ) + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getPrimaryKeys() got called with " + << schema << "." << table); + + Reference< XPreparedStatement > statement = m_origin->prepareStatement( + "SELECT nmsp.nspname, " + "cl.relname, " + "con.conkey, " + "con.conname, " + "con.conrelid " + "FROM pg_constraint as con,pg_class as cl, pg_namespace as nmsp " + "WHERE con.connamespace = nmsp.oid AND con.conrelid = cl.oid AND con.contype = 'p' " + "AND nmsp.nspname LIKE ? AND cl.relname LIKE ?" ); + + Reference< XParameters > parameters( statement, UNO_QUERY_THROW ); + parameters->setString( 1 , schema ); + parameters->setString( 2 , table ); + + Reference< XResultSet > rs = statement->executeQuery(); + Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + std::vector< std::vector<Any> > vec; + + while( rs->next() ) + { + std::vector< Any > row( 6 ); + row[0] <<= m_pSettings->catalog; + row[1] <<= xRow->getString(1); + row[2] <<= xRow->getString(2); + OUString array = xRow->getString(3); + row[4] <<= xRow->getString(5); // the relid + row[5] <<= xRow->getString(4); + + int i = 0; + // now retrieve the columns information + // unfortunately, postgresql does not allow array of variable size in + // WHERE clauses (in the default installation), so we have to choose + // this expensive and somewhat ugly way + // annotation: postgresql shouldn't have chosen an array here, instead they + // should have multiple rows per table + // LEM: to transform an array into several rows, see unnest; + // it is as simple as "SELECT foo, bar, unnest(qux) FROM ..." + // where qux is the column that contains an array. + while( array[i] && '}' != array[i] ) + { + i++; + int start = i; + while( array[i] && array[i] != '}' && array[i] != ',' ) i++; + row[3] <<= array.copy(start, i - start ); + vec.push_back( row ); + } + } + + { + Reference< XCloseable > closeable( statement, UNO_QUERY ); + if( closeable.is() ) + closeable->close(); + } + + + OUString lastTableOid; + sal_Int32 index = 0; + std::vector< std::vector< Any > > ret( vec.size() ); + int elements = 0; + for (auto const& elem : vec) + { + + std::vector< Any > row = elem; + OUString tableOid; + OUString attnum; + + row[4] >>= tableOid; + row[3] >>= attnum; + statement = m_origin->prepareStatement( + "SELECT att.attname FROM " + "pg_attribute AS att, pg_class AS cl WHERE " + "att.attrelid = ? AND att.attnum = ?" ); + + parameters.set( statement, UNO_QUERY_THROW ); + parameters->setString( 1 , tableOid ); + parameters->setString( 2 , attnum ); + + rs = statement->executeQuery(); + xRow.set( rs, UNO_QUERY_THROW ); + if( rs->next() ) + { + // column name + row[3] <<= xRow->getString( 1 ); + if( tableOid != lastTableOid ) + index = 1; + lastTableOid = tableOid; + row[4] <<= OUString::number( index ); + index ++; + } + { + Reference< XCloseable > closeable( statement, UNO_QUERY ); + if( closeable.is() ) + closeable->close(); + } + ret[elements] = row; + elements ++; + } + return new SequenceResultSet( + m_xMutex, *this, std::vector(getStatics().primaryKeyNames), std::move(ret), m_pSettings->tc ); +} + +// Copied / adapted / simplified from JDBC driver +#define SQL_CASE_KEYRULE " WHEN 'c' THEN " SAL_STRINGIFY(KEYRULE_CASCADE) \ + " WHEN 'n' THEN " SAL_STRINGIFY(KEYRULE_SET_NULL) \ + " WHEN 'd' THEN " SAL_STRINGIFY(KEYRULE_SET_DEFAULT) \ + " WHEN 'r' THEN " SAL_STRINGIFY(KEYRULE_RESTRICT) \ + " WHEN 'a' THEN " SAL_STRINGIFY(KEYRULE_NO_ACTION) \ + " ELSE NULL " + +#define SQL_GET_REFERENCES \ + "WITH con AS (SELECT oid, conname, contype, condeferrable, condeferred, conrelid, confrelid, confupdtype, confdeltype, generate_subscripts(conkey,1) AS conkeyseq, unnest(conkey) AS conkey , unnest(confkey) AS confkey FROM pg_catalog.pg_constraint) " \ + "SELECT NULL::text AS PKTABLE_CAT, pkn.nspname AS PKTABLE_SCHEM, pkc.relname AS PKTABLE_NAME, pka.attname AS PKCOLUMN_NAME, " \ + " NULL::text AS FKTABLE_CAT, fkn.nspname AS FKTABLE_SCHEM, fkc.relname AS FKTABLE_NAME, fka.attname AS FKCOLUMN_NAME, " \ + " con.conkeyseq AS KEY_SEQ, " \ + " CASE con.confupdtype " \ + SQL_CASE_KEYRULE \ + " END AS UPDATE_RULE, " \ + " CASE con.confdeltype " \ + SQL_CASE_KEYRULE \ + " END AS DELETE_RULE, " \ + " con.conname AS FK_NAME, pkic.relname AS PK_NAME, " \ + " CASE " \ + " WHEN con.condeferrable AND con.condeferred THEN " SAL_STRINGIFY(DEFERRABILITY_INITIALLY_DEFERRED) \ + " WHEN con.condeferrable THEN " SAL_STRINGIFY(DEFERRABILITY_INITIALLY_IMMEDIATE) \ + " ELSE " SAL_STRINGIFY(DEFERRABILITY_NONE) \ + " END AS DEFERRABILITY " \ + "FROM " \ + " pg_catalog.pg_namespace pkn, pg_catalog.pg_class pkc, pg_catalog.pg_attribute pka, " \ + " pg_catalog.pg_namespace fkn, pg_catalog.pg_class fkc, pg_catalog.pg_attribute fka, " \ + " con, pg_catalog.pg_depend dep, pg_catalog.pg_class pkic " \ + "WHERE pkn.oid = pkc.relnamespace AND pkc.oid = pka.attrelid AND pka.attnum = con.confkey AND con.confrelid = pkc.oid " \ + " AND fkn.oid = fkc.relnamespace AND fkc.oid = fka.attrelid AND fka.attnum = con.conkey AND con.conrelid = fkc.oid " \ + " AND con.contype = 'f' AND con.oid = dep.objid AND pkic.oid = dep.refobjid AND pkic.relkind = 'i' AND dep.classid = 'pg_constraint'::regclass::oid AND dep.refclassid = 'pg_class'::regclass::oid " + +#define SQL_GET_REFERENCES_PSCHEMA " AND pkn.nspname = ? " +#define SQL_GET_REFERENCES_PTABLE " AND pkc.relname = ? " +#define SQL_GET_REFERENCES_FSCHEMA " AND fkn.nspname = ? " +#define SQL_GET_REFERENCES_FTABLE " AND fkc.relname = ? " +#define SQL_GET_REFERENCES_ORDER_SOME_PTABLE "ORDER BY fkn.nspname, fkc.relname, conkeyseq" +#define SQL_GET_REFERENCES_ORDER_NO_PTABLE "ORDER BY pkn.nspname, pkc.relname, conkeyseq" + +#define SQL_GET_REFERENCES_NONE_NONE_NONE_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_SOME_NONE_NONE_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_NONE_SOME_NONE_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_SOME_SOME_NONE_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_NONE_NONE_SOME_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_NONE_NONE_NONE_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_NONE_NONE_SOME_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_SOME_NONE_SOME_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_SOME_NONE_NONE_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_SOME_NONE_SOME_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_NONE_SOME_SOME_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_NONE_SOME_NONE_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_NONE_SOME_SOME_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_SOME_SOME_SOME_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_SOME_SOME_NONE_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_SOME_SOME_SOME_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +void DatabaseMetaData::init_getReferences_stmt () +{ + m_getReferences_stmt[0] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_NONE); + m_getReferences_stmt[1] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_NONE); + m_getReferences_stmt[2] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_NONE); + m_getReferences_stmt[3] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_NONE); + m_getReferences_stmt[4] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_NONE); + m_getReferences_stmt[5] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_NONE); + m_getReferences_stmt[6] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_NONE); + m_getReferences_stmt[7] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_NONE); + m_getReferences_stmt[8] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_SOME); + m_getReferences_stmt[9] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_SOME); + m_getReferences_stmt[10] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_SOME); + m_getReferences_stmt[11] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_SOME); + m_getReferences_stmt[12] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_SOME); + m_getReferences_stmt[13] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_SOME); + m_getReferences_stmt[14] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_SOME); + m_getReferences_stmt[15] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_SOME); +} + +void DatabaseMetaData::init_getPrivs_stmt () +{ + OUStringBuffer sSQL(300); + sSQL.append( + " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.privilege, dp.is_grantable " + " FROM (" + " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name," + " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable" + " FROM information_schema.table_privileges"); + if ( PQserverVersion( m_pSettings->pConnection ) < 90200 ) + // information_schema.table_privileges does not fill in default ACLs when no ACL + // assume default ACL is "owner has all privileges" and add it + sSQL.append( + " UNION " + " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME," + " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable" + " FROM pg_catalog.pg_class c," + " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('DELETE'), ('TRUNCATE'), ('REFERENCES'), ('TRIGGER')) p (privilege)," + " pg_catalog.pg_roles ro," + " ( SELECT oid, rolname FROM pg_catalog.pg_roles" + " UNION ALL" + " VALUES (0::oid, 'PUBLIC')" + " ) AS rg (oid, rolname)," + " pg_catalog.pg_namespace pn" + " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')" + " AND c.relowner=ro.oid AND c.relnamespace = pn.oid"); + sSQL.append( + " ) dp," + " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr" + " WHERE table_schem LIKE ? AND table_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))" + " ORDER BY table_schem, table_name, privilege" ); + + m_getTablePrivs_stmt = m_origin->prepareStatement( sSQL.makeStringAndClear() ); + + sSQL.append( + " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.COLUMN_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.PRIVILEGE, dp.IS_GRANTABLE FROM (" + " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name, column_name," + " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable" + " FROM information_schema.column_privileges"); + if ( PQserverVersion( m_pSettings->pConnection ) < 90200 ) + // information_schema.table_privileges does not fill in default ACLs when no ACL + // assume default ACL is "owner has all privileges" and add it + sSQL.append( + " UNION " + " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME, a.attname AS column_name," + " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable" + " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a," + " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('REFERENCES')) p (privilege)," + " pg_catalog.pg_roles ro," + " ( SELECT oid, rolname FROM pg_catalog.pg_roles" + " UNION ALL" + " VALUES (0::oid, 'PUBLIC')" + " ) AS rg (oid, rolname)," + " pg_catalog.pg_namespace pn" + " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')" + " AND c.relowner=ro.oid AND c.relnamespace = pn.oid AND a.attrelid = c.oid AND a.attnum > 0"); + sSQL.append( + " ) dp," + " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr" + " WHERE table_schem = ? AND table_name = ? AND column_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))" + " ORDER BY column_name, privilege" ); + + m_getColumnPrivs_stmt = m_origin->prepareStatement( sSQL.makeStringAndClear() ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getImportedExportedKeys( + const Any& /* primaryCatalog */, + const OUString& primarySchema, + const OUString& primaryTable, + const Any& /* foreignCatalog */, + const OUString& foreignSchema, + const OUString& foreignTable ) +{ + unsigned int i = 0; + if ( ! primarySchema.isEmpty() ) + i |= 0x01; + if ( ! primaryTable.isEmpty() ) + i |= 0x02; + if ( ! foreignSchema.isEmpty() ) + i |= 0x04; + if ( ! foreignTable.isEmpty() ) + i |= 0x08; + + Reference< XPreparedStatement > stmt = m_getReferences_stmt[i]; + Reference< XParameters > param ( stmt, UNO_QUERY_THROW ); + + unsigned int j = 1; + if ( i & 0x01 ) + param->setString( j++, primarySchema ); + if ( i & 0x02 ) + param->setString( j++, primaryTable ); + if ( i & 0x04 ) + param->setString( j++, foreignSchema ); + if ( i & 0x08 ) + param->setString( j++, foreignTable ); + + Reference< XResultSet > rs = stmt->executeQuery(); + + return rs; +} + + +css::uno::Reference< XResultSet > DatabaseMetaData::getImportedKeys( + const css::uno::Any& catalog, + const OUString& schema, + const OUString& table ) +{ + return getImportedExportedKeys(Any(), OUString(), OUString(), catalog, schema, table); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getExportedKeys( + const css::uno::Any& catalog, + const OUString& schema, + const OUString& table ) +{ + return getImportedExportedKeys(catalog, schema, table, Any(), OUString(), OUString()); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getCrossReference( + const css::uno::Any& primaryCatalog, + const OUString& primarySchema, + const OUString& primaryTable, + const css::uno::Any& foreignCatalog, + const OUString& foreignSchema, + const OUString& foreignTable ) +{ + return getImportedExportedKeys( primaryCatalog, primarySchema, primaryTable, foreignCatalog, foreignSchema, foreignTable ); +} + +namespace +{ + struct TypeInfoByDataTypeSorter + { + bool operator () ( const std::vector< Any > & a, const std::vector< Any > & b ) + { + OUString valueA; + OUString valueB; + a[1 /*DATA_TYPE*/] >>= valueA; + b[1 /*DATA_TYPE*/] >>= valueB; + if( valueB.toInt32() == valueA.toInt32() ) + { + OUString nameA; + OUString nameB; + a[0 /*TYPE_NAME*/] >>= nameA; + b[0 /*TYPE_NAME*/] >>= nameB; + std::u16string_view nsA, tnA, nsB, tnB; + + // parse typename into schema and typename + sal_Int32 nIndex=0; + nsA = o3tl::getToken(nameA, 0, '.', nIndex); + if (nIndex<0) + { + tnA = nsA; + nsA = std::u16string_view(); + } + else + { + tnA = o3tl::getToken(nameA, 0, '.', nIndex); + assert(nIndex < 0); + } + + nIndex=0; + nsB = o3tl::getToken(nameB, 0, '.', nIndex); + if (nIndex<0) + { + tnB = nsB; + nsB = std::u16string_view(); + } + else + { + tnB = o3tl::getToken(nameB, 0, '.', nIndex); + assert(nIndex < 0); + } + + const int ns_comp = compare_schema(nsA, nsB); + if(ns_comp == 0) + { + if(nsA.empty()) + { + assert(nsB.empty()); + // within each type category, sort privileged choice first + if( tnA == u"int4" || tnA == u"varchar" || tnA == u"char" || tnA == u"text") + return true; + if( tnB == u"int4" || tnB == u"varchar" || tnB == u"char" || tnB == u"text") + return false; + } + return nameA.compareTo( nameB ) < 0; + } + else + { + return ns_comp < 0; + } + } + + return valueA.toInt32() < valueB.toInt32(); + } + }; + + sal_Int32 calcSearchable( sal_Int32 dataType ) + { + sal_Int32 ret = css::sdbc::ColumnSearch::FULL; + if( css::sdbc::DataType::BINARY == dataType || + css::sdbc::DataType::VARBINARY == dataType || + css::sdbc::DataType::LONGVARBINARY == dataType ) + ret = css::sdbc::ColumnSearch::NONE; + + return ret; + } + + sal_Int32 getMaxScale( sal_Int32 dataType ) + { + // LEM TODO: review, see where used, see JDBC, ... + sal_Int32 ret = 0; + if( dataType == css::sdbc::DataType::NUMERIC ) + ret = 1000; // see pg-docs DataType/numeric +// else if( dataType == DataType::DOUBLE ) +// ret = 308; +// else if( dataType == DataType::FLOAT ) +// ret = + return ret; + } + + OUString construct_full_typename(std::u16string_view ns, const OUString &tn) + { + if(ns.empty() || ns == u"pg_catalog") + return tn; + else + return OUString::Concat(ns) + "." + tn; + } + + void pgTypeInfo2ResultSet( + std::vector< std::vector<Any> > &vec, + const Reference< XResultSet > &rs ) + { + static const sal_Int32 TYPE_NAME = 0; // string Type name + static const sal_Int32 DATA_TYPE = 1; // short SQL data type from java.sql.Types + static const sal_Int32 PRECISION = 2; // long maximum precision + static const sal_Int32 CREATE_PARAMS = 5; // string => parameters used in creating the type (may be NULL ) + static const sal_Int32 NULLABLE = 6; // short ==> can you use NULL for this type? + // - NO_NULLS - does not allow NULL values + // - NULLABLE - allows NULL values + // - NULLABLE_UNKNOWN - nullability unknown + + static const sal_Int32 CASE_SENSITIVE = 7; // boolean==> is it case sensitive + static const sal_Int32 SEARCHABLE = 8; // short ==>; can you use + // "WHERE" based on this type: + // - NONE - No support + // - CHAR - Only supported with WHERE .. LIKE + // - BASIC - Supported except for WHERE .. LIKE + // - FULL - Supported for all WHERE .. + static const sal_Int32 UNSIGNED_ATTRIBUTE = 9; // boolean ==> is it unsigned? + // FIXED_PREC_SCALE = 10; boolean ==> can it be a money value? + static const sal_Int32 AUTO_INCREMENT = 11; // boolean ==> can it be used for + // an auto-increment value? + static const sal_Int32 MINIMUM_SCALE = 13; // short ==> minimum scale supported + static const sal_Int32 MAXIMUM_SCALE = 14; // short ==> maximum scale supported + static const sal_Int32 NUM_PREC_RADIX = 17; // long ==> usually 2 or 10 + + /* not filled so far + 3. LITERAL_PREFIX string ==> prefix used to quote a literal + (may be <NULL/>) + 4. LITERAL_SUFFIX string ==> suffix used to quote a literal + (may be <NULL/>) + 5. CREATE_PARAMS string ==> parameters used in creating the type (may be <NULL/>) + 12. LOCAL_TYPE_NAME string ==> localized version of type name (may be <NULL/>) + 15, SQL_DATA_TYPE long ==> unused + 16. SQL_DATETIME_SUB long ==> unused + */ + Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + while( rs->next() ) + { + std::vector< Any > row(18); + + sal_Int32 dataType =typeNameToDataType(xRow->getString(5),xRow->getString(2)); + sal_Int32 precision = xRow->getString(3).toInt32(); + + if( dataType == css::sdbc::DataType::CHAR || + ( dataType == css::sdbc::DataType::VARCHAR && + xRow->getString(TYPE_NAME+1).equalsIgnoreAsciiCase("varchar") ) ) + { + // reflect varchar as varchar with upper limit ! + //NOTE: the sql spec requires varchar to have an upper limit, however + // in postgresql the upper limit is optional, no limit means unlimited + // length (=1GB). + precision = 0x40000000; // about 1 GB, see character type docs in postgresql + row[CREATE_PARAMS] <<= OUString("length"); + } + else if( dataType == css::sdbc::DataType::NUMERIC ) + { + precision = 1000; + row[CREATE_PARAMS] <<= OUString("length, scale"); + } + + row[TYPE_NAME] <<= construct_full_typename(xRow->getString(6), xRow->getString(1)); + row[DATA_TYPE] <<= OUString::number(dataType); + row[PRECISION] <<= OUString::number( precision ); + sal_Int32 nullable = xRow->getBoolean(4) ? + css::sdbc::ColumnValue::NO_NULLS : + css::sdbc::ColumnValue::NULLABLE; + row[NULLABLE] <<= OUString::number(nullable); + row[CASE_SENSITIVE] <<= OUString::number(1); + row[SEARCHABLE] <<= OUString::number( calcSearchable( dataType ) ); + row[UNSIGNED_ATTRIBUTE] <<= OUString("0"); + if( css::sdbc::DataType::INTEGER == dataType || + css::sdbc::DataType::BIGINT == dataType ) + row[AUTO_INCREMENT] <<= OUString("1"); // TODO + else + row[AUTO_INCREMENT] <<= OUString("0"); // TODO + row[MINIMUM_SCALE] <<= OUString("0"); // TODO: what is this ? + row[MAXIMUM_SCALE] <<= OUString::number( getMaxScale( dataType ) ); + row[NUM_PREC_RADIX] <<= OUString("10"); // TODO: what is this ? + vec.push_back( row ); + } + } +} + + +css::uno::Reference< XResultSet > DatabaseMetaData::getTypeInfo( ) +{ + // Note: Indexes start at 0 (in the API doc, they start at 1) + MutexGuard guard( m_xMutex->GetMutex() ); + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTypeInfo() got called"); + + Reference< XStatement > statement = m_origin->createStatement(); + Reference< XResultSet > rs = statement->executeQuery( + "SELECT pg_type.typname AS typname," //1 + "pg_type.typtype AS typtype," //2 + "pg_type.typlen AS typlen," //3 + "pg_type.typnotnull AS typnotnull," //4 + "pg_type.typname AS typname, " //5 + "pg_namespace.nspname as typns " //6 + "FROM pg_type LEFT JOIN pg_namespace ON pg_type.typnamespace=pg_namespace.oid " + "WHERE pg_type.typtype = 'b' " + "OR pg_type.typtype = 'p'" + ); + + std::vector< std::vector<Any> > vec; + pgTypeInfo2ResultSet( vec, rs ); + + // check for domain types + rs = statement->executeQuery( + "SELECT t1.typname as typname," + "t2.typtype AS typtype," + "t2.typlen AS typlen," + "t2.typnotnull AS typnotnull," + "t2.typname as realtypname, " + "pg_namespace.nspname as typns " + "FROM pg_type as t1 LEFT JOIN pg_type AS t2 ON t1.typbasetype=t2.oid LEFT JOIN pg_namespace ON t1.typnamespace=pg_namespace.oid " + "WHERE t1.typtype = 'd'" ); + pgTypeInfo2ResultSet( vec, rs ); + + std::sort( vec.begin(), vec.end(), TypeInfoByDataTypeSorter() ); + + return new SequenceResultSet( + m_xMutex, + *this, + std::vector(getStatics().typeinfoColumnNames), + std::move(vec), + m_pSettings->tc, + &( getStatics().typeInfoMetaData )); +} + + +css::uno::Reference< XResultSet > DatabaseMetaData::getIndexInfo( + const css::uno::Any& , + const OUString& schema, + const OUString& table, + sal_Bool unique, + sal_Bool ) +{ + //LEM TODO: review + MutexGuard guard( m_xMutex->GetMutex() ); + + /* + 1. TABLE_CAT string -> table catalog (may be NULL ) + 2. TABLE_SCHEM string -> table schema (may be NULL ) + 3. TABLE_NAME string -> table name + 4. NON_UNIQUE boolean -> Can index values be non-unique? + false when TYPE is tableIndexStatistic + 5. INDEX_QUALIFIER string -> index catalog (may be NULL ); + NULL when TYPE is tableIndexStatistic + 6. INDEX_NAME string -> index name; NULL when TYPE is tableIndexStatistic + 7. TYPE short -> index type: + * 0 - this identifies table statistics that are returned + in conjunction with a table's index descriptions + * CLUSTERED - this is a clustered index + * HASHED - this is a hashed index + * OTHER - this is some other style of index + 8. ORDINAL_POSITION short -> column sequence number within index; + zero when TYPE is tableIndexStatistic + 9. COLUMN_NAME string -> column name; NULL when TYPE is tableIndexStatistic + 10. ASC_OR_DESC string -> column sort sequence, "A"= ascending, + "D" = descending, may be NULL if sort sequence + is not supported; NULL when TYPE is tableIndexStatistic + 11. CARDINALITY long -> When TYPE is tableIndexStatistic, then this is + the number of rows in the table; otherwise, it + is the number of unique values in the index. + 12. PAGES long -> When TYPE is tableIndexStatistic then this is + the number of pages used for the table, otherwise + it is the number of pages used for the current index. + 13. FILTER_CONDITION string -> Filter condition, if any. (may be NULL ) + + */ + static const sal_Int32 C_SCHEMA = 1; + static const sal_Int32 C_TABLENAME = 2; + static const sal_Int32 C_INDEXNAME = 3; + static const sal_Int32 C_IS_CLUSTERED = 4; + static const sal_Int32 C_IS_UNIQUE = 5; + // C_IS_PRIMARY = 6 + static const sal_Int32 C_COLUMNS = 7; + + static const sal_Int32 R_TABLE_SCHEM = 1; + static const sal_Int32 R_TABLE_NAME = 2; + static const sal_Int32 R_NON_UNIQUE = 3; + static const sal_Int32 R_INDEX_NAME = 5; + static const sal_Int32 R_TYPE = 6; + static const sal_Int32 R_ORDINAL_POSITION = 7; + static const sal_Int32 R_COLUMN_NAME = 8; + + Reference< XPreparedStatement > stmt = m_origin->prepareStatement( + "SELECT nspname, " // 1 + "pg_class.relname, " // 2 + "class2.relname, " // 3 + "indisclustered, " // 4 + "indisunique, " // 5 + "indisprimary, " // 6 + "indkey " // 7 + "FROM pg_index INNER JOIN pg_class ON indrelid = pg_class.oid " + "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid " + "INNER JOIN pg_class as class2 ON pg_index.indexrelid = class2.oid " + "WHERE nspname = ? AND pg_class.relname = ?" ); + + Reference< XParameters > param ( stmt, UNO_QUERY_THROW ); + param->setString( 1, schema ); + param->setString( 2, table ); + Reference< XResultSet > rs = stmt->executeQuery(); + Reference< XRow > xRow ( rs, UNO_QUERY_THROW ); + + std::vector< std::vector<Any> > vec; + while( rs->next() ) + { + std::vector< sal_Int32 > columns = parseIntArray( xRow->getString(C_COLUMNS) ); + Reference< XPreparedStatement > columnsStmt = m_origin->prepareStatement( + "SELECT attnum, attname " + "FROM pg_attribute " + " INNER JOIN pg_class ON attrelid = pg_class.oid " + " INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid " + " WHERE pg_namespace.nspname=? AND pg_class.relname=?" ); + Reference< XParameters > paramColumn ( columnsStmt, UNO_QUERY_THROW ); + OUString currentSchema = xRow->getString( C_SCHEMA ); + OUString currentTable = xRow->getString( C_TABLENAME ); + OUString currentIndexName = xRow->getString( C_INDEXNAME ); + bool isNonUnique = ! xRow->getBoolean( C_IS_UNIQUE ); + sal_Int32 indexType = xRow->getBoolean( C_IS_CLUSTERED ) ? + css::sdbc::IndexType::CLUSTERED : + css::sdbc::IndexType::HASHED; + + paramColumn->setString( C_SCHEMA, currentSchema ); + paramColumn->setString( C_TABLENAME, currentTable ); + + Reference< XResultSet > rsColumn = columnsStmt->executeQuery(); + Reference< XRow > rowColumn( rsColumn, UNO_QUERY_THROW ); + while( rsColumn->next() ) + { + auto findIt = std::find( columns.begin(), columns.end(), rowColumn->getInt( 1 ) ); + if( findIt != columns.end() && ( ! isNonUnique || ! unique ) ) + { + std::vector< Any > result( 13 ); + result[R_TABLE_SCHEM] <<= currentSchema; + result[R_TABLE_NAME] <<= currentTable; + result[R_INDEX_NAME] <<= currentIndexName; + result[R_NON_UNIQUE] <<= isNonUnique; + result[R_TYPE] <<= indexType; + result[R_COLUMN_NAME] <<= rowColumn->getString(2); + sal_Int32 nPos = static_cast<sal_Int32>(findIt - columns.begin() +1); // MSVC++ nonsense + result[R_ORDINAL_POSITION] <<= nPos; + vec.push_back( result ); + } + } + } + return new SequenceResultSet( + m_xMutex, *this, std::vector(getStatics().indexinfoColumnNames), + std::move(vec), + m_pSettings->tc ); +} + +sal_Bool DatabaseMetaData::supportsResultSetType( sal_Int32 setType ) +{ + if ( setType == css::sdbc::ResultSetType::SCROLL_SENSITIVE ) + return false; + else + return true; +} + +sal_Bool DatabaseMetaData::supportsResultSetConcurrency( + sal_Int32 setType, sal_Int32 ) +{ + if ( ! supportsResultSetType( setType ) ) + return false; + else + return true; +} + +sal_Bool DatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /* setType */ ) +{ + return true; +} + +sal_Bool DatabaseMetaData::ownDeletesAreVisible( sal_Int32 /* setType */ ) +{ + return true; +} + +sal_Bool DatabaseMetaData::ownInsertsAreVisible( sal_Int32 /* setType */ ) +{ + return true; +} + +sal_Bool DatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /* setType */ ) +{ + return false; +} + +sal_Bool DatabaseMetaData::othersDeletesAreVisible( sal_Int32 /* setType */ ) +{ + return false; +} + +sal_Bool DatabaseMetaData::othersInsertsAreVisible( sal_Int32 /* setType */ ) +{ + return false; +} + +sal_Bool DatabaseMetaData::updatesAreDetected( sal_Int32 /* setType */ ) +{ + return false; +} + +sal_Bool DatabaseMetaData::deletesAreDetected( sal_Int32 /* setType */ ) +{ + return false; +} +sal_Bool DatabaseMetaData::insertsAreDetected( sal_Int32 /* setType */ ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsBatchUpdates( ) +{ + return true; +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getUDTs( const css::uno::Any&, const OUString&, const OUString&, const css::uno::Sequence< sal_Int32 >& ) +{ + //LEM TODO: implement! See JDBC driver + MutexGuard guard( m_xMutex->GetMutex() ); + return new SequenceResultSet( + m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc ); +} + +css::uno::Reference< css::sdbc::XConnection > DatabaseMetaData::getConnection() +{ + return m_origin; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_databasemetadata.hxx b/connectivity/source/drivers/postgresql/pq_databasemetadata.hxx new file mode 100644 index 000000000..134f72cf0 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_databasemetadata.hxx @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include "pq_connection.hxx" +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> + +#include <cppuhelper/implbase.hxx> + +namespace pq_sdbc_driver +{ + +class DatabaseMetaData : + public ::cppu::WeakImplHelper< css::sdbc::XDatabaseMetaData > +{ + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + ConnectionSettings *m_pSettings; + css::uno::Reference< css::sdbc::XConnection > m_origin; + css::uno::Reference< css::sdbc::XPreparedStatement > m_getIntSetting_stmt; + css::uno::Reference< css::sdbc::XPreparedStatement > m_getReferences_stmt[16]; + css::uno::Reference< css::sdbc::XPreparedStatement > m_getTablePrivs_stmt; + css::uno::Reference< css::sdbc::XPreparedStatement > m_getColumnPrivs_stmt; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getIntSetting(const OUString& settingName); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getMaxIndexKeys(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getMaxNameLength(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + css::uno::Reference< css::sdbc::XResultSet > getImportedExportedKeys( + const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, + const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ); + void init_getReferences_stmt (); + void init_getPrivs_stmt (); + +public: + DatabaseMetaData( + const ::rtl::Reference< comphelper::RefCountedMutex > & reMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings + ); + +public: + // Methods + virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override; + virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override; + virtual OUString SAL_CALL getURL( ) override; + virtual OUString SAL_CALL getUserName( ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override; + virtual OUString SAL_CALL getDatabaseProductName( ) override; + virtual OUString SAL_CALL getDatabaseProductVersion( ) override; + virtual OUString SAL_CALL getDriverName( ) override; + virtual OUString SAL_CALL getDriverVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override; + virtual sal_Bool SAL_CALL usesLocalFiles( ) override; + virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers( ) override; + virtual OUString SAL_CALL getIdentifierQuoteString( ) override; + virtual OUString SAL_CALL getSQLKeywords( ) override; + virtual OUString SAL_CALL getNumericFunctions( ) override; + virtual OUString SAL_CALL getStringFunctions( ) override; + virtual OUString SAL_CALL getSystemFunctions( ) override; + virtual OUString SAL_CALL getTimeDateFunctions( ) override; + virtual OUString SAL_CALL getSearchStringEscape( ) override; + virtual OUString SAL_CALL getExtraNameCharacters( ) override; + virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override; + virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override; + virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override; + virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override; + virtual sal_Bool SAL_CALL supportsTypeConversion( ) override; + virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override; + virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override; + virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupBy( ) override; + virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override; + virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override; + virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override; + virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override; + virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override; + virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override; + virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override; + virtual sal_Bool SAL_CALL supportsOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override; + virtual OUString SAL_CALL getSchemaTerm( ) override; + virtual OUString SAL_CALL getProcedureTerm( ) override; + virtual OUString SAL_CALL getCatalogTerm( ) override; + virtual sal_Bool SAL_CALL isCatalogAtStart( ) override; + virtual OUString SAL_CALL getCatalogSeparator( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInDataManipulation( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInTableDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInDataManipulation( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInTableDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override; + virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override; + virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override; + virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override; + virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override; + virtual sal_Bool SAL_CALL supportsUnion( ) override; + virtual sal_Bool SAL_CALL supportsUnionAll( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override; + virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override; + virtual sal_Int32 SAL_CALL getMaxConnections( ) override; + virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override; + virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxRowSize( ) override; + virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override; + virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override; + virtual sal_Int32 SAL_CALL getMaxStatements( ) override; + virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxTablesInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override; + virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override; + virtual sal_Bool SAL_CALL supportsTransactions( ) override; + virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override; + virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override; + virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override; + virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override; + virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTypeInfo( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override; + virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override; + virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_driver.cxx b/connectivity/source/drivers/postgresql/pq_driver.cxx new file mode 100644 index 000000000..09fe61ab2 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_driver.cxx @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/weak.hxx> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> + +#include "pq_driver.hxx" + +using osl::MutexGuard; + +using com::sun::star::lang::XSingleComponentFactory; +using com::sun::star::lang::XServiceInfo; +using com::sun::star::lang::XComponent; + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::Any; + +using com::sun::star::beans::PropertyValue; + +using com::sun::star::sdbc::XConnection; +using com::sun::star::sdbc::DriverPropertyInfo; + +using com::sun::star::sdbcx::XTablesSupplier; + + +namespace pq_sdbc_driver +{ + +Reference< XConnection > Driver::connect( + const OUString& url,const Sequence< PropertyValue >& info ) +{ + if( ! acceptsURL( url ) ) // XDriver spec tells me to do so ... + return Reference< XConnection > (); + + Sequence< Any > seq{ Any(url), Any(info) }; + return Reference< XConnection> ( + m_smgr->createInstanceWithArgumentsAndContext( + "org.openoffice.comp.connectivity.pq.Connection.noext", + seq, m_ctx ), + UNO_QUERY ); +} + +sal_Bool Driver::acceptsURL( const OUString& url ) +{ + return url.startsWith( "sdbc:postgresql:" ); +} + +Sequence< DriverPropertyInfo > Driver::getPropertyInfo( + const OUString&,const Sequence< PropertyValue >& ) +{ + return Sequence< DriverPropertyInfo > (); +} + +sal_Int32 Driver::getMajorVersion( ) +{ + return PQ_SDBC_MAJOR; +} + + +sal_Int32 Driver::getMinorVersion( ) +{ + return PQ_SDBC_MINOR; +} + + // XServiceInfo +OUString SAL_CALL Driver::getImplementationName() +{ + return "org.openoffice.comp.connectivity.pq.Driver.noext"; +} + +sal_Bool Driver::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > Driver::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.Driver" }; +} + +// XComponent +void Driver::disposing() +{ + +} + + +Reference< XTablesSupplier > Driver::getDataDefinitionByConnection( + const Reference< XConnection >& connection ) +{ + return Reference< XTablesSupplier >( connection , UNO_QUERY ); +} + +Reference< XTablesSupplier > Driver::getDataDefinitionByURL( + const OUString& url, const Sequence< PropertyValue >& info ) +{ + return Reference< XTablesSupplier > ( connect( url, info ), UNO_QUERY ); +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +connectivity_pq_sdbc_driver_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new pq_sdbc_driver::Driver(context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_driver.hxx b/connectivity/source/drivers/postgresql/pq_driver.hxx new file mode 100644 index 000000000..31d407f36 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_driver.hxx @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <sal/macros.h> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> + +#include <com/sun/star/uno/XComponentContext.hpp> + +namespace pq_sdbc_driver +{ + +#define PQ_SDBC_DRIVER_VERSION SAL_STRINGIFY(PQ_SDBC_MAJOR) "." \ + SAL_STRINGIFY(PQ_SDBC_MINOR) "." \ + SAL_STRINGIFY(PQ_SDBC_MICRO) + +// use this to switch off sdbc support ! +// typedef cppu::WeakComponentImplHelper< +// css::sdbc::XDriver, +// css::lang::XServiceInfo +// > DriverBase ; +typedef cppu::WeakComponentImplHelper< + css::sdbc::XDriver, + css::lang::XServiceInfo, + css::sdbcx::XDataDefinitionSupplier > DriverBase ; +class Driver : public cppu::BaseMutex, public DriverBase +{ + css::uno::Reference< css::uno::XComponentContext > m_ctx; + css::uno::Reference< css::lang::XMultiComponentFactory > m_smgr; + +public: + explicit Driver ( const css::uno::Reference < css::uno::XComponentContext > & ctx ) + : DriverBase( m_aMutex ), + m_ctx( ctx ), + m_smgr( ctx->getServiceManager() ) + {} + +public: // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( + const OUString& url, + const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( + const OUString& url, + const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + + virtual sal_Int32 SAL_CALL getMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getMinorVersion( ) override; + +public: + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XDataDefinitionSupplier + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL + getDataDefinitionByConnection( + const css::uno::Reference< css::sdbc::XConnection >& connection ) override; + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL + getDataDefinitionByURL( + const OUString& url, + const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + + // XComponent + virtual void SAL_CALL disposing() override; + +}; + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx new file mode 100644 index 000000000..a75897ccb --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include "pq_fakedupdateableresultset.hxx" +#include <com/sun/star/sdbc/SQLException.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> + + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::sdbc::SQLException; +using com::sun::star::sdbc::XResultSetUpdate; +using com::sun::star::sdbc::XRowUpdate; + +namespace pq_sdbc_driver +{ + +FakedUpdateableResultSet::FakedUpdateableResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + ConnectionSettings **pSettings, + PGresult *result, + const OUString &schema, + const OUString &table, + const OUString &aReason ) + : ResultSet( mutex, owner, pSettings, result, schema, table ), + m_aReason( aReason ) +{} + + +css::uno::Any FakedUpdateableResultSet::queryInterface( + const css::uno::Type & reqType ) +{ + Any ret = ResultSet::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< XResultSetUpdate * > ( this ), + static_cast< XRowUpdate * > ( this ) ); + return ret; +} + + +css::uno::Sequence< css::uno::Type > FakedUpdateableResultSet::getTypes() +{ + static cppu::OTypeCollection s_collection( + cppu::UnoType<XResultSetUpdate>::get(), + cppu::UnoType<XRowUpdate>::get(), + ResultSet::getTypes()); + + return s_collection.getTypes(); + +} + +css::uno::Sequence< sal_Int8> FakedUpdateableResultSet::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +void FakedUpdateableResultSet::insertRow( ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateRow( ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::deleteRow( ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); + } + +void FakedUpdateableResultSet::cancelRowUpdates( ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::moveToInsertRow( ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::moveToCurrentRow( ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + + +void FakedUpdateableResultSet::updateNull( sal_Int32 /* columnIndex */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateBoolean( sal_Int32 /* columnIndex */, sal_Bool /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateByte( sal_Int32 /* columnIndex */, sal_Int8 /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateShort( sal_Int32 /* columnIndex */, sal_Int16 /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateInt( sal_Int32 /* columnIndex */, sal_Int32 /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateLong( sal_Int32 /* columnIndex */, sal_Int64 /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateFloat( sal_Int32 /* columnIndex */, float /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateDouble( sal_Int32 /* columnIndex */, double /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateString( sal_Int32 /* columnIndex */, const OUString& /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateBytes( sal_Int32 /* columnIndex */, const css::uno::Sequence< sal_Int8 >& /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateDate( sal_Int32 /* columnIndex */, const css::util::Date& /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateTime( sal_Int32 /* columnIndex */, const css::util::Time& /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateTimestamp( sal_Int32 /* columnIndex */, const css::util::DateTime& /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateBinaryStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateCharacterStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateNumericObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */, sal_Int32 /* scale */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.hxx b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.hxx new file mode 100644 index 000000000..c2907aeb0 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.hxx @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> + +#include "pq_resultset.hxx" + +namespace pq_sdbc_driver +{ +/** necessary to avoid crashes in OOo, when an updateable result set is requested, + but cannot be delivered. + */ +class FakedUpdateableResultSet : + public ResultSet, + public css::sdbc::XResultSetUpdate, + public css::sdbc::XRowUpdate +{ + OUString m_aReason; + +public: + FakedUpdateableResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + ConnectionSettings **pSettings, + PGresult *result, + const OUString &schema, + const OUString &table, + const OUString &aReason ); + +public: // XInterface + virtual void SAL_CALL acquire() noexcept override { ResultSet::acquire(); } + virtual void SAL_CALL release() noexcept override { ResultSet::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XResultSetUpdate + virtual void SAL_CALL insertRow( ) override; + virtual void SAL_CALL updateRow( ) override; + virtual void SAL_CALL deleteRow( ) override; + virtual void SAL_CALL cancelRowUpdates( ) override; + virtual void SAL_CALL moveToInsertRow( ) override; + virtual void SAL_CALL moveToCurrentRow( ) override; + +public: // XRowUpdate + virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override; + virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override; + virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override; + virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override; + virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override; + virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override; + virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override; + virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override; + virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override; + virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override; + virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override; + virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override; + +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_preparedstatement.cxx b/connectivity/source/drivers/postgresql/pq_preparedstatement.cxx new file mode 100644 index 000000000..2f31b4226 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_preparedstatement.cxx @@ -0,0 +1,738 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include "pq_preparedstatement.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" +#include "pq_statement.hxx" + +#include <o3tl/safeint.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> + + +#include <comphelper/sequence.hxx> + +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <memory> +#include <string.h> +#include <string_view> + +#include <connectivity/dbconversion.hxx> + +using osl::MutexGuard; + + +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::UNO_QUERY; + +using com::sun::star::lang::IllegalArgumentException; + +using com::sun::star::sdbc::XCloseable; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XRef; +using com::sun::star::sdbc::XBlob; +using com::sun::star::sdbc::XClob; +using com::sun::star::sdbc::XArray; +using com::sun::star::sdbc::XConnection; +using com::sun::star::sdbc::SQLException; + +using com::sun::star::beans::Property; +using com::sun::star::beans::XPropertySetInfo; + +using namespace dbtools; + +namespace pq_sdbc_driver +{ +static ::cppu::IPropertyArrayHelper & getPreparedStatementPropertyArrayHelper() +{ + static ::cppu::OPropertyArrayHelper arrayHelper( + Sequence<Property>{ + Property( + "CursorName", 0, + ::cppu::UnoType<OUString>::get() , 0 ), + Property( + "EscapeProcessing", 1, + cppu::UnoType<bool>::get() , 0 ), + Property( + "FetchDirection", 2, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "FetchSize", 3, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "MaxFieldSize", 4, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "MaxRows", 5, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "QueryTimeOut", 6, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "ResultSetConcurrency", 7, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "ResultSetType", 8, + ::cppu::UnoType<sal_Int32>::get() , 0 )}, + true ); + static ::cppu::IPropertyArrayHelper *pArrayHelper = &arrayHelper; + + return *pArrayHelper; +} + +static bool isOperator( char c ) +{ + static const char * const operators = "<>=()!/&%.,;"; + + const char * w = operators; + while (*w && *w != c) + { + ++w; + } + return *w != 0; +} + +static bool isNamedParameterStart( std::string_view o , int index ) +{ + return o[index] == ':' && ( + isWhitespace( o[index-1] ) || isOperator(o[index-1]) ); +} + +static bool isQuoted( std::string_view str ) +{ + return str[0] == '"' || str[0] == '\''; +} + +PreparedStatement::PreparedStatement( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< XConnection > & conn, + struct ConnectionSettings *pSettings, + const OString & stmt ) + : PreparedStatement_BASE(refMutex->GetMutex()) + , OPropertySetHelper(PreparedStatement_BASE::rBHelper) + , m_connection(conn) + , m_pSettings(pSettings) + , m_stmt(stmt) + , m_xMutex(refMutex) + , m_multipleResultAvailable(false) + , m_multipleResultUpdateCount(0) + , m_lastOidInserted( InvalidOid ) +{ + m_props[PREPARED_STATEMENT_QUERY_TIME_OUT] <<= sal_Int32(0); + m_props[PREPARED_STATEMENT_MAX_ROWS] <<= sal_Int32(0); + m_props[PREPARED_STATEMENT_RESULT_SET_CONCURRENCY] <<= + css::sdbc::ResultSetConcurrency::READ_ONLY; + m_props[PREPARED_STATEMENT_RESULT_SET_TYPE] <<= + css::sdbc::ResultSetType::SCROLL_INSENSITIVE; + + splitSQL( m_stmt, m_splittedStatement ); + int elements = 0; + for(const OString & str : m_splittedStatement) + { + // ignore quoted strings... + if( ! isQuoted( str ) ) + { + // the ':' cannot be the first or the last part of the + // token, + // the ? cannot be the first part of the token , so we start + // at one + for( int index = 1 ; index < str.getLength() ; index ++ ) + { + if( str[index] == '?' || + isNamedParameterStart( str , index ) + ) + { + elements ++; + } + } + } + } + m_vars = std::vector< OString >( elements ); +} + +PreparedStatement::~PreparedStatement() +{ +} + +void PreparedStatement::checkColumnIndex( sal_Int32 parameterIndex ) +{ + if( parameterIndex < 1 || o3tl::make_unsigned(parameterIndex) > m_vars.size() ) + { + throw SQLException( + "pq_preparedstatement: parameter index out of range (expected 1 to " + + OUString::number( m_vars.size() ) + + ", got " + OUString::number( parameterIndex ) + + ", statement '" + OStringToOUString( m_stmt, ConnectionSettings::encoding ) + + "')", + *this, OUString(), 1, Any () ); + } +} +void PreparedStatement::checkClosed() +{ + if( ! m_pSettings || ! m_pSettings->pConnection ) + throw SQLException( + "pq_driver: PreparedStatement or connection has already been closed !", + *this, OUString(),1,Any()); +} + +Any PreparedStatement::queryInterface( const Type & rType ) +{ + Any aRet = PreparedStatement_BASE::queryInterface(rType); + return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType); +} + + +Sequence< Type > PreparedStatement::getTypes() +{ + static Sequence< Type > collection( + ::comphelper::concatSequences( + OPropertySetHelper::getTypes(), + PreparedStatement_BASE::getTypes())); + + return collection; +} + +Sequence< sal_Int8> PreparedStatement::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +void PreparedStatement::close( ) +{ + // let the connection die without acquired mutex ! + Reference< XConnection > r; + Reference< XCloseable > resultSet; + { + MutexGuard guard( m_xMutex->GetMutex() ); + m_pSettings = nullptr; + r = m_connection; + m_connection.clear(); + + resultSet = m_lastResultset; + m_lastResultset.clear(); + } + if( resultSet.is() ) + { + resultSet->close(); + } +} + +void PreparedStatement::raiseSQLException( const char * errorMsg ) +{ + OUStringBuffer buf(128); + buf.append( "pq_driver: "); + buf.append( + OUString( errorMsg, strlen(errorMsg) , ConnectionSettings::encoding ) ); + buf.append( " (caused by statement '" ); + buf.appendAscii( m_executedStatement.getStr() ); + buf.append( "')" ); + OUString error = buf.makeStringAndClear(); + SAL_WARN("connectivity.postgresql", error); + throw SQLException( error, *this, OUString(), 1, Any() ); +} + +Reference< XResultSet > PreparedStatement::executeQuery( ) +{ + if( ! execute( ) ) + { + raiseSQLException( "not a query" ); + } + return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY ); +} + +sal_Int32 PreparedStatement::executeUpdate( ) +{ + if( execute( ) ) + { + raiseSQLException( "not a command" ); + } + return m_multipleResultUpdateCount; +} + +sal_Bool PreparedStatement::execute( ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + OStringBuffer buf( m_stmt.getLength() *2 ); + + std::vector< OString >::size_type vars = 0; + for(const OString & str : m_splittedStatement) + { + // LEM TODO: instead of this manual mucking with SQL + // could we use PQexecParams / PQExecPrepared / ...? + // Only snafu is giving the types of the parameters and + // that it needs $1, $2, etc instead of "?" + +// printf( "Split %d %s\n" , i , str.getStr() ); + if( isQuoted( str ) ) + { + buf.append( str ); + } + else + { + int start = 0,index; + for( index = 1 ; index < str.getLength() ; index ++ ) + { + if( str[index] == '?' ) + { + buf.append( str.getStr()+start, index - start ); + buf.append( m_vars[vars] ); + vars ++; + start =index+1; + } + else + { + if ( isNamedParameterStart( str, index ) ) + { + buf.append( str.getStr()+start, index -start ); + buf.append( m_vars[vars] ); + + // skip to the end of the named parameter + while ( index < str.getLength() + && !( isWhitespace(str[index]) + || isOperator (str[index]))) + { + ++index; + } + start = index; + vars ++; + } + } + } +// if( index +1 >= str.getLength() ) +// { + buf.append( str.getStr() + start, index -start ); +// } + } + } + + m_executedStatement = buf.makeStringAndClear(); + + Reference< XCloseable > lastResultSet = m_lastResultset; + if( lastResultSet.is() ) + lastResultSet->close(); + + m_lastResultset.clear(); + m_lastTableInserted.clear(); + + struct CommandData data; + data.refMutex = m_xMutex; + data.ppSettings = &m_pSettings; + data.pLastOidInserted = &m_lastOidInserted; + data.pLastQuery = &m_lastQuery; + data.pMultipleResultUpdateCount = &m_multipleResultUpdateCount; + data.pMultipleResultAvailable = &m_multipleResultAvailable; + data.pLastTableInserted = &m_lastTableInserted; + data.pLastResultset = &m_lastResultset; + data.owner = *this; + data.tableSupplier.set( m_connection, UNO_QUERY ); + data.concurrency = extractIntProperty( this, getStatics().RESULT_SET_CONCURRENCY ); + + return executePostgresCommand( m_executedStatement , &data ); // see pq_statement.cxx +} + +Reference< XConnection > PreparedStatement::getConnection( ) +{ + Reference< XConnection > ret; + { + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + ret = m_connection; + } + return ret; +} + + +void PreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + m_vars[parameterIndex-1] = OString( "NULL" ); +} + +void PreparedStatement::setObjectNull( + sal_Int32 parameterIndex, sal_Int32, const OUString& ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + m_vars[parameterIndex-1] = OString( "NULL" ); +} + + +void PreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x ) +{ + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + if( x ) + m_vars[parameterIndex-1] = OString( "'t'" ); + else + m_vars[parameterIndex-1] = OString( "'f'" ); +} + +void PreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x ) +{ + setInt(parameterIndex,x); +} + +void PreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x ) +{ + setInt(parameterIndex, x ); +} + +void PreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x ) +{ +// printf( "setString %d %d\n ", parameterIndex, x); + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + m_vars[parameterIndex-1] = "'" + OString::number(x) + "'"; +} + +void PreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x ) +{ + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + m_vars[parameterIndex-1] = "'" + OString::number(x) + "'"; +} + +void PreparedStatement::setFloat( sal_Int32 parameterIndex, float x ) +{ + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + m_vars[parameterIndex-1] = "'" + OString::number(x) + "'"; +} + +void PreparedStatement::setDouble( sal_Int32 parameterIndex, double x ) +{ + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + m_vars[parameterIndex-1] = "'" + OString::number(x) + "'"; +} + +void PreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x ) +{ +// printf( "setString %d %s\n ", parameterIndex, +// OUStringToOString( x , RTL_TEXTENCODING_ASCII_US ).getStr()); + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + OStringBuffer buf( 20 ); + buf.append( "'" ); + OString y = OUStringToOString( x, ConnectionSettings::encoding ); + buf.ensureCapacity( y.getLength() * 2 + 2 ); + int len = PQescapeString( const_cast<char*>(buf.getStr())+1, y.getStr() , y.getLength() ); + buf.setLength( 1 + len ); + buf.append( "'" ); + m_vars[parameterIndex-1] = buf.makeStringAndClear(); +} + +void PreparedStatement::setBytes( + sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x ) +{ + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + size_t len; + const std::unique_ptr<unsigned char, deleter_from_fn<PQfreemem>> escapedString( + PQescapeBytea( reinterpret_cast<unsigned char const *>(x.getConstArray()), x.getLength(), &len)); + if( ! escapedString ) + { + throw SQLException( + "pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string", + *this, OUString(), 1, Any() ); + } + m_vars[parameterIndex-1] + = OString::Concat("'") + std::string_view(reinterpret_cast<char *>(escapedString.get()), len -1) + "'"; +} + + +void PreparedStatement::setDate( sal_Int32 parameterIndex, const css::util::Date& x ) +{ + setString( parameterIndex, DBTypeConversion::toDateString( x ) ); +} + +void PreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& x ) +{ + setString( parameterIndex, DBTypeConversion::toTimeString( x ) ); +} + +void PreparedStatement::setTimestamp( + sal_Int32 parameterIndex, const css::util::DateTime& x ) +{ + setString( parameterIndex, DBTypeConversion::toDateTimeString( x ) ); +} + +void PreparedStatement::setBinaryStream( + sal_Int32, + const Reference< css::io::XInputStream >&, + sal_Int32 ) +{ + throw SQLException( + "pq_preparedstatement: setBinaryStream not implemented", + *this, OUString(), 1, Any () ); +} + +void PreparedStatement::setCharacterStream( + sal_Int32, + const Reference< css::io::XInputStream >&, + sal_Int32 ) +{ + throw SQLException( + "pq_preparedstatement: setCharacterStream not implemented", + *this, OUString(), 1, Any () ); +} + +void PreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) +{ + if( ! implSetObject( this, parameterIndex, x )) + { + throw SQLException( + "pq_preparedstatement::setObject: can't convert value of type " + x.getValueTypeName(), + *this, OUString(), 1, Any () ); + } +} + +void PreparedStatement::setObjectWithInfo( + sal_Int32 parameterIndex, + const Any& x, + sal_Int32 targetSqlType, + sal_Int32 ) +{ + if( css::sdbc::DataType::DECIMAL == targetSqlType || + css::sdbc::DataType::NUMERIC == targetSqlType ) + { + double myDouble = 0.0; + OUString myString; + if( x >>= myDouble ) + { + myString = OUString::number( myDouble ); + } + else + { + x >>= myString; + } + if( myString.isEmpty() ) + { + throw SQLException( + "pq_preparedstatement::setObjectWithInfo: can't convert value of type " + + x.getValueTypeName() + " to type DECIMAL or NUMERIC", + *this, OUString(), 1, Any () ); + } + + setString( parameterIndex, myString ); + } + else + { + setObject( parameterIndex, x ); + } + +} + +void PreparedStatement::setRef( + sal_Int32, + const Reference< XRef >& ) +{ + throw SQLException( + "pq_preparedstatement: setRef not implemented", + *this, OUString(), 1, Any () ); +} + +void PreparedStatement::setBlob( + sal_Int32, + const Reference< XBlob >& ) +{ + throw SQLException( + "pq_preparedstatement: setBlob not implemented", + *this, OUString(), 1, Any () ); +} + +void PreparedStatement::setClob( + sal_Int32, + const Reference< XClob >& ) +{ + throw SQLException( + "pq_preparedstatement: setClob not implemented", + *this, OUString(), 1, Any () ); +} + +void PreparedStatement::setArray( + sal_Int32 parameterIndex, + const Reference< XArray >& x ) +{ + setString( parameterIndex, array2String( x->getArray( nullptr ) ) ); +} + +void PreparedStatement::clearParameters( ) +{ + MutexGuard guard(m_xMutex->GetMutex() ); + m_vars = std::vector< OString >( m_vars.size() ); +} + +Any PreparedStatement::getWarnings( ) +{ + return Any(); +} + +void PreparedStatement::clearWarnings( ) +{ +} + +Reference< css::sdbc::XResultSetMetaData > PreparedStatement::getMetaData() +{ + Reference< css::sdbc::XResultSetMetaData > ret; + Reference< css::sdbc::XResultSetMetaDataSupplier > supplier( m_lastResultset, UNO_QUERY ); + if( supplier.is() ) + ret = supplier->getMetaData(); + return ret; +} + +::cppu::IPropertyArrayHelper & PreparedStatement::getInfoHelper() +{ + return getPreparedStatementPropertyArrayHelper(); +} + + +sal_Bool PreparedStatement::convertFastPropertyValue( + Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) +{ + bool bRet; + rOldValue = m_props[nHandle]; + switch( nHandle ) + { + case PREPARED_STATEMENT_CURSOR_NAME: + { + OUString val; + bRet = ( rValue >>= val ); + rConvertedValue <<= val; + break; + } + case PREPARED_STATEMENT_ESCAPE_PROCESSING: + { + bool val(false); + bRet = ( rValue >>= val ); + rConvertedValue <<= val; + break; + } + case PREPARED_STATEMENT_FETCH_DIRECTION: + case PREPARED_STATEMENT_FETCH_SIZE: + case PREPARED_STATEMENT_MAX_FIELD_SIZE: + case PREPARED_STATEMENT_MAX_ROWS: + case PREPARED_STATEMENT_QUERY_TIME_OUT: + case PREPARED_STATEMENT_RESULT_SET_CONCURRENCY: + case PREPARED_STATEMENT_RESULT_SET_TYPE: + { + sal_Int32 val; + bRet = ( rValue >>= val ); + rConvertedValue <<= val; + break; + } + default: + { + throw IllegalArgumentException( + "pq_statement: Invalid property handle (" + + OUString::number( nHandle ) + ")", + *this, 2 ); + } + } + return bRet; +} + + +void PreparedStatement::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle,const Any& rValue ) +{ + m_props[nHandle] = rValue; +} + +void PreparedStatement::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + rValue = m_props[nHandle]; +} + +Reference < XPropertySetInfo > PreparedStatement::getPropertySetInfo() +{ + return OPropertySetHelper::createPropertySetInfo( getPreparedStatementPropertyArrayHelper() ); +} + +void PreparedStatement::disposing() +{ + close(); +} + + +Reference< XResultSet > PreparedStatement::getResultSet( ) +{ + return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY ); +} +sal_Int32 PreparedStatement::getUpdateCount( ) +{ + return m_multipleResultUpdateCount; +} +sal_Bool PreparedStatement::getMoreResults( ) +{ + Reference< XCloseable > lastResultSet = m_lastResultset; + if( lastResultSet.is() ) + lastResultSet->close(); + m_multipleResultUpdateCount = -1; + return false; +} + +Reference< XResultSet > PreparedStatement::getGeneratedValues( ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + return getGeneratedValuesFromLastInsert( + m_pSettings, m_connection, m_lastOidInserted, m_lastTableInserted, m_lastQuery ); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_preparedstatement.hxx b/connectivity/source/drivers/postgresql/pq_preparedstatement.hxx new file mode 100644 index 000000000..4755efbe0 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_preparedstatement.hxx @@ -0,0 +1,221 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once +#include <vector> + +#include <libpq-fe.h> + +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/component.hxx> + +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XMultipleResults.hpp> +#include <com/sun/star/sdbc/XGeneratedResultSet.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> + +#include "pq_connection.hxx" +namespace pq_sdbc_driver +{ + +const sal_Int32 PREPARED_STATEMENT_CURSOR_NAME = 0; +const sal_Int32 PREPARED_STATEMENT_ESCAPE_PROCESSING = 1; +const sal_Int32 PREPARED_STATEMENT_FETCH_DIRECTION = 2; +const sal_Int32 PREPARED_STATEMENT_FETCH_SIZE = 3; +const sal_Int32 PREPARED_STATEMENT_MAX_FIELD_SIZE = 4; +const sal_Int32 PREPARED_STATEMENT_MAX_ROWS = 5; +const sal_Int32 PREPARED_STATEMENT_QUERY_TIME_OUT = 6; +const sal_Int32 PREPARED_STATEMENT_RESULT_SET_CONCURRENCY = 7; +const sal_Int32 PREPARED_STATEMENT_RESULT_SET_TYPE = 8; + +#define PREPARED_STATEMENT_SIZE 9 + +typedef ::cppu::WeakComponentImplHelper< css::sdbc::XPreparedStatement, + css::sdbc::XParameters, + css::sdbc::XCloseable, + css::sdbc::XWarningsSupplier, + css::sdbc::XMultipleResults, + css::sdbc::XGeneratedResultSet, + css::sdbc::XResultSetMetaDataSupplier + > PreparedStatement_BASE; +class PreparedStatement : public PreparedStatement_BASE, + public cppu::OPropertySetHelper +{ +private: + css::uno::Any m_props[PREPARED_STATEMENT_SIZE]; + css::uno::Reference< css::sdbc::XConnection > m_connection; + ConnectionSettings *m_pSettings; + css::uno::Reference< css::sdbc::XCloseable > m_lastResultset; + OString m_stmt; + OString m_executedStatement; + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + std::vector< OString > m_vars; + std::vector< OString > m_splittedStatement; + bool m_multipleResultAvailable; + sal_Int32 m_multipleResultUpdateCount; + sal_Int32 m_lastOidInserted; + OUString m_lastTableInserted; + OString m_lastQuery; + +public: + /** + * @param ppConnection The piece of memory, pConnection points to, is accessible + * as long as a reference to parameter con is held. + */ + PreparedStatement( const rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection> & con, + struct ConnectionSettings *pSettings, + const OString &stmt ); + + virtual ~PreparedStatement() override; +public: // XInterface + virtual void SAL_CALL acquire() noexcept override { PreparedStatement_BASE::acquire(); } + virtual void SAL_CALL release() noexcept override { PreparedStatement_BASE::release(); } + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & reqType ) override; + +public: // XCloseable + virtual void SAL_CALL close( ) override; + +public: // XPreparedStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery() override; + virtual sal_Int32 SAL_CALL executeUpdate( ) override; + virtual sal_Bool SAL_CALL execute( ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; +public: // XParameters + virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override; + virtual void SAL_CALL setObjectNull( + sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override; + virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override; + virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override; + virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override; + virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override; + virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override; + virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override; + virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override; + virtual void SAL_CALL setBytes( + sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override; + virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override; + virtual void SAL_CALL setTimestamp( + sal_Int32 parameterIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL setBinaryStream( + sal_Int32 parameterIndex, + const css::uno::Reference< css::io::XInputStream >& x, + sal_Int32 length ) override; + virtual void SAL_CALL setCharacterStream( + sal_Int32 parameterIndex, + const css::uno::Reference< css::io::XInputStream >& x, + sal_Int32 length ) override; + virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL setObjectWithInfo( + sal_Int32 parameterIndex, + const css::uno::Any& x, + sal_Int32 targetSqlType, + sal_Int32 scale ) override; + virtual void SAL_CALL setRef( + sal_Int32 parameterIndex, + const css::uno::Reference< css::sdbc::XRef >& x ) override; + virtual void SAL_CALL setBlob( + sal_Int32 parameterIndex, + const css::uno::Reference< css::sdbc::XBlob >& x ) override; + virtual void SAL_CALL setClob( + sal_Int32 parameterIndex, + const css::uno::Reference< css::sdbc::XClob >& x ) override; + virtual void SAL_CALL setArray( + sal_Int32 parameterIndex, + const css::uno::Reference< css::sdbc::XArray >& x ) override; + virtual void SAL_CALL clearParameters( ) override; + +public: // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // OPropertySetHelper + virtual cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + using ::cppu::OPropertySetHelper::getFastPropertyValue; + + void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle ) const override; + + // XPropertySet + css::uno::Reference < css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + +public: // XGeneratedResultSet + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL + getGeneratedValues( ) override; + +public: // XMultipleResults + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override; + virtual sal_Int32 SAL_CALL getUpdateCount( ) override; + virtual sal_Bool SAL_CALL getMoreResults( ) override; + +public: // XResultSetMetaDataSupplier (is required by framework (see + // dbaccess/source/core/api/preparedstatement.cxx::getMetaData() ) + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + +public: // OComponentHelper + virtual void SAL_CALL disposing() override; + +private: + void checkColumnIndex( sal_Int32 parameterIndex ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkClosed(); + /// @throws css::sdbc::SQLException + void raiseSQLException( const char * errorMsg ); +// PGresult *pgExecute( OString *pQuery ); +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_resultset.cxx b/connectivity/source/drivers/postgresql/pq_resultset.cxx new file mode 100644 index 000000000..556bae92d --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_resultset.cxx @@ -0,0 +1,308 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include "pq_resultset.hxx" +#include "pq_resultsetmetadata.hxx" + +#include <connectivity/dbexception.hxx> + +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + + +using osl::MutexGuard; + +using com::sun::star::uno::Any; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; + +using com::sun::star::sdbc::SQLException; +using com::sun::star::sdbc::XResultSetMetaData; + + +namespace pq_sdbc_driver +{ + +void ResultSet::checkClosed() +{ + if( ! m_result ) + { + throw SQLException( "pq_resultset: already closed", + *this, OUString(), 1, Any() ); + } + + if( ! m_ppSettings || ! *m_ppSettings || ! (*m_ppSettings)->pConnection ) + { + throw SQLException( "pq_resultset: statement has been closed already", + *this, OUString(), 1, Any() ); + } + +} + +ResultSet::ResultSet( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< XInterface > & owner, + ConnectionSettings **ppSettings, + PGresult * result, + const OUString &schema, + const OUString &table) + : BaseResultSet( + refMutex, owner, PQntuples( result ), + PQnfields( result ),(*ppSettings)->tc ), + m_result( result ), + m_schema( schema ), + m_table( table ), + m_ppSettings( ppSettings ) +{ + // LEM TODO: shouldn't these things be inherited from the statement or something like that? + // Positioned update/delete not supported, so no cursor name + // Fetch direction and size are cursor-specific things, so not used now. + // Fetch size not set + m_props[ BASERESULTSET_FETCH_DIRECTION ] <<= css::sdbc::FetchDirection::UNKNOWN; + // No escape processing for now + m_props[ BASERESULTSET_ESCAPE_PROCESSING ] <<= false; + // Bookmarks not implemented for now + m_props[ BASERESULTSET_IS_BOOKMARKABLE ] <<= false; + m_props[ BASERESULTSET_RESULT_SET_CONCURRENCY ] <<= css::sdbc::ResultSetConcurrency::READ_ONLY; + m_props[ BASERESULTSET_RESULT_SET_TYPE ] <<= css::sdbc::ResultSetType::SCROLL_INSENSITIVE; +} + + +Any ResultSet::getValue( sal_Int32 columnIndex ) +{ + Any ret; + if( PQgetisnull( m_result, m_row, columnIndex -1 ) ) + { + m_wasNull = true; + } + else + { + m_wasNull = false; + ret <<= OUString( + PQgetvalue( m_result, m_row , columnIndex -1 ) , + PQgetlength( m_result, m_row , columnIndex -1 ) , + ConnectionSettings::encoding ); + + } + return ret; +} + +ResultSet::~ResultSet() +{} + +void ResultSet::close( ) +{ + Reference< XInterface > owner; + { + MutexGuard guard( m_xMutex->GetMutex() ); + if( m_result ) + { + PQclear(m_result ); + m_result = nullptr; + m_row = -1; + } + owner = m_owner; + m_owner.clear(); + } +} + +Reference< XResultSetMetaData > ResultSet::getMetaData( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return new ResultSetMetaData( + m_xMutex, this, this, m_ppSettings, m_result, m_schema, m_table ); +} + +sal_Int32 ResultSet::findColumn( const OUString& columnName ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + sal_Int32 res = PQfnumber( m_result, + OUStringToOString( columnName, ConnectionSettings::encoding ).getStr()); + /* PQfnumber return -1 for not found, which is what we want + * other than that we use col number as 1-based not 0-based */ + if(res >= 0) + { + res += 1; + } + else + { + ::dbtools::throwInvalidColumnException( columnName, *this ); + assert(false); + } + return res; +} + +static bool isNumber( const char * data, sal_Int32 len ) +{ + bool ret = false; + if( len ) + { + ret = true; + for( int i = 0 ; i < len ; i ++ ) + { + if( ( data[i] >= '0' && data[i] <= '9' ) || + data[i] == '-' || data[i] == '+' || data[i] == '.' || data[i] == ',' ) + { + if( data[i] == '-' && i != 0 && i != len-1 ) + { + // no number, maybe a date + ret = false; + break; + } + } + else + { + ret = false; + break; + } + } + } + return ret; +} + +static bool isInteger( const char * data, sal_Int32 len ) +{ + bool ret = false; + if( len ) + { + ret = true; + for( int i = 0 ; i < len ; i ++ ) + { + if( ( data[i] >= '0' && data[i] <= '9' ) || + data[i] == '-' || data[i] == '+' ) + { + if( data[i] == '-' && i != 0 && i != len-1 ) + { + // no number, maybe a date + ret = false; + break; + } + } + else + { + ret = false; + break; + } + } + } + return ret; +} + +static bool isDate( const char * data, sal_Int32 len ) +{ + return 10 == len && + '-' == data[4] && + '-' == data[7] && + isInteger( &(data[0]),4 ) && + isInteger( &(data[5]),2) && + isInteger( &(data[8]),2 ); +} + +static bool isTime( const char * data, sal_Int32 len ) +{ + return 8 == len && + ':' == data[2] && + ':' == data[5] && + isInteger( &(data[0]),2 ) && + isInteger( &(data[3]),2) && + isInteger( &(data[6]),2 ); + +} + +static bool isTimestamp( const char * data, sal_Int32 len ) +{ + return len == 19 && isDate( data, 10) && isTime( &(data[11]),8 ); +} + +sal_Int32 ResultSet::guessDataType( sal_Int32 column ) +{ + // we don't look into more than 100 rows ... + sal_Int32 ret = css::sdbc::DataType::INTEGER; + + int maxRows = std::min<sal_Int32>( m_rowCount, 100 ); + for( int i = 0 ; i < maxRows ; i ++ ) + { + if( ! PQgetisnull( m_result, i , column-1 ) ) + { + const char * p = PQgetvalue( m_result, i , column -1 ); + int len = PQgetlength( m_result, i , column -1 ); + + if( css::sdbc::DataType::INTEGER == ret ) + { + if( ! isInteger( p,len ) ) + ret = css::sdbc::DataType::NUMERIC; + } + if( css::sdbc::DataType::NUMERIC == ret ) + { + if( ! isNumber( p,len ) ) + { + ret = css::sdbc::DataType::DATE; + } + } + if( css::sdbc::DataType::DATE == ret ) + { + if( ! isDate( p,len ) ) + { + ret = css::sdbc::DataType::TIME; + } + } + if( css::sdbc::DataType::TIME == ret ) + { + if( ! isTime( p,len ) ) + { + ret = css::sdbc::DataType::TIMESTAMP; + } + } + if( css::sdbc::DataType::TIMESTAMP == ret ) + { + if( ! isTimestamp( p,len ) ) + { + ret = css::sdbc::DataType::LONGVARCHAR; + break; + } + } + } + } + return ret; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_resultset.hxx b/connectivity/source/drivers/postgresql/pq_resultset.hxx new file mode 100644 index 000000000..340e34b70 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_resultset.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/component.hxx> + +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include "pq_connection.hxx" +#include "pq_baseresultset.hxx" + +namespace pq_sdbc_driver +{ + +class ResultSet : public BaseResultSet +{ +protected: + PGresult *m_result; + OUString m_schema; + OUString m_table; + ConnectionSettings **m_ppSettings; + +protected: + /** mutex should be locked before called + */ + virtual void checkClosed() override; + + /** unchecked, acquire mutex before calling + */ + virtual css::uno::Any getValue( sal_Int32 columnIndex ) override; + +public: + ResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + ConnectionSettings **pSettings, + PGresult *result, + const OUString &schema, + const OUString &table ); + virtual ~ResultSet() override; + +public: // XCloseable + virtual void SAL_CALL close( ) override; + +public: // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + +public: // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; + +public: + sal_Int32 guessDataType( sal_Int32 column ); +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_resultsetmetadata.cxx b/connectivity/source/drivers/postgresql/pq_resultsetmetadata.cxx new file mode 100644 index 000000000..fbe10f82d --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_resultsetmetadata.cxx @@ -0,0 +1,441 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <rtl/ustrbuf.hxx> + +#include "pq_resultsetmetadata.hxx" +#include "pq_resultset.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> + +#include <string.h> + +using osl::MutexGuard; + + +using com::sun::star::uno::Any; +using com::sun::star::uno::Exception; +using com::sun::star::uno::Reference; +using com::sun::star::uno::UNO_QUERY; + + +using com::sun::star::sdbc::SQLException; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbcx::XColumnsSupplier; +using com::sun::star::sdbcx::XTablesSupplier; + +using com::sun::star::beans::XPropertySet; +using com::sun::star::container::XNameAccess; + + +namespace pq_sdbc_driver +{ + +// struct ColumnMetaData +// { +// OUString tableName; +// OUString schemaTableName; +// OUString typeName; +// css::sdbc::DataType type; +// sal_Int32 precision; +// sal_Int32 scale; +// sal_Bool isCurrency; +// sal_Bool isNullable; +// sal_Bool isAutoIncrement; +// sal_Bool isReadOnly; +// sal_Bool isSigned; +// }; + +// is not exported by the postgres header +const int PQ_VARHDRSZ = sizeof( sal_Int32 ); + +static void extractPrecisionAndScale( sal_Int32 atttypmod, sal_Int32 *precision, sal_Int32 *scale ) +{ + if( atttypmod < PQ_VARHDRSZ ) + { + *precision = 0; + *scale = 0; + } + else + { + if( atttypmod & 0xffff0000 ) + { + *precision = ( ( atttypmod - PQ_VARHDRSZ ) >> 16 ) & 0xffff; + *scale = (atttypmod - PQ_VARHDRSZ ) & 0xffff; + } + else + { + *precision = atttypmod - PQ_VARHDRSZ; + *scale = 0; + } + } +} + +ResultSetMetaData::ResultSetMetaData( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XResultSet > & origin, + ResultSet * pResultSet, + ConnectionSettings **ppSettings, + PGresult const *pResult, + const OUString &schemaName, + const OUString &tableName ) : + m_xMutex( refMutex ), + m_ppSettings( ppSettings ), + m_origin( origin ), + m_tableName( tableName ), + m_schemaName( schemaName ), + m_colDesc( PQnfields( pResult ) ), + m_pResultSet( pResultSet ), + m_checkedForTable( false ), + m_checkedForTypes( false ), + m_colCount( PQnfields( pResult ) ) +{ + + // extract all needed information from the result object, so that we don't + // need it anymore after this call ! + for( int col = 0; col < m_colCount ; col ++ ) + { + sal_Int32 size = PQfsize( pResult, col ); + size = -1 == size ? 25 : size; + m_colDesc[col].displaySize = size; + + extractPrecisionAndScale( + PQfmod( pResult, col ), + & ( m_colDesc[col].precision ), + & ( m_colDesc[col].scale ) ); + char *name = PQfname( pResult, col ); + m_colDesc[col].name = OUString( name, strlen(name) , ConnectionSettings::encoding ); + m_colDesc[col].typeOid = PQftype( pResult, col ); + m_colDesc[col].type = css::sdbc::DataType::LONGVARCHAR; + } +} + +void ResultSetMetaData::checkForTypes() +{ + if( m_checkedForTypes ) + return; + + Reference< XStatement > stmt = + extractConnectionFromStatement( m_origin->getStatement() )->createStatement(); + DisposeGuard guard( stmt ); + OUStringBuffer buf(128); + buf.append( "SELECT oid, typname, typtype FROM pg_type WHERE "); + for( int i = 0 ; i < m_colCount ; i ++ ) + { + if( i > 0 ) + buf.append( " OR " ); + int oid = m_colDesc[i].typeOid; + buf.append( "oid=" ); + buf.append( static_cast<sal_Int32>(oid) ); + } + Reference< XResultSet > rs = stmt->executeQuery( buf.makeStringAndClear() ); + Reference< XRow > xRow( rs, UNO_QUERY ); + while( rs->next() ) + { + Oid oid = xRow->getInt( 1 ); + OUString typeName = xRow->getString( 2 ); + OUString typType = xRow->getString( 3 ); + + sal_Int32 type = typeNameToDataType( typeName, typType ); + + for( sal_Int32 j = 0; j < m_colCount ; j ++ ) + { + if( m_colDesc[j].typeOid == oid ) + { + m_colDesc[j].typeName = typeName; + m_colDesc[j].type = type; + } + } + } + m_checkedForTypes = true; +} + +void ResultSetMetaData::checkTable() +{ + if( m_checkedForTable ) + return; + + m_checkedForTable = true; + if( !m_tableName.getLength() ) + return; + + Reference< css::container::XNameAccess > tables = (*m_ppSettings)->tables; + if( ! tables.is() ) + { + + Reference< XTablesSupplier > supplier( + extractConnectionFromStatement( m_origin->getStatement() ), UNO_QUERY); + if( supplier.is() ) + tables = supplier->getTables(); + } + if( tables.is() ) + { + const OUString name (getTableName ( 1 )); + const OUString schema (getSchemaName( 1 )); + const OUString composedName( schema.isEmpty() ? name : (schema + "." + name) ); + tables->getByName( composedName ) >>= m_table; + } +} + +sal_Int32 ResultSetMetaData::getIntColumnProperty( const OUString & name, int index, int def ) +{ + sal_Int32 ret = def; // give defensive answers, when data is not available + try + { + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( index ); + Reference< XPropertySet > set = getColumnByIndex( index ); + + if( set.is() ) + { + set->getPropertyValue( name ) >>= ret; + } + } + catch( css::uno::Exception & ) + { + } + return ret; +} + +bool ResultSetMetaData::getBoolColumnProperty( const OUString & name, int index, bool def ) +{ + bool ret = def; + try + { + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( index ); + Reference< XPropertySet > set = getColumnByIndex( index ); + if( set.is() ) + { + set->getPropertyValue( name ) >>= ret; + } + } + catch( css::uno::Exception & ) + { + } + + return ret; +} + +Reference< css::beans::XPropertySet > ResultSetMetaData::getColumnByIndex( int index ) +{ + Reference< XPropertySet > ret; + checkTable(); + if( m_table.is() ) + { + OUString columnName = getColumnName( index ); + Reference< XColumnsSupplier > supplier( m_table, UNO_QUERY ); + if( supplier.is() ) + { + Reference< XNameAccess > columns = supplier->getColumns(); + if( columns.is() && columns->hasByName( columnName ) ) + { + columns->getByName( columnName ) >>= ret; + } + } + } + return ret; +} + +// Methods +sal_Int32 ResultSetMetaData::getColumnCount( ) +{ + return m_colCount; +} + +sal_Bool ResultSetMetaData::isAutoIncrement( sal_Int32 column ) +{ + + bool ret = getBoolColumnProperty( getStatics().IS_AUTO_INCREMENT, column, false ); + return ret; +} + +sal_Bool ResultSetMetaData::isCaseSensitive( sal_Int32 ) +{ + return true; // ??? hmm, numeric types or +} + +sal_Bool ResultSetMetaData::isSearchable( sal_Int32 ) +{ + return true; // mmm, what types are not searchable ? +} + +sal_Bool ResultSetMetaData::isCurrency( sal_Int32 column ) +{ + return getBoolColumnProperty( getStatics().IS_CURRENCY, column, false ); +} + +sal_Int32 ResultSetMetaData::isNullable( sal_Int32 column ) +{ + return getIntColumnProperty( + getStatics().IS_NULLABLE, column, css::sdbc::ColumnValue::NULLABLE_UNKNOWN ); +} + +sal_Bool ResultSetMetaData::isSigned( sal_Int32 ) +{ + return true; +} + +sal_Int32 ResultSetMetaData::getColumnDisplaySize( sal_Int32 column ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( column ); + return m_colDesc[column-1].displaySize; +} + +OUString ResultSetMetaData::getColumnLabel( sal_Int32 column ) +{ + return getColumnName( column); +} + +OUString ResultSetMetaData::getColumnName( sal_Int32 column ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( column ); + + return m_colDesc[column-1].name; +} + +OUString ResultSetMetaData::getSchemaName( sal_Int32 ) +{ + return m_schemaName; +} + +sal_Int32 ResultSetMetaData::getPrecision( sal_Int32 column ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( column ); + return m_colDesc[column-1].precision; +} + +sal_Int32 ResultSetMetaData::getScale( sal_Int32 column ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( column ); + return m_colDesc[column-1].scale; +} + +OUString ResultSetMetaData::getTableName( sal_Int32 ) +{ +// LEM TODO This is very fishy... Should probably return the table to which that column belongs! + return m_tableName; +} + +OUString ResultSetMetaData::getCatalogName( sal_Int32 ) +{ + // can do this through XConnection.getCatalog() ! + return OUString(); +} +sal_Int32 ResultSetMetaData::getColumnType( sal_Int32 column ) +{ + int ret = getIntColumnProperty( getStatics().TYPE, column, -100 ); + if( -100 == ret ) + { + checkForTypes(); + if( css::sdbc::DataType::LONGVARCHAR == m_colDesc[column-1].type && m_pResultSet ) + m_colDesc[column-1].type = m_pResultSet->guessDataType( column ); + ret = m_colDesc[column-1].type; + } + return ret; +} + +OUString ResultSetMetaData::getColumnTypeName( sal_Int32 column ) +{ + OUString ret; // give defensive answers, when data is not available + try + { + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( column ); + Reference< XPropertySet > set = getColumnByIndex( column ); + + if( set.is() ) + { + set->getPropertyValue( getStatics().TYPE_NAME ) >>= ret; + } + else + { + checkForTypes(); + ret = m_colDesc[column-1].typeName; + } + } + catch( css::uno::Exception & ) + { + } + return ret; +} + + +sal_Bool ResultSetMetaData::isReadOnly( sal_Int32 ) +{ + return false; +} + +sal_Bool ResultSetMetaData::isWritable( sal_Int32 column ) +{ + return ! isReadOnly( column ); // what's the sense if this method ? +} + +sal_Bool ResultSetMetaData::isDefinitelyWritable( sal_Int32 column ) +{ + return isWritable(column); // uhh, now it becomes really esoteric... +} +OUString ResultSetMetaData::getColumnServiceName( sal_Int32 ) +{ + return OUString(); +} + +void ResultSetMetaData::checkColumnIndex(sal_Int32 columnIndex) +{ + if( columnIndex < 1 || columnIndex > m_colCount ) + { + throw SQLException( + "pq_resultsetmetadata: index out of range (expected 1 to " + + OUString::number( m_colCount ) + ", got " + OUString::number( columnIndex ), + *this, OUString(), 1, Any() ); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_resultsetmetadata.hxx b/connectivity/source/drivers/postgresql/pq_resultsetmetadata.hxx new file mode 100644 index 000000000..67e34d44d --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_resultsetmetadata.hxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once +#include <vector> + +#include "pq_connection.hxx" + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <cppuhelper/implbase.hxx> + +namespace pq_sdbc_driver +{ + +struct ColDesc +{ + OUString name; + sal_Int32 precision; + sal_Int32 scale; + sal_Int32 displaySize; + Oid typeOid; + OUString typeName; + sal_Int32 type; +}; + +class ResultSet; + +class ResultSetMetaData : + public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData > +{ + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + ConnectionSettings **m_ppSettings; + css::uno::Reference< css::sdbc::XResultSet > m_origin; + css::uno::Reference< css::beans::XPropertySet > m_table; + OUString m_tableName; + OUString m_schemaName; + std::vector< ColDesc > m_colDesc; + ResultSet *m_pResultSet; + + bool m_checkedForTable; + bool m_checkedForTypes; + + sal_Int32 m_colCount; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkColumnIndex( sal_Int32 columnIndex ); + void checkTable(); + void checkForTypes(); + css::uno::Reference< css::beans::XPropertySet > getColumnByIndex( int index ); + + sal_Int32 getIntColumnProperty( const OUString & name, int index, int def ); + bool getBoolColumnProperty( const OUString & name, int index, bool def ); + +public: + ResultSetMetaData( + const ::rtl::Reference< comphelper::RefCountedMutex > & reMutex, + const css::uno::Reference< css::sdbc::XResultSet > & origin, + ResultSet *pResultSet, + ConnectionSettings **pSettings, + PGresult const *pResult, + const OUString &schemaName, + const OUString &tableName ); + +public: + // Methods + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_sequenceresultset.cxx b/connectivity/source/drivers/postgresql/pq_sequenceresultset.cxx new file mode 100644 index 000000000..defb99906 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_sequenceresultset.cxx @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + + +#include "pq_sequenceresultset.hxx" +#include "pq_sequenceresultsetmetadata.hxx" + +#include <connectivity/dbexception.hxx> + +#include <com/sun/star/sdbc/SQLException.hpp> + +using com::sun::star::sdbc::XResultSetMetaData; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Any; + +namespace pq_sdbc_driver +{ + +void SequenceResultSet::checkClosed() +{ + // we never close :o) +} + + +Any SequenceResultSet::getValue( sal_Int32 columnIndex ) +{ + m_wasNull = ! m_data[m_row][columnIndex -1 ].hasValue(); + return m_data[m_row][columnIndex -1 ]; +} + +SequenceResultSet::SequenceResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + std::vector< OUString >&& colNames, + std::vector< std::vector< Any > >&& data, + const Reference< css::script::XTypeConverter > & tc, + const ColumnMetaDataVector *pVec) : + BaseResultSet( mutex, owner, data.size(), colNames.size(), tc ), + m_data(std::move(data) ), + m_columnNames( std::move(colNames) ) +{ + if( pVec ) + { + m_meta = new SequenceResultSetMetaData( std::vector(*pVec), m_columnNames.size() ); + } +} + +SequenceResultSet::~SequenceResultSet() +{ + +} + +void SequenceResultSet::close( ) +{ + // a noop +} + +Reference< XResultSetMetaData > SAL_CALL SequenceResultSet::getMetaData( ) +{ + if( ! m_meta.is() ) + { + // Oh no, not again + throw css::sdbc::SQLException( + "pq_sequenceresultset: no meta supported ", *this, + // I did not find "IM001" in a specific standard, + // but it seems to be used by other systems (such as ODBC) + // and some parts of LibreOffice special-case it. + "IM001", 1, Any() ); + } + return m_meta; +} + + +sal_Int32 SAL_CALL SequenceResultSet::findColumn( + const OUString& columnName ) +{ + // no need to guard, as all members are readonly ! + for( int i = 0 ;i < m_fieldCount ; i ++ ) + { + if( columnName == m_columnNames[i] ) + { + return i+1; + } + } + ::dbtools::throwInvalidColumnException( columnName, *this ); + assert(false); + return 0; // Never reached +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_sequenceresultset.hxx b/connectivity/source/drivers/postgresql/pq_sequenceresultset.hxx new file mode 100644 index 000000000..64ac212b6 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_sequenceresultset.hxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/component.hxx> + +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include "pq_connection.hxx" +#include "pq_baseresultset.hxx" +#include "pq_statics.hxx" + +namespace pq_sdbc_driver +{ + +class SequenceResultSet : public BaseResultSet +{ +protected: + std::vector< std::vector< css::uno::Any > > m_data; + + std::vector< OUString > m_columnNames; + css::uno::Reference< css::sdbc::XResultSetMetaData > m_meta; + +protected: + /** mutex should be locked before called + */ + virtual void checkClosed() override; + + /** unchecked, acquire mutex before calling + */ + virtual css::uno::Any getValue( sal_Int32 columnIndex ) override; + +public: + SequenceResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + std::vector< OUString >&& colNames, + std::vector< std::vector< css::uno::Any > >&& data, + const css::uno::Reference< css::script::XTypeConverter > &tc, + const ColumnMetaDataVector *pVec = nullptr); + virtual ~SequenceResultSet() override; + +public: // XCloseable + virtual void SAL_CALL close( ) override; + +public: // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + +public: // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.cxx b/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.cxx new file mode 100644 index 000000000..568e6bb9f --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.cxx @@ -0,0 +1,191 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 200? by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include "pq_sequenceresultsetmetadata.hxx" + +#include <com/sun/star/sdbc/SQLException.hpp> + +using com::sun::star::uno::Any; + +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ + +SequenceResultSetMetaData::SequenceResultSetMetaData( + ColumnMetaDataVector&& metaDataVector, + int colCount ) : + m_columnData( std::move(metaDataVector) ), + m_colCount( colCount ) +{ +} + + +// Methods +sal_Int32 SequenceResultSetMetaData::getColumnCount( ) +{ + return m_colCount; +} + +sal_Bool SequenceResultSetMetaData::isAutoIncrement( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].isAutoIncrement; +} + +sal_Bool SequenceResultSetMetaData::isCaseSensitive( sal_Int32 /* column */ ) +{ + + return true; // ??? hmm, numeric types or +} + +sal_Bool SequenceResultSetMetaData::isSearchable( sal_Int32 /* column */ ) +{ + return true; // mmm, what types are not searchable ? +} + +sal_Bool SequenceResultSetMetaData::isCurrency( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].isCurrency; +} + +sal_Int32 SequenceResultSetMetaData::isNullable( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].isNullable ? 1 : 0; +} + +sal_Bool SequenceResultSetMetaData::isSigned( sal_Int32 /* column */ ) +{ + return true; +} + +sal_Int32 SequenceResultSetMetaData::getColumnDisplaySize( sal_Int32 /* column */ ) +{ + return 50; +} + +OUString SequenceResultSetMetaData::getColumnLabel( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].columnName; +} + +OUString SequenceResultSetMetaData::getColumnName( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].columnName; +} + +OUString SequenceResultSetMetaData::getSchemaName( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].schemaTableName; +} + + +sal_Int32 SequenceResultSetMetaData::getPrecision( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].precision; +} + +sal_Int32 SequenceResultSetMetaData::getScale( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].scale; +} + +OUString SequenceResultSetMetaData::getTableName( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].tableName; +} + +OUString SequenceResultSetMetaData::getCatalogName( sal_Int32 /* column */ ) +{ + // can do this through XConnection.getCatalog() ! + return OUString(); +} +sal_Int32 SequenceResultSetMetaData::getColumnType( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].type; +} + +OUString SequenceResultSetMetaData::getColumnTypeName( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].typeName; +} + + +sal_Bool SequenceResultSetMetaData::isReadOnly( sal_Int32 /* column */ ) +{ + return false; +} + +sal_Bool SequenceResultSetMetaData::isWritable( sal_Int32 column ) +{ + return ! isReadOnly( column ); // what's the sense if this method ? +} + +sal_Bool SequenceResultSetMetaData::isDefinitelyWritable( sal_Int32 column ) +{ + return isWritable(column); // uhh, now it becomes really esoteric... +} +OUString SequenceResultSetMetaData::getColumnServiceName( sal_Int32 /* column */ ) +{ + return OUString(); +} + +void SequenceResultSetMetaData::checkColumnIndex(sal_Int32 columnIndex) +{ + if( columnIndex < 1 || columnIndex > m_colCount ) + { + throw SQLException( + "pq_sequenceresultsetmetadata: index out of range (expected 1 to " + + OUString::number( m_colCount ) + + ", got " + OUString::number( columnIndex ), + *this, OUString(), 1, Any() ); + } +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.hxx b/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.hxx new file mode 100644 index 000000000..3cd32ff66 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.hxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 200? by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> + +#include "pq_connection.hxx" +#include "pq_statics.hxx" + +namespace pq_sdbc_driver +{ + class SequenceResultSetMetaData : + public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData > + { + ColumnMetaDataVector m_columnData; + sal_Int32 m_colCount; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkColumnIndex( sal_Int32 columnIndex ); + + public: + SequenceResultSetMetaData( + ColumnMetaDataVector&& vec, + int colCount ); + + public: + // Methods + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_statement.cxx b/connectivity/source/drivers/postgresql/pq_statement.cxx new file mode 100644 index 000000000..7db4b2053 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_statement.cxx @@ -0,0 +1,888 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include "pq_statement.hxx" +#include "pq_fakedupdateableresultset.hxx" +#include "pq_updateableresultset.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +#include <osl/time.h> + +#include <rtl/ustrbuf.hxx> + +#include <comphelper/sequence.hxx> + +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> + +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <com/sun/star/sdbcx/XKeysSupplier.hpp> + +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> + +#include <string.h> +#include <string_view> + +using osl::MutexGuard; + + +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::UNO_QUERY; + +using com::sun::star::lang::IllegalArgumentException; + +using com::sun::star::sdbc::XCloseable; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XPreparedStatement; +using com::sun::star::sdbc::XParameters; +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XConnection; +using com::sun::star::sdbc::SQLException; + +using com::sun::star::sdbcx::XColumnsSupplier; +using com::sun::star::sdbcx::XKeysSupplier; + +using com::sun::star::beans::Property; +using com::sun::star::beans::XPropertySetInfo; +using com::sun::star::beans::XPropertySet; + +using com::sun::star::container::XNameAccess; +using com::sun::star::container::XEnumerationAccess; +using com::sun::star::container::XEnumeration; +using com::sun::star::container::XIndexAccess; + +namespace pq_sdbc_driver +{ +static ::cppu::IPropertyArrayHelper & getStatementPropertyArrayHelper() +{ + static ::cppu::OPropertyArrayHelper arrayHelper( + Sequence<Property>{ + Property( + "CursorName", 0, + ::cppu::UnoType<OUString>::get() , 0 ), + Property( + "EscapeProcessing", 1, + cppu::UnoType<bool>::get() , 0 ), + Property( + "FetchDirection", 2, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "FetchSize", 3, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "MaxFieldSize", 4, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "MaxRows", 5, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "QueryTimeOut", 6, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "ResultSetConcurrency", 7, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "ResultSetType", 8, + ::cppu::UnoType<sal_Int32>::get() , 0 )}, + true ); + + return arrayHelper; +} + +Statement::Statement( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< XConnection > & conn, + struct ConnectionSettings *pSettings ) + : Statement_BASE( refMutex->GetMutex() ) + , OPropertySetHelper( Statement_BASE::rBHelper ) + , m_connection( conn ) + , m_pSettings( pSettings ) + , m_xMutex( refMutex ) + , m_multipleResultAvailable(false) + , m_multipleResultUpdateCount(0) + , m_lastOidInserted(InvalidOid) +{ + m_props[STATEMENT_QUERY_TIME_OUT] <<= sal_Int32(0); + m_props[STATEMENT_MAX_ROWS] <<= sal_Int32(0); + m_props[STATEMENT_RESULT_SET_CONCURRENCY] <<= + css::sdbc::ResultSetConcurrency::READ_ONLY; + m_props[STATEMENT_RESULT_SET_TYPE] <<= + css::sdbc::ResultSetType::SCROLL_INSENSITIVE; +} + +Statement::~Statement() +{ +} + +void Statement::checkClosed() +{ + if( ! m_pSettings || ! m_pSettings->pConnection ) + throw SQLException( + "pq_driver: Statement or connection has already been closed !", + *this, OUString(),1,Any()); +} + +Any Statement::queryInterface( const Type & rType ) +{ + Any aRet = Statement_BASE::queryInterface(rType); + return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType); +} + + +Sequence< Type > Statement::getTypes() +{ + static Sequence< Type > collection( + ::comphelper::concatSequences( + OPropertySetHelper::getTypes(), + Statement_BASE::getTypes())); + + return collection; +} + +Sequence< sal_Int8> Statement::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +void Statement::close( ) +{ + // let the connection die without acquired mutex ! + Reference< XConnection > r; + Reference< XCloseable > resultSet; + { + MutexGuard guard( m_xMutex->GetMutex() ); + m_pSettings = nullptr; + r = m_connection; + m_connection.clear(); + + resultSet = m_lastResultset; + m_lastResultset.clear(); + } + if( resultSet.is() ) + { + resultSet->close(); + } + +} + +void Statement::raiseSQLException( + std::u16string_view sql, const char * errorMsg ) +{ + OUString error = "pq_driver: " + + OUString( errorMsg, strlen(errorMsg), ConnectionSettings::encoding ) + + " (caused by statement '" + sql + "')"; + SAL_WARN("connectivity.postgresql", error); + throw SQLException( error, *this, OUString(), 1, Any() ); +} + +Reference< XResultSet > Statement::executeQuery(const OUString& sql ) +{ + if( ! execute( sql ) ) + { + raiseSQLException( sql, "not a query" ); + } + return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY ); +} + +sal_Int32 Statement::executeUpdate( const OUString& sql ) +{ + if( execute( sql ) ) + { + raiseSQLException( sql, "not a command" ); + } + return m_multipleResultUpdateCount; +} + +/// @throws SQLException +static void raiseSQLException( + const Reference< XInterface> & owner, + std::string_view sql, + const char * errorMsg, + const char *errorType = nullptr ) +{ + OUStringBuffer buf(128); + buf.append( "pq_driver: "); + if( errorType ) + { + buf.append( "[" ); + buf.appendAscii( errorType ); + buf.append( "]" ); + } + buf.append( + OUString( errorMsg, strlen(errorMsg) , ConnectionSettings::encoding ) ); + buf.append( " (caused by statement '" ); + buf.append( OStringToOUString( sql, ConnectionSettings::encoding ) ); + buf.append( "')" ); + OUString error = buf.makeStringAndClear(); + SAL_WARN("connectivity.postgresql", error); + throw SQLException( error, owner, OUString(), 1, Any() ); +} + + +// returns the elements of the primary key of the given table +// static Sequence< Reference< css::beans::XPropertySet > > lookupKeys( +static std::vector< OUString > lookupKeys( + const Reference< css::container::XNameAccess > &tables, + const OUString & table, + OUString *pSchema, + OUString *pTable) +{ + std::vector< OUString > ret; + Reference< XKeysSupplier > keySupplier; + Statics & st = getStatics(); + + if( tables->hasByName( table ) ) + tables->getByName( table ) >>= keySupplier; + else if( -1 == table.indexOf( '.' ) ) + { + // it wasn't a fully qualified name. Now need to skip through all tables. + Reference< XEnumerationAccess > enumerationAccess( tables, UNO_QUERY ); + + Reference< css::container::XEnumeration > enumeration = + enumerationAccess->createEnumeration(); + while( enumeration->hasMoreElements() ) + { + Reference< XPropertySet > set; + enumeration->nextElement() >>= set; + OUString name; +// OUString schema; + + if( set->getPropertyValue( st.NAME ) >>= name ) + { +// printf( "searching %s %s\n", +// OUStringToOString( schema, RTL_TEXTENCODING_ASCII_US ).getStr(), +// OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() ); + if( name == table ) + { + + if( keySupplier.is() ) + { + // is ambiguous, as I don't know postgresql searchpath, + // I can't continue here, as I may write to a different table + keySupplier.clear(); + SAL_INFO("connectivity.postgresql", "Can't offer updateable result set because table " << name << " is duplicated, add schema to resolve ambiguity"); + break; + } + keySupplier.set( set, UNO_QUERY ); + } + } + } + } + else + { + SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table << " is unknown)"); + } + + if( keySupplier.is() ) + { + Reference< XPropertySet > set( keySupplier, UNO_QUERY ); + set->getPropertyValue( getStatics().NAME ) >>= *pTable; + set->getPropertyValue( getStatics().SCHEMA_NAME ) >>= *pSchema; + set.clear(); + + Reference< XEnumerationAccess > keys ( keySupplier->getKeys(), UNO_QUERY ); + Reference< XEnumeration > enumeration = keys->createEnumeration(); + while( enumeration->hasMoreElements() ) + { + enumeration->nextElement() >>= set; + sal_Int32 keyType = 0; + if( (set->getPropertyValue( st.TYPE ) >>= keyType ) && + keyType == css::sdbcx::KeyType::PRIMARY ) + { + Reference< XColumnsSupplier > columns( set, UNO_QUERY ); + Reference< XIndexAccess > indexAccess( columns->getColumns(), UNO_QUERY ); + + int length = indexAccess->getCount(); + ret.resize( length ); +// printf( "primary key for Table %s is ", +// OUStringToOString( table, RTL_TEXTENCODING_ASCII_US ).getStr() ); + for( int i = 0 ; i < length ; i ++ ) + { + indexAccess->getByIndex( i ) >>= set; + OUString name; + set->getPropertyValue( st.NAME ) >>= name; + ret[i] = name; +// printf( "%s," , OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() ); + } +// printf( "\n" ); + } + } + if( ret.empty() ) + { + SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table << " does not have a primary key)"); + } + } + return ret; +} + +bool executePostgresCommand( const OString & cmd, struct CommandData *data ) +{ + ConnectionSettings *pSettings = *(data->ppSettings); + + sal_Int32 duration = osl_getGlobalTimer(); + PGresult *result = PQexec( pSettings->pConnection, cmd.getStr() ); + duration = osl_getGlobalTimer() - duration; + if( ! result ) + raiseSQLException( + data->owner, cmd, PQerrorMessage( pSettings->pConnection ) ); + + ExecStatusType state = PQresultStatus( result ); + *(data->pLastOidInserted) = 0; + data->pLastTableInserted->clear(); + *(data->pLastQuery) = cmd; + + bool ret = false; + switch( state ) + { + case PGRES_COMMAND_OK: + { + *(data->pMultipleResultUpdateCount) = atoi( PQcmdTuples( result ) ); + *(data->pMultipleResultAvailable) = false; + + // in case an oid value is available, we retrieve it + *(data->pLastOidInserted) = PQoidValue( result ); + + // in case it was a single insert, extract the name of the table, + // otherwise the table name is empty + *(data->pLastTableInserted) = + extractTableFromInsert( OStringToOUString( cmd, ConnectionSettings::encoding ) ); + + OString strMain = "executed command '" + cmd + "' successfully ('" + OString::number(*( data->pMultipleResultUpdateCount )) + + "), duration=" + OString::number(duration) + "ms"; + + OString strOption; + if( *(data->pLastOidInserted) ) + { + strOption += ", usedOid=" + OString::number( *(data->pLastOidInserted) ) + ", diagnosedTable=" + + OUStringToOString(*data->pLastTableInserted, ConnectionSettings::encoding); + } + SAL_INFO("connectivity.postgresql", strMain + strOption); + PQclear( result ); + break; + } + case PGRES_TUPLES_OK: // success + { + // In case it is a single table, it has a primary key and all columns + // belonging to the primary key are in the result set, allow updateable result sets + // otherwise, don't + OUString table, schema; + std::vector< OString > vec; + tokenizeSQL( cmd, vec ); + OUString sourceTable = + OStringToOUString( + extractSingleTableFromSelect( vec ), ConnectionSettings::encoding ); + + if( data->concurrency == + css::sdbc::ResultSetConcurrency::UPDATABLE ) + { + OString aReason; + if( sourceTable.getLength() ) + { + std::vector< OUString > sourceTableKeys = lookupKeys( + pSettings->tables.is() ? + pSettings->tables : data->tableSupplier->getTables() , + sourceTable, + &schema, + &table); + + // check, whether the columns are in the result set (required !) + int i; + for( i = 0 ; i < static_cast<int>(sourceTableKeys.size()) ; i ++ ) + { + if( -1 == PQfnumber( + result, + OUStringToOString( sourceTableKeys[i] , + ConnectionSettings::encoding ).getStr()) ) + { + break; + } + } + + if( !sourceTableKeys.empty() && i == static_cast<int>(sourceTableKeys.size()) ) + { + *(data->pLastResultset) = + UpdateableResultSet::createFromPGResultSet( + data->refMutex, data->owner, data->ppSettings, result, + schema, table, std::move(sourceTableKeys) ); + } + else if( ! table.getLength() ) + { + aReason = "can't support updateable resultset, because a single table in the " + "WHERE part of the statement could not be identified (" + cmd + "."; + } + else if( !sourceTableKeys.empty() ) + { + aReason = "can't support updateable resultset for table " + + OUStringToOString( schema, ConnectionSettings::encoding ) + "." + + OUStringToOString( table, ConnectionSettings::encoding ) + + ", because resultset does not contain a part of the primary key ( column " + + OUStringToOString( sourceTableKeys[i], ConnectionSettings::encoding ) + + " is missing )"; + } + else + { + + aReason = "can't support updateable resultset for table " + + OUStringToOString( schema, ConnectionSettings::encoding ) + "." + + OUStringToOString( table, ConnectionSettings::encoding ) + + ", because resultset table does not have a primary key "; + } + } + else + { + SAL_WARN("connectivity.postgresql", "can't support updateable result for selects with multiple tables (" << cmd << ")"); + } + if( ! (*(data->pLastResultset)).is() ) + { + SAL_WARN("connectivity.postgresql", aReason); + + // TODO: How to react here correctly ? + // remove this piece of code + *(data->pLastResultset) = + new FakedUpdateableResultSet( + data->refMutex, data->owner, + data->ppSettings,result, schema, table, + OStringToOUString( aReason, ConnectionSettings::encoding) ); + } + + } + else if( sourceTable.getLength() > 0) + { + splitConcatenatedIdentifier( sourceTable, &schema, &table ); + } + + sal_Int32 returnedRows = PQntuples( result ); + if( ! data->pLastResultset->is() ) + *(data->pLastResultset) = + Reference< XCloseable > ( + new ResultSet( + data->refMutex, data->owner, + data->ppSettings,result, schema, table ) ); + *(data->pMultipleResultAvailable) = true; + ret = true; + SAL_INFO("connectivity.postgresql", "executed query '" << cmd << "' successfully, duration=" << duration << "ms, returnedRows=" << returnedRows << "."); + break; + } + case PGRES_EMPTY_QUERY: + case PGRES_COPY_OUT: + case PGRES_COPY_IN: + case PGRES_BAD_RESPONSE: + case PGRES_NONFATAL_ERROR: + case PGRES_FATAL_ERROR: + default: + raiseSQLException( + data->owner, cmd, PQresultErrorMessage( result ) , PQresStatus( state ) ); + } + return ret; + +} + +static Sequence< OUString > getPrimaryKeyColumnNames( + const Reference< XConnection > & connection, const OUString &schemaName, const OUString &tableName ) +{ + Sequence< OUString > ret; + + Int2StringMap mapIndex2Name; + fillAttnum2attnameMap( mapIndex2Name, connection, schemaName, tableName ); + + // retrieve the primary key ... + Reference< XPreparedStatement > stmt = connection->prepareStatement( + "SELECT conkey " // 7 + "FROM pg_constraint INNER JOIN pg_class ON conrelid = pg_class.oid " + "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid " + "LEFT JOIN pg_class AS class2 ON confrelid = class2.oid " + "LEFT JOIN pg_namespace AS nmsp2 ON class2.relnamespace=nmsp2.oid " + "WHERE pg_class.relname = ? AND pg_namespace.nspname = ? AND pg_constraint.contype='p'" ); + DisposeGuard guard( stmt ); + Reference< XParameters > paras( stmt, UNO_QUERY ); + paras->setString( 1 , tableName ); + paras->setString( 2 , schemaName ); + Reference< XResultSet > rs = stmt->executeQuery(); + Reference< XRow > xRow( rs , UNO_QUERY ); + + if( rs->next() ) + { + ret = convertMappedIntArray2StringArray( mapIndex2Name, string2intarray(xRow->getString( 1 ) ) ); + } + return ret; +} + +static void getAutoValues( + String2StringMap & result, + const Reference< XConnection > & connection, + const OUString &schemaName, + const OUString & tableName, + const ConnectionSettings *pConnectionSettings ) +{ + OUString strDefaultValue = getColExprForDefaultSettingVal(pConnectionSettings); + Reference< XPreparedStatement > stmt = connection->prepareStatement( + "SELECT pg_attribute.attname, " + strDefaultValue + + "FROM pg_class, pg_namespace, pg_attribute " + "LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND " + "pg_attribute.attnum = pg_attrdef.adnum " + "WHERE pg_attribute.attrelid = pg_class.oid AND " + "pg_class.relnamespace = pg_namespace.oid AND " + "pg_namespace.nspname = ? AND " + // LEM TODO: this is weird; why "LIKE" and not "="? + // Most probably gives problems if tableName contains '%' + "pg_class.relname LIKE ? AND " + + strDefaultValue + " != ''" + ); + DisposeGuard guard( stmt ); + Reference< XParameters > paras( stmt, UNO_QUERY ); + paras->setString( 1 , schemaName ); + paras->setString( 2 , tableName ); + Reference< XResultSet > rs = stmt->executeQuery(); + Reference< XRow > xRow( rs , UNO_QUERY ); + + while( rs->next() ) + { + result[ OUStringToOString( xRow->getString( 1 ), RTL_TEXTENCODING_ASCII_US) ] = + OUStringToOString( xRow->getString(2), RTL_TEXTENCODING_ASCII_US ); + } +} + +Reference< XResultSet > getGeneratedValuesFromLastInsert( + ConnectionSettings *pConnectionSettings, + const Reference< XConnection > &connection, + sal_Int32 nLastOid, + const OUString & lastTableInserted, + const OString & lastQuery ) +{ + Reference< XResultSet > ret; + OUString query; + OUString schemaName, tableName; + splitConcatenatedIdentifier( + lastTableInserted, &schemaName, &tableName ); + + if( nLastOid && lastTableInserted.getLength() ) + { + OUStringBuffer buf( 128 ); + buf.append( "SELECT * FROM " ); + if( schemaName.getLength() ) + bufferQuoteQualifiedIdentifier(buf, schemaName, tableName, pConnectionSettings ); + else + bufferQuoteIdentifier( buf, lastTableInserted, pConnectionSettings ); + buf.append( " WHERE oid = " ); + buf.append( nLastOid ); + query = buf.makeStringAndClear(); + } + else if ( lastTableInserted.getLength() && lastQuery.getLength() ) + { + // extract nameValue Pairs + String2StringMap namedValues; + extractNameValuePairsFromInsert( namedValues, lastQuery ); + + // debug ... +// OStringBuffer buf( 128); +// buf.append( "extracting name/value from '" ); +// buf.append( lastQuery.getStr() ); +// buf.append( "' to [" ); +// for( String2StringMap::iterator ii = namedValues.begin() ; ii != namedValues.end() ; ++ii ) +// { +// buf.append( ii->first.getStr() ); +// buf.append( "=" ); +// buf.append( ii->second.getStr() ); +// buf.append( "," ); +// } +// buf.append( "]\n" ); +// printf( "%s", buf.makeStringAndClear() ); + + // TODO: make also unqualified tables names work here. Have a look at 2.8.3. The Schema Search Path + // in postgresql doc + + const Sequence< OUString > keyColumnNames = getPrimaryKeyColumnNames( connection, schemaName, tableName ); + if( keyColumnNames.hasElements() ) + { + OUStringBuffer buf( 128 ); + buf.append( "SELECT * FROM " ); + bufferQuoteQualifiedIdentifier(buf, schemaName, tableName, pConnectionSettings ); + buf.append( " WHERE " ); + bool bAdditionalCondition = false; + String2StringMap autoValues; + for( OUString const & columnNameUnicode : keyColumnNames ) + { + OUString value; + OString columnName = OUStringToOString( columnNameUnicode, ConnectionSettings::encoding ); + bool bColumnMatchNamedValue = false; + for (auto const& namedValue : namedValues) + { + if( columnName.equalsIgnoreAsciiCase( namedValue.first ) ) + { + value = OStringToOUString( namedValue.second , ConnectionSettings::encoding ); + bColumnMatchNamedValue = true; + break; + } + } + + // check, if a column of the primary key was not inserted explicitly, + if( !bColumnMatchNamedValue ) + { + if( autoValues.empty() ) + { + getAutoValues( autoValues, connection, schemaName, tableName, pConnectionSettings ); + } + // this could mean, that the column is a default or auto value, check this ... + bool bColumnMatchAutoValue = false; + for (auto const& autoValue : autoValues) + { + if( columnName.equalsIgnoreAsciiCase( autoValue.first ) ) + { + // it is indeed an auto value. + value = OStringToOUString(autoValue.second, RTL_TEXTENCODING_ASCII_US ); + // check, whether it is a sequence + + if( autoValue.second.startsWith("nextval(") ) + { + // retrieve current sequence value: + OUStringBuffer myBuf(128 ); + myBuf.append( "SELECT currval(" ); + myBuf.appendAscii( &(autoValue.second.getStr()[8])); + value = querySingleValue( connection, myBuf.makeStringAndClear() ); + } + bColumnMatchAutoValue = true; + break; + } + } + if( !bColumnMatchAutoValue ) + { + // it even was no autovalue, no sense to continue as we can't query the + // inserted row + buf.truncate(); + break; + } + } + + if( bAdditionalCondition ) + buf.append( " AND " ); + bufferQuoteIdentifier( buf, columnNameUnicode, pConnectionSettings ); + buf.append( " = " ); + buf.append( value ); + bAdditionalCondition = true; + } + query = buf.makeStringAndClear(); + } + } + + if( query.getLength() ) + { + Reference< css::sdbc::XStatement > stmt = connection->createStatement(); + ret = stmt->executeQuery( query ); + } + + return ret; + +} + +sal_Bool Statement::execute( const OUString& sql ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + OString cmd = OUStringToOString( sql, m_pSettings ); + + Reference< XCloseable > lastResultSetHolder = m_lastResultset; + if( lastResultSetHolder.is() ) + lastResultSetHolder->close(); + + m_lastResultset.clear(); + m_lastTableInserted.clear(); + + struct CommandData data; + data.refMutex = m_xMutex; + data.ppSettings = &m_pSettings; + data.pLastOidInserted = &m_lastOidInserted; + data.pLastQuery = &m_lastQuery; + data.pMultipleResultUpdateCount = &m_multipleResultUpdateCount; + data.pMultipleResultAvailable = &m_multipleResultAvailable; + data.pLastTableInserted = &m_lastTableInserted; + data.pLastResultset = &m_lastResultset; + data.owner = *this; + data.tableSupplier.set( m_connection, UNO_QUERY ); + data.concurrency = + extractIntProperty( this, getStatics().RESULT_SET_CONCURRENCY ); + return executePostgresCommand( cmd , &data ); +} + +Reference< XConnection > Statement::getConnection( ) +{ + Reference< XConnection > ret; + { + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + ret = m_connection; + } + return ret; +} + + +Any Statement::getWarnings( ) +{ + return Any(); +} + +void Statement::clearWarnings( ) +{ +} + +Reference< css::sdbc::XResultSetMetaData > Statement::getMetaData() +{ + Reference< css::sdbc::XResultSetMetaData > ret; + Reference< css::sdbc::XResultSetMetaDataSupplier > supplier( m_lastResultset, UNO_QUERY ); + if( supplier.is() ) + ret = supplier->getMetaData(); + return ret; +} + + +::cppu::IPropertyArrayHelper & Statement::getInfoHelper() +{ + return getStatementPropertyArrayHelper(); +} + + +sal_Bool Statement::convertFastPropertyValue( + Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) +{ + rOldValue = m_props[nHandle]; + bool bRet; + switch( nHandle ) + { + case STATEMENT_CURSOR_NAME: + { + OUString val; + bRet = ( rValue >>= val ); + rConvertedValue <<= val; + break; + } + case STATEMENT_ESCAPE_PROCESSING: + { + bool val(false); + bRet = ( rValue >>= val ); + rConvertedValue <<= val; + break; + } + case STATEMENT_FETCH_DIRECTION: + case STATEMENT_FETCH_SIZE: + case STATEMENT_MAX_FIELD_SIZE: + case STATEMENT_MAX_ROWS: + case STATEMENT_QUERY_TIME_OUT: + case STATEMENT_RESULT_SET_CONCURRENCY: + case STATEMENT_RESULT_SET_TYPE: + { + sal_Int32 val; + bRet = ( rValue >>= val ); + rConvertedValue <<= val; + break; + } + default: + { + throw IllegalArgumentException( + "pq_statement: Invalid property handle (" + + OUString::number( nHandle ) + ")", + *this, 2 ); + } + } + return bRet; +} + + +void Statement::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle,const Any& rValue ) +{ + m_props[nHandle] = rValue; +} + +void Statement::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + rValue = m_props[nHandle]; +} + +Reference < XPropertySetInfo > Statement::getPropertySetInfo() +{ + return OPropertySetHelper::createPropertySetInfo( getStatementPropertyArrayHelper() ); +} + + +Reference< XResultSet > Statement::getResultSet( ) +{ + return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY ); +} + +sal_Int32 Statement::getUpdateCount( ) +{ + return m_multipleResultUpdateCount; +} + +sal_Bool Statement::getMoreResults( ) +{ + // The PostgreSQL C interface always returns a single result, + // so we will never have multiple ones. + // Implicitly close the open resultset (if any) as per spec, + // and setup to signal "no more result, neither as resultset, + // nor as update count". + Reference< XCloseable > lastResultSetHolder = m_lastResultset; + if( lastResultSetHolder.is() ) + lastResultSetHolder->close(); + m_multipleResultUpdateCount = -1; + return false; +} + + +void Statement::disposing() +{ + close(); +} + +Reference< XResultSet > Statement::getGeneratedValues( ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + return getGeneratedValuesFromLastInsert( + m_pSettings, m_connection, m_lastOidInserted, m_lastTableInserted, m_lastQuery ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_statement.hxx b/connectivity/source/drivers/postgresql/pq_statement.hxx new file mode 100644 index 000000000..fae6568bb --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_statement.hxx @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <sal/config.h> + +#include <string_view> + +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/component.hxx> + +#include <libpq-fe.h> + +#include "pq_connection.hxx" +#include <com/sun/star/sdbc/XMultipleResults.hpp> +#include <com/sun/star/sdbc/XGeneratedResultSet.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> + +namespace pq_sdbc_driver +{ + +const sal_Int32 STATEMENT_CURSOR_NAME = 0; +const sal_Int32 STATEMENT_ESCAPE_PROCESSING = 1; +const sal_Int32 STATEMENT_FETCH_DIRECTION = 2; +const sal_Int32 STATEMENT_FETCH_SIZE = 3; +const sal_Int32 STATEMENT_MAX_FIELD_SIZE = 4; +const sal_Int32 STATEMENT_MAX_ROWS = 5; +const sal_Int32 STATEMENT_QUERY_TIME_OUT = 6; +const sal_Int32 STATEMENT_RESULT_SET_CONCURRENCY = 7; +const sal_Int32 STATEMENT_RESULT_SET_TYPE = 8; + +#define STATEMENT_SIZE 9 + +typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement, + css::sdbc::XCloseable, + css::sdbc::XWarningsSupplier, + css::sdbc::XMultipleResults, + css::sdbc::XGeneratedResultSet, + css::sdbc::XResultSetMetaDataSupplier + > Statement_BASE; + +class Statement : public Statement_BASE, + public cppu::OPropertySetHelper +{ +private: + css::uno::Any m_props[STATEMENT_SIZE]; + css::uno::Reference< css::sdbc::XConnection > m_connection; + ConnectionSettings *m_pSettings; + css::uno::Reference< css::sdbc::XCloseable > m_lastResultset; + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + bool m_multipleResultAvailable; + sal_Int32 m_multipleResultUpdateCount; + sal_Int32 m_lastOidInserted; + OUString m_lastTableInserted; + OString m_lastQuery; + +public: + /** + * @param ppConnection The piece of memory, pConnection points to, is accessible + * as long as a reference to parameter con is held. + */ + Statement( const rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection> & con, + struct ConnectionSettings *pSettings ); + + virtual ~Statement() override; +public: // XInterface + virtual void SAL_CALL acquire() noexcept override { Statement_BASE::acquire(); } + virtual void SAL_CALL release() noexcept override { Statement_BASE::release(); } + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & reqType ) override; + +public: // XCloseable + virtual void SAL_CALL close( ) override; + +public: // XStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( + const OUString& sql ) override; + virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override; + virtual sal_Bool SAL_CALL execute( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + +public: // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // OPropertySetHelper + virtual cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + using ::cppu::OPropertySetHelper::getFastPropertyValue; + + void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle ) const override; + + // XPropertySet + css::uno::Reference < css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + +public: // XGeneratedResultSet + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL + getGeneratedValues( ) override; + +public: // XMultipleResults + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override; + virtual sal_Int32 SAL_CALL getUpdateCount( ) override; + virtual sal_Bool SAL_CALL getMoreResults( ) override; + +public: // OComponentHelper + virtual void SAL_CALL disposing() override; + +public: // XResultSetMetaDataSupplier (is required by framework (see + // dbaccess/source/core/api/preparedstatement.cxx::getMetaData() ) + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + +private: + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkClosed(); + /// @throws css::sdbc::SQLException + void raiseSQLException( std::u16string_view sql, const char * errorMsg ); +}; + + +struct CommandData +{ + ConnectionSettings **ppSettings; + sal_Int32 *pLastOidInserted; + sal_Int32 *pMultipleResultUpdateCount; + bool *pMultipleResultAvailable; + OUString *pLastTableInserted; + css::uno::Reference< css::sdbc::XCloseable > *pLastResultset; + OString *pLastQuery; + ::rtl::Reference< comphelper::RefCountedMutex > refMutex; + css::uno::Reference< css::uno::XInterface > owner; + css::uno::Reference< css::sdbcx::XTablesSupplier > tableSupplier; + sal_Int32 concurrency; +}; + +bool executePostgresCommand( const OString & cmd, struct CommandData *data ); +css::uno::Reference< css::sdbc::XResultSet > getGeneratedValuesFromLastInsert( + ConnectionSettings *pConnectionSettings, + const css::uno::Reference< css::sdbc::XConnection > &connection, + sal_Int32 nLastOid, + const OUString & lastTableInserted, + const OString & lastQuery ); + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_statics.cxx b/connectivity/source/drivers/postgresql/pq_statics.cxx new file mode 100644 index 000000000..ec3d0d8ac --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_statics.cxx @@ -0,0 +1,626 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include "pq_statics.hxx" +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::beans::PropertyAttribute::READONLY; +using com::sun::star::beans::Property; + +namespace pq_sdbc_driver +{ + +namespace { + +struct DefColumnMetaData +{ + const char * columnName; + const char * tableName; + const char * schemaTableName; + const char * typeName; + sal_Int32 type; + sal_Int32 precision; + sal_Int32 scale; + bool isCurrency; + bool isNullable; + bool isAutoIncrement; +}; + +struct BaseTypeDef { const char * typeName; sal_Int32 value; }; + +struct PropertyDef +{ + PropertyDef( const OUString &str, const Type &t ) + : name( str ) , type( t ) {} + OUString name; + css::uno::Type type; +}; + +struct PropertyDefEx : public PropertyDef +{ + PropertyDefEx( const OUString & str, const Type &t , sal_Int32 a ) + : PropertyDef( str, t ) , attribute( a ) + {} + sal_Int32 attribute; +}; + +} + +static cppu::IPropertyArrayHelper * createPropertyArrayHelper( + PropertyDef const *props, int count , sal_Int16 attr ) +{ + Sequence< Property > seq( count ); + auto seqRange = asNonConstRange(seq); + for( int i = 0 ; i < count ; i ++ ) + { + seqRange[i] = Property( props[i].name, i, props[i].type, attr ); + } + return new cppu::OPropertyArrayHelper( seq, true ); +} + +static cppu::IPropertyArrayHelper * createPropertyArrayHelper( + PropertyDefEx const *props, int count ) +{ + Sequence< Property > seq( count ); + auto seqRange = asNonConstRange(seq); + for( int i = 0 ; i < count ; i ++ ) + { + seqRange[i] = Property( props[i].name, i, props[i].type, props[i].attribute ); + } + return new cppu::OPropertyArrayHelper( seq, true ); +} + +Statics & getStatics() +{ + static Statics* p = []() { + static Statics statics ; + statics.SYSTEM_TABLE = "SYSTEM TABLE"; + statics.TABLE = "TABLE"; + statics.VIEW = "VIEW"; + statics.UNKNOWN = "UNKNOWN"; + statics.YES = "YES"; + statics.NO = "NO"; + statics.NO_NULLS = "NO_NULLS"; + statics.NULABLE = "NULABLE"; + statics.NULLABLE_UNKNOWN = "NULLABLE_UNKNOWN"; + + statics.TYPE = "Type"; + statics.TYPE_NAME = "TypeName"; + statics.NAME = "Name"; + statics.SCHEMA_NAME = "SchemaName"; + statics.CATALOG_NAME = "CatalogName"; + statics.DESCRIPTION = "Description"; + statics.PRIVILEGES = "Privileges"; + + statics.DEFAULT_VALUE = "DefaultValue"; + statics.IS_AUTO_INCREMENT = "IsAutoIncrement"; + statics.IS_CURRENCY = "IsCurrency"; + statics.IS_NULLABLE = "IsNullable"; + statics.IS_ROW_VERSISON = "IsRowVersion"; + statics.PRECISION = "Precision"; + statics.SCALE = "Scale"; + + statics.cPERCENT = "%"; + statics.BEGIN = "BEGIN"; + statics.COMMIT = "COMMIT"; + statics.ROLLBACK = "ROLLBACK"; + + statics.KEY = "Key"; + statics.REFERENCED_TABLE = "ReferencedTable"; + statics.UPDATE_RULE = "UpdateRule"; + statics.DELETE_RULE = "DeleteRule"; + statics.PRIVATE_COLUMNS = "PrivateColumns"; + statics.PRIVATE_FOREIGN_COLUMNS = "PrivateForeignColumns"; + + statics.KEY_COLUMN = "KeyColumn"; + statics.RELATED_COLUMN = "RelatedColumn"; + statics.PASSWORD = "Password"; + statics.USER = "User"; + + statics.CURSOR_NAME = "CursorName"; + statics.ESCAPE_PROCESSING = "EscapeProcessing"; + statics.FETCH_DIRECTION = "FetchDirection"; + statics.FETCH_SIZE = "FetchSize"; + statics.IS_BOOKMARKABLE = "IsBookmarkable"; + statics.RESULT_SET_CONCURRENCY = "ResultSetConcurrency"; + statics.RESULT_SET_TYPE = "ResultSetType"; + + statics.COMMAND = "Command"; + statics.CHECK_OPTION = "CheckOption"; + + statics.TRUE = "t"; + statics.FALSE = "f"; + statics.IS_PRIMARY_KEY_INDEX = "IsPrimaryKeyIndex"; + statics.IS_CLUSTERED = "IsClustered"; + statics.IS_UNIQUE = "IsUnique"; + statics.IS_ASCENDING = "IsAscending"; + statics.PRIVATE_COLUMN_INDEXES = "PrivateColumnIndexes"; + statics.HELP_TEXT = "HelpText"; + + statics.CATALOG = "Catalog"; + + Type tString = cppu::UnoType<OUString>::get(); + Type tInt = cppu::UnoType<sal_Int32>::get(); + Type tBool = cppu::UnoType<bool>::get(); + Type tStringSequence = cppu::UnoType<css::uno::Sequence< OUString >>::get(); + + // Table props set + ImplementationStatics &ist = statics.refl.table; + ist.implName = "org.openoffice.comp.pq.sdbcx.Table"; + ist.serviceNames = { "com.sun.star.sdbcx.Table" }; + PropertyDef tableDef[] = + { + PropertyDef( statics.CATALOG_NAME , tString ), + PropertyDef( statics.DESCRIPTION , tString ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PRIVILEGES , tInt ), + PropertyDef( statics.SCHEMA_NAME , tString ), + PropertyDef( statics.TYPE , tString ) + }; + ist.pProps = createPropertyArrayHelper( + tableDef, std::size(tableDef), READONLY ); + + statics.refl.tableDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.TableDescriptor"; + statics.refl.tableDescriptor.serviceNames = { "com.sun.star.sdbcx.TableDescriptor" }; + PropertyDef tableDescDef[] = + { + PropertyDef( statics.CATALOG_NAME , tString ), + PropertyDef( statics.DESCRIPTION , tString ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PRIVILEGES , tInt ), + PropertyDef( statics.SCHEMA_NAME , tString ) + }; + statics.refl.tableDescriptor.pProps = createPropertyArrayHelper( + tableDescDef, std::size(tableDescDef), 0 ); + + // Column props set + statics.refl.column.implName = "org.openoffice.comp.pq.sdbcx.Column"; + statics.refl.column.serviceNames = { "com.sun.star.sdbcx.Column" }; + PropertyDefEx columnDef[] = + { + PropertyDefEx( statics.CATALOG_NAME , tString, READONLY ), + PropertyDefEx( statics.DEFAULT_VALUE, tString, READONLY ), + PropertyDefEx( statics.DESCRIPTION , tString, READONLY ), +// PropertyDefEx( statics.HELP_TEXT , tString, BOUND ), + PropertyDefEx( statics.IS_AUTO_INCREMENT, tBool, READONLY ), + PropertyDefEx( statics.IS_CURRENCY, tBool, READONLY ), + PropertyDefEx( statics.IS_NULLABLE, tInt, READONLY ), + PropertyDefEx( statics.IS_ROW_VERSISON, tBool,READONLY ), + PropertyDefEx( statics.NAME , tString,READONLY ), + PropertyDefEx( statics.PRECISION , tInt, READONLY ), + PropertyDefEx( statics.SCALE , tInt ,READONLY), + PropertyDefEx( statics.TYPE , tInt ,READONLY), + PropertyDefEx( statics.TYPE_NAME , tString ,READONLY) + }; + statics.refl.column.pProps = createPropertyArrayHelper( + columnDef, std::size(columnDef) ); + + statics.refl.columnDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.ColumnDescriptor"; + statics.refl.columnDescriptor.serviceNames = { "com.sun.star.sdbcx.ColumnDescriptor" }; + PropertyDef columnDescDef[] = + { + PropertyDef( statics.CATALOG_NAME , tString ), + PropertyDef( statics.DEFAULT_VALUE, tString ), + PropertyDef( statics.DESCRIPTION , tString ), +// PropertyDef( statics.HELP_TEXT , tString ), + PropertyDef( statics.IS_AUTO_INCREMENT, tBool ), + PropertyDef( statics.IS_CURRENCY, tBool ), + PropertyDef( statics.IS_NULLABLE, tInt ), + PropertyDef( statics.IS_ROW_VERSISON, tBool ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PRECISION , tInt ), + PropertyDef( statics.SCALE , tInt ), + PropertyDef( statics.TYPE , tInt ), + PropertyDef( statics.TYPE_NAME , tString ) + }; + + statics.refl.columnDescriptor.pProps = createPropertyArrayHelper( + columnDescDef, std::size(columnDescDef), 0 ); + + // Key properties + statics.refl.key.implName = "org.openoffice.comp.pq.sdbcx.Key"; + statics.refl.key.serviceNames = { "com.sun.star.sdbcx.Key" }; + PropertyDef keyDef[] = + { + PropertyDef( statics.DELETE_RULE, tInt ), + PropertyDef( statics.NAME, tString ), + PropertyDef( statics.PRIVATE_COLUMNS, tStringSequence ), + PropertyDef( statics.PRIVATE_FOREIGN_COLUMNS, tStringSequence ), + PropertyDef( statics.REFERENCED_TABLE, tString ), + PropertyDef( statics.TYPE, tInt ), + PropertyDef( statics.UPDATE_RULE, tInt ) + }; + statics.refl.key.pProps = createPropertyArrayHelper( + keyDef, std::size(keyDef), READONLY ); + + + // Key properties + statics.refl.keyDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.KeyDescriptor"; + statics.refl.keyDescriptor.serviceNames = { "com.sun.star.sdbcx.KeyDescriptor" }; + PropertyDef keyDescDef[] = + { + PropertyDef( statics.DELETE_RULE, tInt ), + PropertyDef( statics.NAME, tString ), + PropertyDef( statics.REFERENCED_TABLE, tString ), + PropertyDef( statics.TYPE, tInt ), + PropertyDef( statics.UPDATE_RULE, tInt ) + }; + statics.refl.keyDescriptor.pProps = createPropertyArrayHelper( + keyDescDef, std::size(keyDescDef), 0 ); + + + // KeyColumn props set + statics.refl.keycolumn.implName = "org.openoffice.comp.pq.sdbcx.KeyColumn"; + statics.refl.keycolumn.serviceNames = { "com.sun.star.sdbcx.KeyColumn" }; + PropertyDef keycolumnDef[] = + { + PropertyDef( statics.CATALOG_NAME , tString ), + PropertyDef( statics.DEFAULT_VALUE, tString ), + PropertyDef( statics.DESCRIPTION , tString ), + PropertyDef( statics.IS_AUTO_INCREMENT, tBool ), + PropertyDef( statics.IS_CURRENCY, tBool ), + PropertyDef( statics.IS_NULLABLE, tInt ), + PropertyDef( statics.IS_ROW_VERSISON, tBool ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PRECISION , tInt ), + PropertyDef( statics.RELATED_COLUMN, tString ), + PropertyDef( statics.SCALE , tInt ), + PropertyDef( statics.TYPE , tInt ), + PropertyDef( statics.TYPE_NAME , tString ) + }; + statics.refl.keycolumn.pProps = createPropertyArrayHelper( + keycolumnDef, std::size(keycolumnDef), READONLY ); + + // KeyColumn props set + statics.refl.keycolumnDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.KeyColumnDescriptor"; + statics.refl.keycolumnDescriptor.serviceNames = + { "com.sun.star.sdbcx.KeyColumnDescriptor" }; + PropertyDef keycolumnDescDef[] = + { + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.RELATED_COLUMN, tString ) + }; + statics.refl.keycolumnDescriptor.pProps = createPropertyArrayHelper( + keycolumnDescDef, std::size(keycolumnDescDef), 0 ); + + // view props set + statics.refl.view.implName = "org.openoffice.comp.pq.sdbcx.View"; + statics.refl.view.serviceNames = { "com.sun.star.sdbcx.View" }; + PropertyDef viewDef[] = + { + PropertyDef( statics.CATALOG_NAME , tString ), + PropertyDef( statics.CHECK_OPTION , tInt ), + PropertyDef( statics.COMMAND , tString ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.SCHEMA_NAME , tString ) + }; + statics.refl.view.pProps = createPropertyArrayHelper( + viewDef, std::size(viewDef), READONLY ); + + // view props set + statics.refl.viewDescriptor.implName = "org.openoffice.comp.pq.sdbcx.ViewDescriptor"; + statics.refl.viewDescriptor.serviceNames = { "com.sun.star.sdbcx.ViewDescriptor" }; + statics.refl.viewDescriptor.pProps = createPropertyArrayHelper( + viewDef, std::size(viewDef), 0 ); // reuse view, as it is identical + // user props set + statics.refl.user.implName = "org.openoffice.comp.pq.sdbcx.User"; + statics.refl.user.serviceNames = { "com.sun.star.sdbcx.User" }; + PropertyDef userDefRO[] = + { + PropertyDef( statics.NAME , tString ) + }; + statics.refl.user.pProps = createPropertyArrayHelper( + userDefRO, std::size(userDefRO), READONLY ); + + // user props set + statics.refl.userDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.UserDescriptor"; + statics.refl.userDescriptor.serviceNames = { "com.sun.star.sdbcx.UserDescriptor" }; + PropertyDef userDefWR[] = + { + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PASSWORD , tString ) + }; + statics.refl.userDescriptor.pProps = createPropertyArrayHelper( + userDefWR, std::size(userDefWR), 0 ); + + // index props set + statics.refl.index.implName = "org.openoffice.comp.pq.sdbcx.Index"; + statics.refl.index.serviceNames = { "com.sun.star.sdbcx.Index" }; + PropertyDef indexDef[] = + { + PropertyDef( statics.CATALOG , tString ), + PropertyDef( statics.IS_CLUSTERED, tBool ), + PropertyDef( statics.IS_PRIMARY_KEY_INDEX, tBool ), + PropertyDef( statics.IS_UNIQUE, tBool ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PRIVATE_COLUMN_INDEXES, tStringSequence ) + }; + statics.refl.index.pProps = createPropertyArrayHelper( + indexDef, std::size(indexDef), READONLY ); + + // index props set + statics.refl.indexDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.IndexDescriptor"; + statics.refl.indexDescriptor.serviceNames = { "com.sun.star.sdbcx.IndexDescriptor" }; + statics.refl.indexDescriptor.pProps = createPropertyArrayHelper( + indexDef, std::size(indexDef), 0 ); + + // indexColumn props set + statics.refl.indexColumn.implName = "org.openoffice.comp.pq.sdbcx.IndexColumn"; + statics.refl.indexColumn.serviceNames = { "com.sun.star.sdbcx.IndexColumn" }; + PropertyDef indexColumnDef[] = + { + PropertyDef( statics.CATALOG_NAME , tString ), + PropertyDef( statics.DEFAULT_VALUE, tString ), + PropertyDef( statics.DESCRIPTION , tString ), + PropertyDef( statics.IS_ASCENDING, tBool ), + PropertyDef( statics.IS_AUTO_INCREMENT, tBool ), + PropertyDef( statics.IS_CURRENCY, tBool ), + PropertyDef( statics.IS_NULLABLE, tInt ), + PropertyDef( statics.IS_ROW_VERSISON, tBool ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PRECISION , tInt ), + PropertyDef( statics.SCALE , tInt ), + PropertyDef( statics.TYPE , tInt ), + PropertyDef( statics.TYPE_NAME , tString ) + }; + statics.refl.indexColumn.pProps = createPropertyArrayHelper( + indexColumnDef, std::size(indexColumnDef), READONLY ); + + // indexColumn props set + statics.refl.indexColumnDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.IndexColumnDescriptor"; + statics.refl.indexColumnDescriptor.serviceNames = + { "com.sun.star.sdbcx.IndexColumnDescriptor" }; + PropertyDef indexColumnDescDef[] = + { + PropertyDef( statics.IS_ASCENDING, tBool ), + PropertyDef( statics.NAME , tString ) + }; + statics.refl.indexColumnDescriptor.pProps = createPropertyArrayHelper( + indexColumnDescDef, std::size(indexColumnDescDef), 0 ); + + // databasemetadata + statics.tablesRowNames = std::vector< OUString > ( 5 ); + statics.tablesRowNames[TABLE_INDEX_CATALOG] = "TABLE_CAT"; + statics.tablesRowNames[TABLE_INDEX_SCHEMA] = "TABLE_SCHEM"; + statics.tablesRowNames[TABLE_INDEX_NAME] = "TABLE_NAME"; + statics.tablesRowNames[TABLE_INDEX_TYPE] = "TABLE_TYPE"; + statics.tablesRowNames[TABLE_INDEX_REMARKS] = "REMARKS"; + + statics.primaryKeyNames = std::vector< OUString > ( 6 ); + statics.primaryKeyNames[0] = "TABLE_CAT"; + statics.primaryKeyNames[1] = "TABLE_SCHEM"; + statics.primaryKeyNames[2] = "TABLE_NAME"; + statics.primaryKeyNames[3] = "COLUMN_NAME"; + statics.primaryKeyNames[4] = "KEY_SEQ"; + statics.primaryKeyNames[5] = "PK_NAME"; + + statics.SELECT = "SELECT"; + statics.UPDATE = "UPDATE"; + statics.INSERT = "INSERT"; + statics.DELETE = "DELETE"; + statics.RULE = "RULE"; + statics.REFERENCES = "REFERENCES"; + statics.TRIGGER = "TRIGGER"; + statics.EXECUTE = "EXECUTE"; + statics.USAGE = "USAGE"; + statics.CREATE = "CREATE"; + statics.TEMPORARY = "TEMPORARY"; + statics.INDEX = "Index"; + statics.INDEX_COLUMN = "IndexColumn"; + + statics.schemaNames = std::vector< OUString > ( 1 ); + statics.schemaNames[0] = "TABLE_SCHEM"; + + statics.tableTypeData = std::vector< std::vector< Any > >( 2 ); + + statics.tableTypeData[0] = std::vector< Any > ( 1 ); + statics.tableTypeData[0][0] <<= statics.TABLE; + +// statics.tableTypeData[2] = Sequence< Any > ( 1 ); +// statics.tableTypeData[2][0] <<= statics.VIEW; + + statics.tableTypeData[1] = std::vector< Any > ( 1 ); + statics.tableTypeData[1][0] <<= statics.SYSTEM_TABLE; + + statics.tableTypeNames = std::vector< OUString > ( 1 ); + statics.tableTypeNames[0] = "TABLE_TYPE"; + + statics.columnRowNames = + { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", + "DATA_TYPE", "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH", + "DECIMAL_DIGITS", "NUM_PREC_RADIX", "NULLABLE", "REMARKS", + "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH", + "ORDINAL_POSITION", "IS_NULLABLE" + }; + + statics.typeinfoColumnNames = + { + "TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX", + "LITERAL_SUFFIX", "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE", + "SEARCHABLE", "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE", + "AUTO_INCREMENT", "LOCAL_TYPE_NAME", "MINIMUM_SCALE", + "MAXIMUM_SCALE", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", + "NUM_PREC_RADIX" + }; + + statics.indexinfoColumnNames = + { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "NON_UNIQUE", "INDEX_QUALIFIER", "INDEX_NAME", + "TYPE", "ORDINAL_POSITION", "COLUMN_NAME", + "ASC_OR_DESC", "CARDINALITY", "PAGES", "FILTER_CONDITION" + }; + + statics.resultSetArrayColumnNames = { "INDEX" , "VALUE" }; + + // LEM TODO see if a refresh is needed; obtain automatically from pg_catalog.pg_type? + BaseTypeDef baseTypeDefs[] = + { + { "bool" , css::sdbc::DataType::BOOLEAN }, + { "bytea", css::sdbc::DataType::VARBINARY }, + { "char" , css::sdbc::DataType::CHAR }, + + { "int8" , css::sdbc::DataType::BIGINT }, + { "serial8" , css::sdbc::DataType::BIGINT }, + + + { "int2" , css::sdbc::DataType::SMALLINT }, + + { "int4" , css::sdbc::DataType::INTEGER }, +// { "regproc" , css::sdbc::DataType::INTEGER }, +// { "oid" , css::sdbc::DataType::INTEGER }, +// { "xid" , css::sdbc::DataType::INTEGER }, +// { "cid" , css::sdbc::DataType::INTEGER }, +// { "serial", css::sdbc::DataType::INTEGER }, +// { "serial4", css::sdbc::DataType::INTEGER }, + + { "text", css::sdbc::DataType::LONGVARCHAR }, + { "bpchar", css::sdbc::DataType::CHAR }, + { "varchar", css::sdbc::DataType::VARCHAR }, + + { "float4", css::sdbc::DataType::REAL }, + { "float8", css::sdbc::DataType::DOUBLE }, + + { "numeric", css::sdbc::DataType::NUMERIC }, + { "decimal", css::sdbc::DataType::DECIMAL }, + + { "date", css::sdbc::DataType::DATE }, + { "time", css::sdbc::DataType::TIME }, + { "timestamp", css::sdbc::DataType::TIMESTAMP }, + +// { "_bool" , css::sdbc::DataType::ARRAY }, +// { "_bytea", css::sdbc::DataType::ARRAY }, +// { "_char" , css::sdbc::DataType::ARRAY }, + +// { "_int8" , css::sdbc::DataType::ARRAY }, +// { "_serial8" , css::sdbc::DataType::ARRAY }, + + +// { "_int2" , css::sdbc::DataType::ARRAY }, + +// { "_int4" , css::sdbc::DataType::ARRAY }, +// { "_regproc" , css::sdbc::DataType::ARRAY }, +// { "_oid" , css::sdbc::DataType::ARRAY }, +// { "_xid" , css::sdbc::DataType::ARRAY }, +// { "_cid" , css::sdbc::DataType::ARRAY }, + +// { "_text", css::sdbc::DataType::ARRAY }, +// { "_bpchar", css::sdbc::DataType::ARRAY }, +// { "_varchar", css::sdbc::DataType::ARRAY }, + +// { "_float4", css::sdbc::DataType::ARRAY }, +// { "_float8", css::sdbc::DataType::ARRAY }, + +// { "_numeric", css::sdbc::DataType::ARRAY }, +// { "_decimal", css::sdbc::DataType::ARRAY }, + +// { "_date", css::sdbc::DataType::ARRAY }, // switch to date later +// { "_time", css::sdbc::DataType::ARRAY }, // switch to time later + + { nullptr, 0 } + }; + int i; + for( i = 0 ; baseTypeDefs[i].typeName ; i ++ ) + { + statics.baseTypeMap[ + OUString::createFromAscii( baseTypeDefs[i].typeName) ] = + baseTypeDefs[i].value; + } + + // This is the metadata for the columns of the recordset returned + // by css::sdbc::XDatabaseMetaData::getTypeInfo(), + // that is what is returned by getTypeInfo().getMetaData() + DefColumnMetaData defTypeInfoMetaData[] = + { + { "TYPE_NAME", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 0 + { "DATA_TYPE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::SMALLINT, 0,50,false,false,false }, // 1 + { "PRECISION", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false }, // 2 + { "LITERAL_PREFIX", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 3 + { "LITERAL_SUFFIX", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 4 + { "CREATE_PARAMS", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 5 + { "NULLABLE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false }, // 6 + { "CASE_SENSITIVE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::BOOLEAN, 0,50,false,false,false }, // 7 + { "SEARCHABLE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::SMALLINT, 0,50,false,false,false }, // 8 + { "UNSIGNED_ATTRIBUTE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::BOOLEAN, 0,50,false,false,false }, // 9 + { "FIXED_PREC_SCALE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::BOOLEAN, 0,50,false,false,false }, // 10 + { "AUTO_INCREMENT", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::BOOLEAN, 0,50,false,false,false }, // 11 + { "LOCAL_TYPE_NAME", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 12 + { "MINIMUM_SCALE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::SMALLINT, 0,50,false,false,false}, // 13 + { "MAXIMUM_SCALE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::SMALLINT, 0,50,false,false,false }, // 14 + { "SQL_DATA_TYPE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false }, // 15 + { "SQL_DATETIME_SUB", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false}, // 16 + { "NUM_PREC_RADIX", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false }, // 17 + {nullptr,nullptr,nullptr,nullptr,0,0,0,false,false,false} + }; + + for( i = 0 ; defTypeInfoMetaData[i].columnName ; i++ ) + { + statics.typeInfoMetaData.push_back( + ColumnMetaData( + OUString::createFromAscii( defTypeInfoMetaData[i].columnName ), + OUString::createFromAscii( defTypeInfoMetaData[i].tableName ), + OUString::createFromAscii( defTypeInfoMetaData[i].schemaTableName ), + OUString::createFromAscii( defTypeInfoMetaData[i].typeName ), + defTypeInfoMetaData[i].type, + defTypeInfoMetaData[i].precision, + defTypeInfoMetaData[i].scale, + defTypeInfoMetaData[i].isCurrency, + defTypeInfoMetaData[i].isNullable, + defTypeInfoMetaData[i].isAutoIncrement ) ); + } + + return &statics; + }(); + return *p; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_statics.hxx b/connectivity/source/drivers/postgresql/pq_statics.hxx new file mode 100644 index 000000000..b5a868d6c --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_statics.hxx @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <unordered_map> +#include <vector> + +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#include <cppuhelper/propshlp.hxx> + +namespace pq_sdbc_driver +{ + +struct ColumnMetaData +{ + ColumnMetaData( + const OUString &_columnName, + const OUString &_tableName, + const OUString &_schemaTableName, + const OUString &_typeName, + sal_Int32 _type, + sal_Int32 _precision, + sal_Int32 _scale, + bool _isCurrency, + bool _isNullable, + bool _isAutoIncrement ) : + columnName( _columnName ), + tableName( _tableName ), + schemaTableName( _schemaTableName ), + typeName( _typeName ), + type( _type ), + precision( _precision ), + scale( _scale ), + isCurrency( _isCurrency ), + isNullable( _isNullable ), + isAutoIncrement( _isAutoIncrement ) + {} + + OUString columnName; + OUString tableName; + OUString schemaTableName; + OUString typeName; + sal_Int32 type; + sal_Int32 precision; + sal_Int32 scale; + bool isCurrency; + bool isNullable; + bool isAutoIncrement; +}; + +typedef std::vector< ColumnMetaData > ColumnMetaDataVector; + +typedef std::unordered_map +< + OUString, + sal_Int32 +> BaseTypeMap; + +struct ImplementationStatics +{ + ImplementationStatics() : + pProps(nullptr) + {} + + OUString implName; + css::uno::Sequence< OUString > serviceNames; + cppu::IPropertyArrayHelper *pProps; + css::uno::Sequence< css::uno::Type > types; +}; + +struct ReflectionImplementations +{ + struct ImplementationStatics table; + struct ImplementationStatics tableDescriptor; + struct ImplementationStatics column; + struct ImplementationStatics columnDescriptor; + struct ImplementationStatics key; + struct ImplementationStatics keyDescriptor; + struct ImplementationStatics keycolumn; + struct ImplementationStatics keycolumnDescriptor; + struct ImplementationStatics user; + struct ImplementationStatics userDescriptor; + struct ImplementationStatics view; + struct ImplementationStatics viewDescriptor; + struct ImplementationStatics index; + struct ImplementationStatics indexDescriptor; + struct ImplementationStatics indexColumn; + struct ImplementationStatics indexColumnDescriptor; +}; + +const sal_Int32 TABLE_INDEX_CATALOG = 0; +const sal_Int32 TABLE_INDEX_SCHEMA = 1; +const sal_Int32 TABLE_INDEX_NAME = 2; +const sal_Int32 TABLE_INDEX_TYPE = 3; +const sal_Int32 TABLE_INDEX_REMARKS = 4; + +struct Statics +{ + OUString SYSTEM_TABLE; + OUString TABLE; + OUString VIEW; + OUString UNKNOWN; + OUString YES; + OUString NO; + OUString NO_NULLS; + OUString NULABLE; + OUString NULLABLE_UNKNOWN; + OUString SELECT; + OUString UPDATE; + OUString INSERT; + OUString DELETE; + OUString RULE; + OUString REFERENCES; + OUString TRIGGER; + OUString EXECUTE; + OUString USAGE; + OUString CREATE; + OUString TEMPORARY; + OUString INDEX; + OUString INDEX_COLUMN; + + OUString NAME; + OUString SCHEMA_NAME; + OUString CATALOG_NAME; + OUString DESCRIPTION; + OUString TYPE; + OUString TYPE_NAME; + OUString PRIVILEGES; + + OUString DEFAULT_VALUE; + OUString IS_AUTO_INCREMENT; + OUString IS_CURRENCY; + OUString IS_NULLABLE; + OUString IS_ROW_VERSISON; + OUString PRECISION; + OUString SCALE; + + OUString cPERCENT; + + OUString BEGIN; + OUString ROLLBACK; + OUString COMMIT; + + OUString KEY; + OUString REFERENCED_TABLE; + OUString UPDATE_RULE; + OUString DELETE_RULE; + OUString PRIVATE_COLUMNS; + OUString PRIVATE_FOREIGN_COLUMNS; + + OUString KEY_COLUMN; + OUString RELATED_COLUMN; + + OUString PASSWORD; + OUString USER; + + OUString CURSOR_NAME; + OUString ESCAPE_PROCESSING; + OUString FETCH_DIRECTION; + OUString FETCH_SIZE; + OUString IS_BOOKMARKABLE; + OUString RESULT_SET_CONCURRENCY; + OUString RESULT_SET_TYPE; + + OUString COMMAND; + OUString CHECK_OPTION; + + OUString TRUE; + OUString FALSE; + + OUString IS_PRIMARY_KEY_INDEX; + OUString IS_CLUSTERED; + OUString IS_UNIQUE; + OUString PRIVATE_COLUMN_INDEXES; + OUString HELP_TEXT; + + OUString CATALOG; + OUString IS_ASCENDING; + ReflectionImplementations refl; + + std::vector< OUString > tablesRowNames; + std::vector< OUString > columnRowNames; + std::vector< OUString > primaryKeyNames; + std::vector< OUString > schemaNames; + std::vector< OUString > tableTypeNames; + std::vector< OUString > typeinfoColumnNames; + std::vector< OUString > indexinfoColumnNames; + std::vector< OUString > resultSetArrayColumnNames; + std::vector< std::vector< css::uno::Any > > tableTypeData; + + ColumnMetaDataVector typeInfoMetaData; + BaseTypeMap baseTypeMap; + Statics(){} +private: + Statics( const Statics & ) = delete; + Statics & operator = ( const Statics & ) = delete; +}; + +Statics & getStatics(); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_tools.cxx b/connectivity/source/drivers/postgresql/pq_tools.cxx new file mode 100644 index 000000000..eb90c24ce --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_tools.cxx @@ -0,0 +1,1249 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/config.h> + +#include <o3tl/any.hxx> +#include <o3tl/string_view.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/KeyRule.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> + +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +#include <libpq-fe.h> +#include <string.h> +#include <string_view> + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::lang::XComponent; + +using com::sun::star::sdbc::SQLException; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XConnection; +using com::sun::star::sdbc::XPreparedStatement; +using com::sun::star::sdbc::XParameters; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XRow; + +using com::sun::star::sdbcx::XColumnsSupplier; + +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Any; + +using com::sun::star::container::XEnumeration; +using com::sun::star::container::XEnumerationAccess; + +namespace pq_sdbc_driver +{ + +OUString concatQualified( std::u16string_view a, std::u16string_view b) +{ + return OUString::Concat(a) + "." + b; +} + +static OString iOUStringToOString( std::u16string_view str, ConnectionSettings const *settings) { + OSL_ENSURE(settings, "pgsql-sdbc: OUStringToOString got NULL settings"); + return rtl::OUStringToOString( str, ConnectionSettings::encoding ); +} + +OString OUStringToOString( std::u16string_view str, ConnectionSettings const *settings) { + return iOUStringToOString( str, settings ); +} + +void bufferEscapeConstant( OUStringBuffer & buf, std::u16string_view value, ConnectionSettings *settings ) +{ + + OString y = iOUStringToOString( value, settings ); + OStringBuffer strbuf( y.getLength() * 2 + 2 ); + int error; + int len = PQescapeStringConn(settings->pConnection, const_cast<char*>(strbuf.getStr()), y.getStr() , y.getLength(), &error ); + if ( error ) + { + char *errstr = PQerrorMessage(settings->pConnection); + // As of PostgreSQL 9.1, the only possible errors "involve invalid multibyte encoding" + // According to https://www2.opengroup.org/ogsys/jsp/publications/PublicationDetails.jsp?publicationid=11216 + // (X/Open SQL CLI, March 1995, ISBN: 1-85912-081-4, X/Open Document Number: C451) + // 22018 is for "Invalid character value" and seems to be the best match. + // We have no good XInterface Reference to pass here, so just give NULL + throw SQLException(OUString(errstr, strlen(errstr), ConnectionSettings::encoding), + nullptr, + "22018", + -1, + Any()); + } + strbuf.setLength( len ); + // Previously here RTL_TEXTENCODING_ASCII_US; as we set the PostgreSQL client_encoding to UTF8, + // we get UTF8 here, too. I'm not sure why it worked well before... + buf.append( OStringToOUString( strbuf.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ) ); +} + +static void ibufferQuoteConstant( OUStringBuffer & buf, std::u16string_view value, ConnectionSettings *settings ) +{ + buf.append( "'" ); + bufferEscapeConstant( buf, value, settings ); + buf.append( "'" ); +} + +void bufferQuoteConstant( OUStringBuffer & buf, std::u16string_view value, ConnectionSettings *settings ) +{ + return ibufferQuoteConstant( buf, value, settings ); +} + +void bufferQuoteAnyConstant( OUStringBuffer & buf, const Any &val, ConnectionSettings *settings ) +{ + if( val.hasValue() ) + { + OUString str; + val >>= str; + bufferQuoteConstant( buf, str, settings ); + } + else + buf.append( "NULL" ); +} + +static void ibufferQuoteIdentifier( OUStringBuffer & buf, std::u16string_view toQuote, ConnectionSettings *settings ) +{ + OSL_ENSURE(settings, "pgsql-sdbc: bufferQuoteIdentifier got NULL settings"); + + OString y = iOUStringToOString( toQuote, settings ); + char *cstr = PQescapeIdentifier(settings->pConnection, y.getStr(), y.getLength()); + if ( cstr == nullptr ) + { + char *errstr = PQerrorMessage(settings->pConnection); + // Implementation-defined SQLACCESS error + throw SQLException(OUString(errstr, strlen(errstr), ConnectionSettings::encoding), + nullptr, + "22018", + -1, + Any()); + } + buf.append( OStringToOUString( cstr, RTL_TEXTENCODING_UTF8 ) ); + PQfreemem( cstr ); +} + +void bufferQuoteIdentifier( OUStringBuffer & buf, std::u16string_view toQuote, ConnectionSettings *settings ) +{ + return ibufferQuoteIdentifier(buf, toQuote, settings); +} + + +void bufferQuoteQualifiedIdentifier( + OUStringBuffer & buf, std::u16string_view schema, std::u16string_view table, ConnectionSettings *settings ) +{ + ibufferQuoteIdentifier(buf, schema, settings); + buf.append( "." ); + ibufferQuoteIdentifier(buf, table, settings); +} + +void bufferQuoteQualifiedIdentifier( + OUStringBuffer & buf, + std::u16string_view schema, + std::u16string_view table, + std::u16string_view col, + ConnectionSettings *settings) +{ + ibufferQuoteIdentifier(buf, schema, settings); + buf.append( "." ); + ibufferQuoteIdentifier(buf, table, settings); + buf.append( "." ); + ibufferQuoteIdentifier(buf, col, settings); +} + + +OUString extractStringProperty( + const Reference< XPropertySet > & descriptor, const OUString &name ) +{ + OUString value; + descriptor->getPropertyValue( name ) >>= value; + return value; +} + +bool extractBoolProperty( + const Reference< XPropertySet > & descriptor, const OUString &name ) +{ + bool value = false; + descriptor->getPropertyValue( name ) >>= value; + return value; +} + +sal_Int32 extractIntProperty( + const Reference< XPropertySet > & descriptor, const OUString &name ) +{ + sal_Int32 ret = 0; + descriptor->getPropertyValue( name ) >>= ret; + return ret; +} + +void disposeObject( const css::uno::Reference< css::uno::XInterface > & r ) +{ + Reference< XComponent > comp( r, UNO_QUERY ); + if( comp.is() ) + comp->dispose(); +} + +void disposeNoThrow( const css::uno::Reference< css::uno::XInterface > & r ) +{ + try + { + disposeObject( r ); + } + catch( SQLException & ) + { + // ignore this + } + +} + +Reference< XConnection > extractConnectionFromStatement( const Reference< XInterface > & stmt ) +{ + Reference< XConnection > ret; + + Reference< css::sdbc::XStatement > owner( stmt, UNO_QUERY ); + if( owner.is() ) + ret = owner->getConnection(); + else + { + Reference< css::sdbc::XPreparedStatement > myowner( stmt, UNO_QUERY ); + if( myowner.is() ) + ret = myowner->getConnection(); + if( ! ret.is() ) + throw SQLException( + "PQSDBC: Couldn't retrieve connection from statement", + Reference< XInterface > () , OUString(), 0 , css::uno::Any() ); + } + + return ret; + +} + +DisposeGuard::DisposeGuard( const Reference< XInterface > & r ) + : d( r ) +{} + +DisposeGuard::~DisposeGuard() +{ + disposeNoThrow( d ); +} + +TransactionGuard::TransactionGuard( const Reference< XStatement > &stmt ) + : m_stmt( stmt ), + m_commited( false ) +{ + m_stmt->executeUpdate( getStatics().BEGIN ); +} + +void TransactionGuard::commit() +{ + m_stmt->executeUpdate( getStatics().COMMIT ); + m_commited = true; +} + +void TransactionGuard::executeUpdate( const OUString & sql ) +{ + m_stmt->executeUpdate( sql ); +} + +TransactionGuard::~TransactionGuard() +{ + try + { + if( ! m_commited ) + m_stmt->executeUpdate( getStatics().ROLLBACK ); + } + catch( css::uno::Exception & ) + { + // ignore, we are within a dtor + } + + disposeNoThrow( m_stmt ); +} + + +bool isWhitespace( sal_Unicode c ) +{ + return ' ' == c || 9 == c || 10 == c || 13 == c; +} + +OUString extractTableFromInsert( const OUString & sql ) +{ + OUString ret; + int i = 0; + while (i < sql.getLength() && isWhitespace(sql[i])) { i++; } + + if( sql.matchIgnoreAsciiCase("insert", i) ) + { + i += 6; + while (i < sql.getLength() && isWhitespace(sql[i])) { i++; } + if( sql.matchIgnoreAsciiCase("into", i) ) + { + i +=4; + while (i < sql.getLength() && isWhitespace(sql[i])) { i++; } + int start = i; + bool quote = (sql[i] == '"'); + for( i++ ; i < sql.getLength() ; i ++ ) + { + if( quote && sql[i] == '"' ) + { + while (i < sql.getLength() && isWhitespace(sql[i])) { i++; } + if( '.' == sql[i] ) + { + while (i < sql.getLength() && isWhitespace(sql[i])) { i++; } + if( '"' == sql[i] ) + { + // the second part of the table name does not use quotes + // parse on + quote = false; + } + } + else + { + // end quoted name, ok + break; + } + } + else + { + if( isWhitespace( sql[i] ) ) + { + // found the end of an unquoted name + break; + } + } + } + ret = o3tl::trim(sql.subView(start, i - start )); +// printf( "pq_statement: parsed table name %s from insert\n" , +// OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US).getStr() ); + } + } + return ret; +} + + +static bool isOperator( char c ) +{ + bool ret; + switch(c) + { + case '+': + case '-': + case '*': + case '/': + case '<': + case '>': + case '=': + case '~': + case '!': + case '@': + case '#': + case '%': + case '^': + case '&': + case '|': + case '`': + case '?': + case '$': + ret = true; + break; + default: + ret = false; + } + return ret; +} + +void splitSQL( const OString & sql, std::vector< OString > &vec ) +{ + int length = sql.getLength(); + + int i = 0; + bool singleQuote = false; + bool doubleQuote = false; + int start = 0; + for( ; i < length ; i ++ ) + { + char c = sql[i]; + if( doubleQuote ) + { + if( '"' == c ) + { + vec.push_back( OString( &sql.getStr()[start], i-start+1 ) ); + start = i + 1; + doubleQuote = false; + } + } + else if( singleQuote ) + { + if( '\'' == c && (i+1) < length && '\'' == sql[i+1] ) + { + // two subsequent single quotes within a quoted string + // mean a single quote within the string + i ++; + } + else if( '\'' == c ) + { + vec.push_back( OString( &sql.getStr()[start], i - start +1 ) ); + start = i + 1; // leave single quotes ! + singleQuote = false; + } + } + else + { + if( '"' == c ) + { + vec.push_back( OString( &sql.getStr()[start], i - start ) ); + doubleQuote = true; + start = i; + } + else if( '\'' == c ) + { + vec.push_back( OString( &sql.getStr()[start], i - start ) ); + singleQuote = true; + start = i; + } + } + } + if( start < i ) + vec.push_back( OString( &sql.getStr()[start] , i - start ) ); + +// for( i = 0 ; i < vec.size() ; i ++ ) +// printf( "%s!" , vec[i].getStr() ); +// printf( "\n" ); + +} + +void tokenizeSQL( const OString & sql, std::vector< OString > &vec ) +{ + int length = sql.getLength(); + + int i = 0; + bool singleQuote = false; + bool doubleQuote = false; + int start = 0; + for( ; i < length ; i ++ ) + { + char c = sql[i]; + if( doubleQuote ) + { + if( '"' == c ) + { + vec.push_back( OString( &sql.getStr()[start], i-start ) ); + start = i + 1; + doubleQuote = false; + } + } + else if( singleQuote ) + { + if( '\'' == c ) + { + vec.push_back( OString( &sql.getStr()[start], i - start +1 ) ); + start = i + 1; // leave single quotes ! + singleQuote = false; + } + } + else + { + if( '"' == c ) + { + doubleQuote = true; + start = i +1; // skip double quotes ! + } + else if( '\'' == c ) + { + singleQuote = true; + start = i; // leave single quotes + } + else if( isWhitespace( c ) ) + { + if( i == start ) + start ++; // skip additional whitespace + else + { + vec.push_back( OString( &sql.getStr()[start], i - start ) ); + start = i +1; + } + } + else if( ',' == c || isOperator( c ) || '(' == c || ')' == c ) + { + if( i - start ) + vec.push_back( OString( &sql.getStr()[start], i - start ) ); + vec.push_back( OString( &sql.getStr()[i], 1 ) ); + start = i + 1; + } + else if( '.' == c ) + { + if( ( i > start && sql[start] >= '0' && sql[start] <= '9' ) || + ( i == start && i > 1 && isWhitespace( sql[i-1] ) ) ) + { + // ignore, is a literal + } + else + { + if( i - start ) + vec.push_back( OString( &sql.getStr()[start], i - start ) ); + vec.push_back( OString( "." ) ); + start = i + 1; + } + } + } + } + if( start < i ) + vec.push_back( OString( &sql.getStr()[start] , i - start ) ); + +// for( i = 0 ; i < vec.size() ; i ++ ) +// printf( "%s!" , vec[i].getStr() ); +// printf( "\n" ); +} + + +void splitConcatenatedIdentifier( std::u16string_view source, OUString *first, OUString *second) +{ + std::vector< OString > vec; + tokenizeSQL( rtl::OUStringToOString( source, RTL_TEXTENCODING_UTF8 ), vec ); + switch (vec.size()) + { + case 1: + first->clear(); + *second = OStringToOUString( vec[0], RTL_TEXTENCODING_UTF8 ); + break; + case 3: + *first = OStringToOUString( vec[0], RTL_TEXTENCODING_UTF8 ); + *second = OStringToOUString( vec[2], RTL_TEXTENCODING_UTF8 ); + break; + default: + SAL_WARN("connectivity.postgresql", + "pq_tools::splitConcatenatedIdentifier unexpected number of tokens in identifier: " + << vec.size()); + } +} + +OUString array2String( const css::uno::Sequence< Any > &seq ) +{ + OUStringBuffer buf(128); + int len = seq.getLength(); + buf.append( "{" ); + for( int i = 0 ; i < len ; i ++ ) + { + OUString element; + seq[i] >>= element; + + if( i > 0 ) + buf.append( "," ); + int strLength = element.getLength(); + buf.append( "\"" ); + for( int j = 0 ; j < strLength ; j ++ ) + { + sal_Unicode c = element[j]; + if( c == '\\' || c == '"' || c == '{' || c == '}' ) + { + buf.append( "\\" ); + } + buf.append( c ); + } + buf.append( "\"" ); + } + buf.append( "}" ); + return buf.makeStringAndClear(); +} + + +std::vector< Any > parseArray( const OUString & str ) +{ + int len = str.getLength(); + bool doubleQuote = false; + int brackets = 0; + int i = 0; + + OUStringBuffer current; + std::vector<Any> elements; + bool doubleQuotedValue = false; + while( i < len ) + { + sal_Unicode c = str[i]; + sal_Unicode cnext = str[i+1]; + if( doubleQuote ) + { + if( '\\' == c ) + { + i ++; + current.append( cnext ); + } + else if( '"' == c ) + { + doubleQuote = false; + doubleQuotedValue = true; // signal, that there was an empty element + } + else + { + current.append( c ); + } + } + else if ( '{' == c ) + { + brackets ++; + } + else if( '}' == c ) + { + brackets --; + if( brackets < 0 ) + { + throw SQLException( + "error during array parsing, didn't expect a } at position " + + OUString::number(i) + " ('" + str + "')", + Reference< XInterface > (), OUString(), 1, Any() ); + } + if( brackets == 0 ) + { + if( !current.isEmpty() || doubleQuotedValue ) + elements.push_back( Any( current.makeStringAndClear() ) ); + } + else + { + current.append( c ); + } + } + else if( '"' == c ) + { +// if( current.getLength() != 0 ) +// { +// OUStringBuffer buf; +// buf.appendAscii( "error during array parsing, didn't expect a \" at position " ); +// buf.append( i ); +// buf.append( " ('" ); +// buf.append( str ); +// buf.append( "')" ); +// throw SDBCException( +// buf.makeStringAndClear(), +// Reference< XInterface > (), 1, Any() ); +// } +// else +// { + doubleQuote = true; +// } + } + else if( ',' == c && brackets == 1) + { + doubleQuotedValue = false; + elements.push_back( Any( current.makeStringAndClear() ) ); + } + else if( isWhitespace( c ) ) + { + // ignore whitespace without quotes + } + else + { + current.append( c ); + } + i++; + } + return elements; +} + +std::vector< sal_Int32 > parseIntArray( const OUString & str ) +{ + sal_Int32 start = 0; + std::vector<sal_Int32> vec; +// printf( ">%s<\n" , OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() ); + for( sal_Int32 i = str.indexOf( ' ' ) ; i != -1 ; i = str.indexOf( ' ', start) ) + { + vec.push_back( rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) ); +// printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 )); + start = i + 1; + } + vec.push_back( rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) ); +// printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 )); + return vec; +} + +void fillAttnum2attnameMap( + Int2StringMap &map, + const Reference< css::sdbc::XConnection > &conn, + const OUString &schema, + const OUString &table ) +{ + Reference< XPreparedStatement > prep = conn->prepareStatement( + "SELECT attname,attnum " + "FROM pg_attribute " + "INNER JOIN pg_class ON attrelid = pg_class.oid " + "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid " + "WHERE relname=? AND nspname=?" ); + + Reference< XParameters > paras( prep, UNO_QUERY_THROW ); + paras->setString( 1 , table ); + paras->setString( 2 , schema ); + Reference< XResultSet > rs = prep->executeQuery(); + + Reference< XRow > xRow( rs , UNO_QUERY_THROW ); + while( rs->next() ) + { + map[ xRow->getInt(2) ] = xRow->getString(1); + } +} + +OString extractSingleTableFromSelect( const std::vector< OString > &vec ) +{ + OString ret; + + if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( + vec[0].pData->buffer, vec[0].pData->length, "select" , 6 , 6 ) ) + { + size_t token = 0; + + for( token = 1; token < vec.size() ; token ++ ) + { + if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( + vec[token].getStr(), vec[token].getLength(), "from" , 4 , 4 ) ) + { + // found from + break; + } + } + token ++; + + if( token < vec.size() && 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( + vec[token].pData->buffer, vec[token].pData->length, "only " , 4 , 4 ) ) + { + token ++; + } + + if( token < vec.size() && vec[token] != "(" ) + { + // it is a table or a function name + OStringBuffer buf(128); + if( '"' == vec[token][0] ) + buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 ); + else + buf.append( vec[token] ); + token ++; + + if( token < vec.size() ) + { + if( vec[token] == "." ) + { + buf.append( vec[token] ); + token ++; + if( token < vec.size() ) + { + if( '"' == vec[token][0] ) + buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 ); + else + buf.append( vec[token] ); + token ++; + } + } + } + + ret = buf.makeStringAndClear(); + // now got my table candidate + + if( token < vec.size() && vec[token] == "(" ) + { + // whoops, it is a function + ret.clear(); + } + else + { + if( token < vec.size() ) + { + if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( + vec[token].pData->buffer, vec[token].pData->length, "as" , 2, 2 ) ) + { + token += 2; // skip alias + } + } + + if( token < vec.size() ) + { + if( vec[token] == "," ) + { + // whoops, multiple tables are used + ret.clear(); + } + else + { + static const char * forbiddenKeywords[] = + { "join", "natural", "outer", "inner", "left", "right", "full" , nullptr }; + for( int i = 0 ; forbiddenKeywords[i] ; i ++ ) + { + size_t nKeywordLen = strlen(forbiddenKeywords[i]); + if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( + vec[token].pData->buffer, vec[token].pData->length, + forbiddenKeywords[i], nKeywordLen, + nKeywordLen ) ) + { + // whoops, it is a join + ret.clear(); + } + } + } + } + } + } + } + return ret; + +} + +OUString getColExprForDefaultSettingVal(ConnectionSettings const *settings) +{ + return (PQserverVersion( settings->pConnection ) < 80000)? + OUString("pg_attrdef.adsrc"): + OUString("pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid, true)"); +} + +css::uno::Sequence< sal_Int32 > string2intarray( const OUString & str ) +{ + css::uno::Sequence< sal_Int32 > ret; + const sal_Int32 strlen = str.getLength(); + if( str.getLength() > 1 ) + { + sal_Int32 start = 0; + sal_uInt32 c; + for (;;) + { + c = str.iterateCodePoints(&start); + if (!iswspace(c)) + break; + if ( start == strlen) + return ret; + } + if ( c != L'{' ) + return ret; + for (;;) + { + c = str.iterateCodePoints(&start); + if ( !iswspace(c) ) + break; + if ( start == strlen) + return ret; + } + if ( c == L'}' ) + return ret; + + std::vector< sal_Int32 > vec; + do + { + OUStringBuffer digits; + do + { + if(!iswspace(c)) + break; + if ( start == strlen) + return ret; + c=str.iterateCodePoints(&start); + } while ( c ); + do + { + if (!iswdigit(c)) + break; + if ( start == strlen) + return ret; + digits.append(OUString(&c, 1)); + c = str.iterateCodePoints(&start); + } while ( c ); + vec.push_back( digits.makeStringAndClear().toInt32() ); + do + { + if(!iswspace(c)) + break; + if ( start == strlen) + return ret; + c = str.iterateCodePoints(&start); + } while ( c ); + if ( c == L'}' ) + break; + if ( str.iterateCodePoints(&start) != L',' ) + return ret; + if ( start == strlen) + return ret; + } while( true ); + // vec is guaranteed non-empty + assert(vec.size() > 0); + ret = css::uno::Sequence< sal_Int32 > ( vec.data() , vec.size() ); + } + return ret; +} + + +Sequence< OUString > convertMappedIntArray2StringArray( + const Int2StringMap &map, const Sequence< sal_Int32 > &intArray ) +{ + Sequence< OUString > ret( intArray.getLength() ); + auto retRange = asNonConstRange(ret); + for( int i = 0; i < intArray.getLength() ; i ++ ) + { + Int2StringMap::const_iterator ii = map.find( intArray[i] ); + if( ii != map.end() ) + retRange[i] = ii->second; + } + return ret; +} + + +OUString sqltype2string( const Reference< XPropertySet > & desc ) +{ + OUStringBuffer typeName; + typeName.append( extractStringProperty( desc, getStatics().TYPE_NAME ) ); + sal_Int32 precision = extractIntProperty( desc, getStatics().PRECISION ); + + if( precision ) + { + switch( extractIntProperty( desc, getStatics().TYPE ) ) + { + case css::sdbc::DataType::VARBINARY: + case css::sdbc::DataType::VARCHAR: + case css::sdbc::DataType::CHAR: + { + typeName.append( "(" ); + typeName.append( precision ); + typeName.append( ")" ); + break; + } + case css::sdbc::DataType::DECIMAL: + case css::sdbc::DataType::NUMERIC: + { + typeName.append( "(" ); + typeName.append( precision ); + typeName.append( "," ); + typeName.append( extractIntProperty( desc, getStatics().SCALE ) ); + typeName.append( ")" ); + break; + } + default: + ((void)0); + } + } + return typeName.makeStringAndClear(); +} + + +static void keyType2String( OUStringBuffer & buf, sal_Int32 keyType ) +{ + if( css::sdbc::KeyRule::CASCADE == keyType ) + { + buf.append( "CASCADE " ); + } + else if( css::sdbc::KeyRule::RESTRICT == keyType ) + { + buf.append( "RESTRICT " ); + } + else if( css::sdbc::KeyRule::SET_DEFAULT == keyType ) + { + buf.append( "SET DEFAULT " ); + } + else if( css::sdbc::KeyRule::SET_NULL == keyType ) + { + buf.append( "SET NULL " ); + } + else //if( css::sdbc::KeyRule::NO_ACTION == keyType ) + { + buf.append( "NO ACTION " ); + } +} + +void bufferKey2TableConstraint( + OUStringBuffer &buf, const Reference< XPropertySet > &key, ConnectionSettings *settings ) +{ + Statics &st = getStatics(); + sal_Int32 type = extractIntProperty( key, st.TYPE ); + OUString referencedTable = extractStringProperty( key, st.REFERENCED_TABLE ); + sal_Int32 updateRule = extractIntProperty( key, st.UPDATE_RULE ); + sal_Int32 deleteRule = extractIntProperty( key, st.DELETE_RULE ); + bool foreign = false; + if( type == css::sdbcx::KeyType::UNIQUE ) + { + buf.append( "UNIQUE( " ); + } + else if( type == css::sdbcx::KeyType::PRIMARY ) + { + buf.append( "PRIMARY KEY( " ); + } + else if( type == css::sdbcx::KeyType::FOREIGN ) + { + foreign = true; + buf.append( "FOREIGN KEY( " ); + } + + Reference< XColumnsSupplier > columns( key, UNO_QUERY ); + if( columns.is() ) + { + Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY ); + if( colEnumAccess.is() ) + { + Reference< XEnumeration > colEnum = colEnumAccess->createEnumeration(); + bool first = true; + while(colEnum.is() && colEnum->hasMoreElements() ) + { + if( first ) + { + first = false; + } + else + { + buf.append( ", " ); + } + Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY_THROW ); + bufferQuoteIdentifier(buf, extractStringProperty( keyColumn, st.NAME ), settings ); + } + } + } + buf.append( ") " ); + + if( !foreign ) + return; + + buf.append( "REFERENCES " ); + OUString schema; + OUString tableName; + splitConcatenatedIdentifier( referencedTable, &schema, &tableName ); + bufferQuoteQualifiedIdentifier(buf , schema, tableName, settings ); + if(columns.is() ) + { + Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY); + if( colEnumAccess.is() ) + { + buf.append( " (" ); + Reference< XEnumeration > colEnum(colEnumAccess->createEnumeration()); + bool first = true; + while(colEnum.is() && colEnum->hasMoreElements() ) + { + if( first ) + { + first = false; + } + else + { + buf.append( ", " ); + } + Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY_THROW ); + bufferQuoteIdentifier( + buf, extractStringProperty( keyColumn, st.RELATED_COLUMN ), settings ); + } + buf.append( ") " ); + } + } + + buf.append( "ON DELETE " ); + keyType2String( buf, deleteRule ); + buf.append( " ON UPDATE " ); + keyType2String( buf, updateRule ); + +} + +void extractNameValuePairsFromInsert( String2StringMap & map, const OString & lastQuery ) +{ + std::vector< OString > vec; + tokenizeSQL( lastQuery, vec ); + + int nSize = vec.size(); +// printf( "1 %d\n", nSize ); + if( !(nSize > 6 && + vec[0].equalsIgnoreAsciiCase( "insert" ) && + vec[1].equalsIgnoreAsciiCase( "into" )) ) + return; + + int n = 2; + +// printf( "1a\n" ); + // skip table name + if( vec[n+1].equalsIgnoreAsciiCase( "." ) ) + { + n +=2; + } + + n ++; + if( !vec[n].equalsIgnoreAsciiCase( "(" ) ) + return; + + std::vector< OString> names; +// printf( "2\n" ); + // extract names + n++; + while( nSize > n && ! vec[n].equalsIgnoreAsciiCase( ")" ) ) + { + names.push_back( vec[n] ); + if( nSize > n+1 && vec[n+1].equalsIgnoreAsciiCase( "," ) ) + { + n ++; + } + n++; + } + n++; + + // now read the values + if( !(nSize > n +1 && vec[n].equalsIgnoreAsciiCase("VALUES") && + vec[n+1].equalsIgnoreAsciiCase( "(" )) ) + return; + + n +=2; +// printf( "3\n" ); + for (auto& name : names) + { + if (n >= nSize) + break; + + map[name] = vec[n]; + if( nSize > n+1 && vec[n+1].equalsIgnoreAsciiCase(",") ) + { + n ++; + } + n++; + } +} + +OUString querySingleValue( + const css::uno::Reference< css::sdbc::XConnection > &connection, + const OUString &query ) +{ + OUString ret; + Reference< XStatement > stmt = connection->createStatement(); + DisposeGuard guard( stmt ); + Reference< XResultSet > rs = stmt->executeQuery( query ); + Reference< XRow > xRow( rs, UNO_QUERY ); + if( rs->next() ) + ret = xRow->getString( 1 ); + return ret; +} + + +// copied from connectivity/source/dbtools, can't use the function directly +bool implSetObject( const Reference< XParameters >& _rxParameters, + const sal_Int32 _nColumnIndex, const Any& _rValue) +{ + bool bSuccessfullyReRouted = true; + switch (_rValue.getValueTypeClass()) + { + case css::uno::TypeClass_HYPER: + { + _rxParameters->setLong( _nColumnIndex, sal_Int64(0) ); + } + break; + + case css::uno::TypeClass_VOID: + _rxParameters->setNull(_nColumnIndex,css::sdbc::DataType::VARCHAR); + break; + + case css::uno::TypeClass_STRING: + _rxParameters->setString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue)); + break; + + case css::uno::TypeClass_BOOLEAN: + _rxParameters->setBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue)); + break; + + case css::uno::TypeClass_BYTE: + _rxParameters->setByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue)); + break; + + case css::uno::TypeClass_UNSIGNED_SHORT: + case css::uno::TypeClass_SHORT: + _rxParameters->setShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue)); + break; + + case css::uno::TypeClass_CHAR: + _rxParameters->setString(_nColumnIndex, OUString(*o3tl::forceAccess<sal_Unicode>(_rValue))); + break; + + case css::uno::TypeClass_UNSIGNED_LONG: + case css::uno::TypeClass_LONG: + _rxParameters->setInt(_nColumnIndex, *o3tl::forceAccess<sal_Int32>(_rValue)); + break; + + case css::uno::TypeClass_FLOAT: + _rxParameters->setFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue)); + break; + + case css::uno::TypeClass_DOUBLE: + _rxParameters->setDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue)); + break; + + case css::uno::TypeClass_SEQUENCE: + if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue)) + { + _rxParameters->setBytes(_nColumnIndex, *s); + } + else + bSuccessfullyReRouted = false; + break; + case css::uno::TypeClass_STRUCT: + if (auto s1 = o3tl::tryAccess<css::util::DateTime>(_rValue)) + _rxParameters->setTimestamp(_nColumnIndex, *s1); + else if (auto s2 = o3tl::tryAccess<css::util::Date>(_rValue)) + _rxParameters->setDate(_nColumnIndex, *s2); + else if (auto s3 = o3tl::tryAccess<css::util::Time>(_rValue)) + _rxParameters->setTime(_nColumnIndex, *s3); + else + bSuccessfullyReRouted = false; + break; + + case css::uno::TypeClass_INTERFACE: + { + Reference< css::io::XInputStream > xStream; + if (_rValue >>= xStream) + { + _rValue >>= xStream; + _rxParameters->setBinaryStream(_nColumnIndex, xStream, xStream->available()); + break; + } + [[fallthrough]]; + } + default: + bSuccessfullyReRouted = false; + + } + + return bSuccessfullyReRouted; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_tools.hxx b/connectivity/source/drivers/postgresql/pq_tools.hxx new file mode 100644 index 000000000..1f9356ed4 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_tools.hxx @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/DateTime.hpp> + +#include <rtl/ustrbuf.hxx> +#include <rtl/string.hxx> + +#include "pq_connection.hxx" + +#include <string_view> +#include <vector> + +namespace +{ +// helper to create one-time deleters +template <auto fn> +using deleter_from_fn = std::integral_constant<decltype(fn), fn>; + +} + +namespace pq_sdbc_driver +{ +bool isWhitespace( sal_Unicode c ); + +OUString concatQualified( std::u16string_view a, std::u16string_view b); + +OString OUStringToOString( std::u16string_view str, ConnectionSettings const *settings); + +void bufferQuoteConstant( OUStringBuffer & buf, std::u16string_view str, ConnectionSettings *settings ); +void bufferQuoteAnyConstant( OUStringBuffer & buf, const css::uno::Any &val, ConnectionSettings *settings ); + +void bufferEscapeConstant( OUStringBuffer & buf, std::u16string_view str, ConnectionSettings *settings ); + +OUString sqltype2string( + const css::uno::Reference< css::beans::XPropertySet > & column ); + + +void bufferQuoteQualifiedIdentifier( + OUStringBuffer & buf, std::u16string_view schema, std::u16string_view name, ConnectionSettings *settings ); + +void bufferQuoteQualifiedIdentifier( + OUStringBuffer & buf, + std::u16string_view schema, + std::u16string_view name, + std::u16string_view col, + ConnectionSettings *settings ); + +void bufferQuoteIdentifier( OUStringBuffer & buf, std::u16string_view toQuote, ConnectionSettings *settings ); +void bufferKey2TableConstraint( + OUStringBuffer &buf, + const css::uno::Reference< css::beans::XPropertySet > &key, + ConnectionSettings *settings ); + +OUString extractStringProperty( + const css::uno::Reference< css::beans::XPropertySet > & descriptor, + const OUString &name ); + +sal_Int32 extractIntProperty( + const css::uno::Reference< css::beans::XPropertySet > & descriptor, + const OUString &name ); + +bool extractBoolProperty( + const css::uno::Reference< css::beans::XPropertySet > & descriptor, + const OUString &name ); + +void disposeNoThrow( const css::uno::Reference< css::uno::XInterface > & r ); +void disposeObject( const css::uno::Reference< css::uno::XInterface > & r ); + +OUString extractTableFromInsert( const OUString & sql ); +OString extractSingleTableFromSelect( const std::vector< OString > &vec ); + +OUString getColExprForDefaultSettingVal(ConnectionSettings const *settings); + +void tokenizeSQL( const OString & sql, std::vector< OString > &vec ); +void splitSQL( const OString & sql, std::vector< OString > &vec ); +std::vector< sal_Int32 > parseIntArray( const OUString & str ); +/// @throws css::sdbc::SQLException +std::vector< css::uno::Any > parseArray( const OUString & str ); + +OUString array2String( const css::uno::Sequence< css::uno::Any > &seq ); + +css::uno::Reference< css::sdbc::XConnection > extractConnectionFromStatement( + const css::uno::Reference< css::uno::XInterface > & stmt ); + +void splitConcatenatedIdentifier( std::u16string_view source, OUString *first, OUString *second); + + +void fillAttnum2attnameMap( + Int2StringMap &map, + const css::uno::Reference< css::sdbc::XConnection > &conn, + const OUString &schema, + const OUString &table ); + +css::uno::Sequence< sal_Int32 > string2intarray( const OUString & str ); + +css::uno::Sequence< OUString > convertMappedIntArray2StringArray( + const Int2StringMap &map, const css::uno::Sequence< sal_Int32> &source ); + +typedef std::unordered_map< OString, OString > String2StringMap; + +OUString querySingleValue( + const css::uno::Reference< css::sdbc::XConnection > &connection, + const OUString &query ); + +void extractNameValuePairsFromInsert( String2StringMap & map, const OString & lastQuery ); +sal_Int32 typeNameToDataType( const OUString &typeName, std::u16string_view typtype ); + +// copied from connectivity/source/dbtools, can't use the function directly +bool implSetObject( const css::uno::Reference< css::sdbc::XParameters >& _rxParameters, + const sal_Int32 _nColumnIndex, const css::uno::Any& _rValue); + +class DisposeGuard +{ + css::uno::Reference< css::uno::XInterface > d; +public: + explicit DisposeGuard(const css::uno::Reference< css::uno::XInterface > & r ); + ~DisposeGuard(); + +}; + +class TransactionGuard +{ + css::uno::Reference< css::sdbc::XStatement > m_stmt; + bool m_commited; +public: + /// takes over ownership of given statement + explicit TransactionGuard( const css::uno::Reference< css::sdbc::XStatement > &stmt ); + ~TransactionGuard( ); + + void commit(); + void executeUpdate( const OUString & sql ); +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_updateableresultset.cxx b/connectivity/source/drivers/postgresql/pq_updateableresultset.cxx new file mode 100644 index 000000000..5c1b23e82 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_updateableresultset.cxx @@ -0,0 +1,550 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 200? by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> + +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XGeneratedResultSet.hpp> + +#include "pq_updateableresultset.hxx" +#include "pq_resultsetmetadata.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +#include <string.h> + +#include <connectivity/dbconversion.hxx> + +using osl::MutexGuard; + + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::sdbc::XGeneratedResultSet; +using com::sun::star::sdbc::XResultSetMetaDataSupplier; +using com::sun::star::sdbc::SQLException; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XCloseable; +using com::sun::star::sdbc::XColumnLocate; +using com::sun::star::sdbc::XResultSetUpdate; +using com::sun::star::sdbc::XRowUpdate; +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XStatement; + +using com::sun::star::beans::XFastPropertySet; +using com::sun::star::beans::XPropertySet; +using com::sun::star::beans::XMultiPropertySet; + +using namespace dbtools; + +namespace pq_sdbc_driver +{ + + +css::uno::Reference< css::sdbc::XCloseable > UpdateableResultSet::createFromPGResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + ConnectionSettings **ppSettings, + PGresult *result, + const OUString &schema, + const OUString &table, + std::vector< OUString > && primaryKey ) +{ + sal_Int32 columnCount = PQnfields( result ); + sal_Int32 rowCount = PQntuples( result ); + std::vector< OUString > columnNames( columnCount ); + for( int i = 0 ; i < columnCount ; i ++ ) + { + char * name = PQfname( result, i ); + columnNames[i] = OUString( name, strlen(name), ConnectionSettings::encoding ); + } + std::vector< std::vector< Any > > data( rowCount ); + + // copy all the data into unicode strings (also binaries, as we yet + // don't know, what a binary is and what not!) + for( int row = 0 ; row < rowCount ; row ++ ) + { + std::vector< Any > aRow( columnCount ); + for( int col = 0 ; col < columnCount ; col ++ ) + { + if( ! PQgetisnull( result, row, col ) ) + { + char * val = PQgetvalue( result, row, col ); + + aRow[col] <<= + OUString( val, strlen( val ), ConnectionSettings::encoding ); + } + } + data[row] = aRow; + } + + rtl::Reference<UpdateableResultSet> pRS = new UpdateableResultSet( + mutex, owner, std::move(columnNames), std::move(data), ppSettings, schema, table, std::move(primaryKey) ); + + pRS->m_meta = new ResultSetMetaData( mutex, pRS,nullptr, ppSettings, result, schema, table ); + + PQclear( result ); // we don't need it anymore + + return pRS; +} + +css::uno::Any UpdateableResultSet::queryInterface( + const css::uno::Type & reqType ) +{ + Any ret = SequenceResultSet::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< XResultSetUpdate * > ( this ), + static_cast< XRowUpdate * > ( this ) ); + return ret; +} + + +css::uno::Sequence< css::uno::Type > UpdateableResultSet::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<XResultSetUpdate>::get(), + cppu::UnoType<XRowUpdate>::get(), + SequenceResultSet::getTypes()); + + return collection.getTypes(); + +} + +css::uno::Sequence< sal_Int8> UpdateableResultSet::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +OUString UpdateableResultSet::buildWhereClause() +{ + OUString ret; + if( !m_primaryKey.empty() ) + { + OUStringBuffer buf( 128 ); + buf.append( " WHERE " ); + for( size_t i = 0 ; i < m_primaryKey.size() ; i ++ ) + { + if( i > 0 ) + buf.append( " AND " ); + sal_Int32 index = findColumn( m_primaryKey[i] ); + bufferQuoteIdentifier( buf, m_primaryKey[i], *m_ppSettings ); + buf.append( " = " ); + bufferQuoteConstant( buf, getString( index ), *m_ppSettings ); + } + ret = buf.makeStringAndClear(); + } + return ret; +} + + +void UpdateableResultSet::insertRow( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + SAL_INFO("connectivity.postgresql", "UpdateableResultSet::insertRow() got called"); + + if( ! m_insertRow ) + throw SQLException( + "pq_resultset.insertRow: moveToInsertRow has not been called !", + *this, OUString(), 1, Any() ); + + OUStringBuffer buf( 128 ); + buf.append( "INSERT INTO " ); + bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings ); + buf.append( " ( " ); + + int columns = 0; + for( UpdateableFieldVector::size_type i = 0 ; i < m_updateableField.size() ; i++ ) + { + if( m_updateableField[i].isTouched ) + { + if( columns > 0 ) + buf.append( ", " ); + columns ++; + bufferQuoteIdentifier( buf, m_columnNames[i], *m_ppSettings); + } + } + buf.append( " ) VALUES ( " ); + + columns = 0; + for(const UpdateableField & i : m_updateableField) + { + if( i.isTouched ) + { + if( columns > 0 ) + buf.append( " , " ); + columns ++; + bufferQuoteAnyConstant( buf, i.value, *m_ppSettings ); + +// OUString val; +// m_updateableField[i].value >>= val; +// buf.append( val ); +// OStringToOUString(val, (*m_ppSettings)->encoding ) ); + } + } + + buf.append( " )" ); + + Reference< XStatement > stmt = + extractConnectionFromStatement(m_owner)->createStatement(); + DisposeGuard dispGuard( stmt ); + stmt->executeUpdate( buf.makeStringAndClear() ); + + // reflect the changes ! + m_rowCount ++; + m_data.resize( m_rowCount ); + m_data[m_rowCount-1] = std::vector< Any > ( m_fieldCount ); + Reference< XGeneratedResultSet > result( stmt, UNO_QUERY ); + if( result.is() ) + { + Reference< XResultSet > rs = result->getGeneratedValues(); + if( rs.is() && rs->next() ) + { + Reference< XColumnLocate > columnLocate( rs, UNO_QUERY ); + Reference< XRow> xRow ( rs, UNO_QUERY ); + for( int i = 0 ; i < m_fieldCount ; i++ ) + { + int field = columnLocate->findColumn( m_columnNames[i] ); + if( field >= 1 ) + { + m_data[m_rowCount-1][i] <<= xRow->getString( field ); +// printf( "adding %s %s\n" , +// OUStringToOString( m_columnNames[i], RTL_TEXTENCODING_ASCII_US).getStr(), +// OUStringToOString( xRow->getString( field ), RTL_TEXTENCODING_ASCII_US).getStr() ); + + } + } + } + else + { + // do the best we can ( DEFAULT and AUTO increment values fail ! ) + for( int i = 0 ; i < m_fieldCount ; i ++ ) + { + if( m_updateableField[i].isTouched ) + m_data[m_rowCount-1][i] = m_updateableField[i].value; + } + } + } + + // cleanup + m_updateableField = UpdateableFieldVector(); +} + +void UpdateableResultSet::updateRow( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + SAL_INFO("connectivity.postgresql", "UpdateableResultSet::updateRow() got called"); + + if( m_insertRow ) + throw SQLException( + "pq_resultset.updateRow: moveToCurrentRow has not been called !", + *this, OUString(), 1, Any() ); + + OUStringBuffer buf( 128 ); + buf.append( "UPDATE " ); + bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings ); + buf.append( "SET " ); + + int columns = 0; + for( UpdateableFieldVector::size_type i = 0; i < m_updateableField.size() ; i ++ ) + { + if( m_updateableField[i].isTouched ) + { + if( columns > 0 ) + buf.append( ", " ); + columns ++; + + buf.append( m_columnNames[i] ); + buf.append( " = " ); + bufferQuoteAnyConstant( buf, m_updateableField[i].value, *m_ppSettings ); +// OUString val; +// m_updateableField[i].value >>= val; +// bufferQuoteConstant( buf, val ): +// buf.append( val ); + } + } + buf.append( buildWhereClause() ); + + Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement(); + DisposeGuard dispGuard( stmt ); + stmt->executeUpdate( buf.makeStringAndClear() ); + + // reflect the changes ! + for( int i = 0 ; i < m_fieldCount ; i ++ ) + { + if( m_updateableField[i].isTouched ) + m_data[m_row][i] = m_updateableField[i].value; + } + m_updateableField = UpdateableFieldVector(); +} + +void UpdateableResultSet::deleteRow( ) +{ + SAL_INFO("connectivity.postgresql", "UpdateableResultSet::deleteRow() got called"); + + if( m_insertRow ) + throw SQLException( + "pq_resultset.deleteRow: deleteRow cannot be called when on insert row !", + *this, OUString(), 1, Any() ); + + if( m_row < 0 || m_row >= m_rowCount ) + { + throw SQLException( + "deleteRow cannot be called on invalid row (" + + OUString::number(m_row) + ")", + *this, OUString(), 0, Any() ); + } + + Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement(); + DisposeGuard dispGuard( stmt ); + OUStringBuffer buf( 128 ); + buf.append( "DELETE FROM " ); + bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings ); + buf.append( " " ); + buf.append( buildWhereClause() ); + + stmt->executeUpdate( buf.makeStringAndClear() ); + + // reflect the changes ! + for( int i = m_row + 1; i < m_row ; i ++ ) + { + m_data[i-1] = m_data[i]; + } + m_rowCount --; + m_data.resize( m_rowCount ); + } + +void UpdateableResultSet::cancelRowUpdates( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + m_updateableField = UpdateableFieldVector(); +} + +void UpdateableResultSet::moveToInsertRow( ) +{ + m_insertRow = true; +} + +void UpdateableResultSet::moveToCurrentRow( ) +{ + m_insertRow = false; +} + +void UpdateableResultSet::checkUpdate( sal_Int32 columnIndex) +{ + checkColumnIndex( columnIndex ); + if( m_updateableField.empty() ) + m_updateableField = UpdateableFieldVector( m_fieldCount ); + m_updateableField[columnIndex-1].isTouched = true; +} + +void UpdateableResultSet::updateNull( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + m_updateableField[columnIndex-1].value = Any(); +} + +void UpdateableResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + + Statics &st = getStatics(); + m_updateableField[columnIndex-1].value <<= ( x ? st.TRUE : st.FALSE ); + +} + +void UpdateableResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x ) +{ + updateInt(columnIndex,x); +} + +void UpdateableResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x ) +{ + updateInt( columnIndex, x ); +} + +void UpdateableResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x ) +{ + updateLong( columnIndex, x ); +// MutexGuard guard( m_xMutex->GetMutex() ); +// checkClosed(); +// checkUpdate( columnIndex ); + +// m_updateableField[columnIndex-1].value <<= OUString::valueOf( x ); + +} + +void UpdateableResultSet::updateLong( sal_Int32 columnIndex, sal_Int64 x ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + +// OStringBuffer buf( 20 ); +// buf.append( "'" ); +// buf.append( (sal_Int64) x ); +// buf.append( "'" ); + m_updateableField[columnIndex-1].value <<= OUString::number( x ); +} + +void UpdateableResultSet::updateFloat( sal_Int32 columnIndex, float x ) +{ + + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + + m_updateableField[columnIndex-1].value <<= OUString::number( x ); +} + +void UpdateableResultSet::updateDouble( sal_Int32 columnIndex, double x ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + + m_updateableField[columnIndex-1].value <<= OUString::number( x ); +} + +void UpdateableResultSet::updateString( sal_Int32 columnIndex, const OUString& x ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + + m_updateableField[columnIndex-1].value <<= x; +} + +void UpdateableResultSet::updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + + size_t len; + unsigned char * escapedString = + PQescapeBytea( reinterpret_cast<unsigned char const *>(x.getConstArray()), x.getLength(), &len); + if( ! escapedString ) + { + throw SQLException( + "pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string", + *this, OUString(), 1, Any() ); + } +// buf.append( (const char *)escapedString, len -1 ); + + m_updateableField[columnIndex-1].value <<= + OUString( reinterpret_cast<char*>(escapedString), len, RTL_TEXTENCODING_ASCII_US ); + PQfreemem( escapedString ); +} + +void UpdateableResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x ) +{ + updateString( columnIndex, DBTypeConversion::toDateString( x ) ); +} + +void UpdateableResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x ) +{ + updateString( columnIndex, DBTypeConversion::toTimeString( x ) ); +} + +void UpdateableResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) +{ + updateString( columnIndex, DBTypeConversion::toDateTimeString( x ) ); +} + +void UpdateableResultSet::updateBinaryStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ ) +{ +} + +void UpdateableResultSet::updateCharacterStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ ) +{ +} + +void UpdateableResultSet::updateObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */ ) +{ +} + +void UpdateableResultSet::updateNumericObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */, sal_Int32 /* scale */ ) +{ +} + + +Sequence< Type > UpdateableResultSet::getStaticTypes( bool updateable ) +{ + if( updateable ) + { + cppu::OTypeCollection collection( + cppu::UnoType<XResultSetUpdate>::get(), + cppu::UnoType<XRowUpdate>::get(), +// cppu::UnoType<css::sdbcx::XRowLocate>::get(), + getStaticTypes( false /* updateable */ ) ); + return collection.getTypes(); + } + else + { + cppu::OTypeCollection collection( + cppu::UnoType<XResultSet>::get(), + cppu::UnoType<XResultSetMetaDataSupplier>::get(), + cppu::UnoType<XRow>::get(), + cppu::UnoType<XColumnLocate>::get(), + cppu::UnoType<XCloseable>::get(), + cppu::UnoType<XPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<css::lang::XComponent>::get(), // OComponentHelper + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<css::uno::XAggregation>::get(), + cppu::UnoType<css::uno::XWeak>::get()); + return collection.getTypes(); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_updateableresultset.hxx b/connectivity/source/drivers/postgresql/pq_updateableresultset.hxx new file mode 100644 index 000000000..1beeadc31 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_updateableresultset.hxx @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 200? by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include "pq_sequenceresultset.hxx" +#include "pq_resultsetmetadata.hxx" + +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> + +namespace pq_sdbc_driver +{ + +struct UpdateableField +{ + UpdateableField( ) + : isTouched(false) + {} + css::uno::Any value; + bool isTouched; +}; + +typedef std::vector< UpdateableField > UpdateableFieldVector; + +class UpdateableResultSet final : + public SequenceResultSet, + public css::sdbc::XResultSetUpdate, + public css::sdbc::XRowUpdate +{ + ConnectionSettings **m_ppSettings; + OUString m_schema; + OUString m_table; + std::vector< OUString > m_primaryKey; + UpdateableFieldVector m_updateableField; + bool m_insertRow; + +private: + UpdateableResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + std::vector< OUString >&& colNames, + std::vector< std::vector< css::uno::Any > >&& data, + ConnectionSettings **ppSettings, + const OUString &schema, + const OUString &table, + std::vector< OUString >&& primaryKey) + : SequenceResultSet( mutex, owner, std::move(colNames), std::move(data), (*ppSettings)->tc ), + m_ppSettings( ppSettings ), + m_schema( schema ), + m_table( table ), + m_primaryKey( std::move(primaryKey) ), + m_insertRow( false ) + { + // LEM TODO: this duplicates code in pq_resultset.cxx, except for different value + // of ResultSetConcurrency. Baaad. + // Why is an updatable ResultSet a sequenceresultset in the first place? + // This seems to imply that the whole data is fetched once and kept in memory. BAAAAD. + // LEM TODO: shouldn't these things be inherited from the statement or something like that? + // Positioned update/delete not supported, so no cursor name + // Fetch direction and size are cursor-specific things, so not used now. + // Fetch size not set + m_props[ BASERESULTSET_FETCH_DIRECTION ] <<= css::sdbc::FetchDirection::UNKNOWN; + // No escape processing for now + m_props[ BASERESULTSET_ESCAPE_PROCESSING ] <<= false; + // Bookmarks not implemented for now + m_props[ BASERESULTSET_IS_BOOKMARKABLE ] <<= false; + m_props[ BASERESULTSET_RESULT_SET_CONCURRENCY ] <<= + css::sdbc::ResultSetConcurrency::UPDATABLE; + m_props[ BASERESULTSET_RESULT_SET_TYPE ] <<= + css::sdbc::ResultSetType::SCROLL_INSENSITIVE; + } + + OUString buildWhereClause(); + void checkUpdate( sal_Int32 column ); + +public: + static css::uno::Reference< css::sdbc::XCloseable > createFromPGResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + ConnectionSettings **ppSettings, + PGresult *result, + const OUString &schema, + const OUString &table, + std::vector< OUString > && primaryKey ); + +public: // XInterface + virtual void SAL_CALL acquire() noexcept override { SequenceResultSet::acquire(); } + virtual void SAL_CALL release() noexcept override { SequenceResultSet::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XResultSetUpdate + virtual void SAL_CALL insertRow( ) override; + virtual void SAL_CALL updateRow( ) override; + virtual void SAL_CALL deleteRow( ) override; + virtual void SAL_CALL cancelRowUpdates( ) override; + virtual void SAL_CALL moveToInsertRow( ) override; + virtual void SAL_CALL moveToCurrentRow( ) override; + +public: // XRowUpdate + virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override; + virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override; + virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override; + virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override; + virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override; + virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override; + virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override; + virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override; + virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override; + virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override; + virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override; + virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override; + +public: + /// @throws css::uno::RuntimeException + static css::uno::Sequence< css::uno::Type > getStaticTypes( bool updateable ); + +}; + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xbase.cxx b/connectivity/source/drivers/postgresql/pq_xbase.cxx new file mode 100644 index 000000000..5dbe6e98b --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xbase.cxx @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/sequence.hxx> + +#include "pq_statics.hxx" +#include "pq_tools.hxx" +#include "pq_xbase.hxx" + +using osl::MutexGuard; + +using com::sun::star::uno::Any; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::RuntimeException; + +using com::sun::star::beans::Property; +using com::sun::star::beans::XPropertySetInfo; +using com::sun::star::beans::XPropertySet; + +namespace pq_sdbc_driver +{ + +ReflectionBase::ReflectionBase( + const OUString &implName, + const css::uno::Sequence< OUString > &supportedServices, + const ::rtl::Reference< comphelper::RefCountedMutex >& refMutex, + const css::uno::Reference< css::sdbc::XConnection > &conn, + ConnectionSettings *pSettings, + cppu::IPropertyArrayHelper & props /* must survive this object !*/ ) + : ReflectionBase_BASE( refMutex->GetMutex() ), + OPropertySetHelper( ReflectionBase_BASE::rBHelper ), + m_implName( implName ), + m_supportedServices( supportedServices ), + m_xMutex( refMutex ), + m_conn( conn ), + m_pSettings( pSettings ), + m_propsDesc( props ), + m_values( props.getProperties().getLength() ) +{} + +cppu::IPropertyArrayHelper & ReflectionBase::getInfoHelper() +{ + return m_propsDesc; +} + +sal_Bool ReflectionBase::convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) +{ + + rOldValue = m_values[nHandle]; + rConvertedValue = rValue; // TODO !!! implement correct conversion ! + m_values[nHandle] = rValue; + return true; +} + +void ReflectionBase::setPropertyValue_NoBroadcast_public( + const OUString & name, const css::uno::Any & value ) +{ + sal_Int32 nHandle = m_propsDesc.getHandleByName( name ); + if( -1 == nHandle ) + { + throw css::uno::RuntimeException( + "Unknown property '" + name + "' in " + m_implName, + *this ); + } + setFastPropertyValue_NoBroadcast( nHandle , value ); +} + +void ReflectionBase::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue ) +{ +// OUString s; +// rValue >>= s; +// printf( "setting value (handle %d):%s\n" , +// nHandle, OUStringToOString(s, RTL_TEXTENCODING_ASCII_US).getStr() ); + m_values[nHandle] = rValue; +} + +void ReflectionBase::getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle ) const +{ + rValue = m_values[nHandle]; +// OUString s; +// rValue >>= s; +// printf( "getting value (handle %d):%s\n" , +// nHandle, OUStringToOString(s, RTL_TEXTENCODING_ASCII_US).getStr() ); + +} + +Reference < css::beans::XPropertySetInfo > ReflectionBase::getPropertySetInfo() +{ + return OPropertySetHelper::createPropertySetInfo( m_propsDesc ); +} + +OUString ReflectionBase::getImplementationName() +{ + return m_implName; +} + +sal_Bool ReflectionBase::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > ReflectionBase::getSupportedServiceNames() +{ + return m_supportedServices; +} + + +Sequence< css::uno::Type > ReflectionBase::getTypes() +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + static Sequence< css::uno::Type > collection( + ::comphelper::concatSequences( + ::cppu::OPropertySetHelper::getTypes(), + ReflectionBase_BASE::getTypes() ) ); + return collection; +} + + +css::uno::Any ReflectionBase::queryInterface( + const css::uno::Type & reqType ) +{ + Any ret = ReflectionBase_BASE::queryInterface( reqType ); + return ret.hasValue() ? ret : OPropertySetHelper::queryInterface( reqType ); + +} + +Sequence< sal_Int8> ReflectionBase::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +void ReflectionBase::copyValuesFrom( const Reference< XPropertySet > & set ) +{ + Reference< XPropertySetInfo > info = set->getPropertySetInfo(); + if( info.is () ) + { + Reference< XPropertySetInfo > myPropInfo = getPropertySetInfo(); + + const Sequence< Property > props = info->getProperties(); + for( Property const & prop : props ) + { + if( myPropInfo->hasPropertyByName( prop.Name ) ) + setPropertyValue_NoBroadcast_public( + prop.Name, set->getPropertyValue( prop.Name ) ); + } + } +} + +OUString ReflectionBase::getName( ) +{ + Statics & st = getStatics(); + if( getInfoHelper().hasPropertyByName( st.SCHEMA_NAME ) ) + return concatQualified( + extractStringProperty( this, getStatics().SCHEMA_NAME ), + extractStringProperty( this, getStatics().NAME ) ); + else + return extractStringProperty( this, getStatics().NAME ); +} + + +void ReflectionBase::setName( const OUString& /* aName */ ) +{ + throw RuntimeException( + "pq_sdbc::ReflectionBase::setName not implemented", + *this ); + //setPropertyValue( getStatics().NAME , makeAny( aName ) ); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xbase.hxx b/connectivity/source/drivers/postgresql/pq_xbase.hxx new file mode 100644 index 000000000..3cd16bc70 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xbase.hxx @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/compbase.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/container/XNamed.hpp> + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ + +typedef ::cppu::WeakComponentImplHelper< css::lang::XServiceInfo, + css::sdbcx::XDataDescriptorFactory, + css::container::XNamed + > ReflectionBase_BASE; + +class ReflectionBase : + public ReflectionBase_BASE, + public cppu::OPropertySetHelper +{ +protected: + const OUString m_implName; + const css::uno::Sequence< OUString > m_supportedServices; + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + css::uno::Reference< css::sdbc::XConnection > m_conn; + ConnectionSettings *m_pSettings; + cppu::IPropertyArrayHelper & m_propsDesc; + std::vector< css::uno::Any > m_values; +public: + ReflectionBase( + const OUString &implName, + const css::uno::Sequence< OUString > &supportedServices, + const ::rtl::Reference< comphelper::RefCountedMutex >& refMutex, + const css::uno::Reference< css::sdbc::XConnection > &conn, + ConnectionSettings *pSettings, + cppu::IPropertyArrayHelper & props /* must survive this object !*/ ); + +public: + void copyValuesFrom( const css::uno::Reference< css::beans::XPropertySet > &set ); + +public: // for initialization purposes only, not exported via an interface ! + void setPropertyValue_NoBroadcast_public( + const OUString & name, const css::uno::Any & value ); + +public: //XInterface + virtual void SAL_CALL acquire() noexcept override { ReflectionBase_BASE::acquire(); } + virtual void SAL_CALL release() noexcept override { ReflectionBase_BASE::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // OPropertySetHelper + virtual cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + using ::cppu::OPropertySetHelper::getFastPropertyValue; + + void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle ) const override; + + // XPropertySet + css::uno::Reference < css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + +public: // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override = 0; + +public: // XNamed + virtual OUString SAL_CALL getName( ) override; + virtual void SAL_CALL setName( const OUString& aName ) override; + +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xcolumn.cxx b/connectivity/source/drivers/postgresql/pq_xcolumn.cxx new file mode 100644 index 000000000..b19d95c3c --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xcolumn.cxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/config.h> + +#include <rtl/ref.hxx> + +#include "pq_statics.hxx" +#include "pq_xcolumn.hxx" + +using com::sun::star::uno::Reference; + +using com::sun::star::beans::XPropertySet; + +namespace pq_sdbc_driver +{ +Column::Column( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.column.implName, + getStatics().refl.column.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.column.pProps ) +{} + +Reference< XPropertySet > Column::createDataDescriptor( ) +{ + rtl::Reference<ColumnDescriptor> pColumn = new ColumnDescriptor( + m_xMutex, m_conn, m_pSettings ); + pColumn->copyValuesFrom( this ); + return Reference< XPropertySet > ( pColumn ); +} + +ColumnDescriptor::ColumnDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.columnDescriptor.implName, + getStatics().refl.columnDescriptor.serviceNames, + refMutex, + connection, + pSettings, + *getStatics().refl.columnDescriptor.pProps ) +{} + +Reference< XPropertySet > ColumnDescriptor::createDataDescriptor( ) +{ + rtl::Reference<ColumnDescriptor> pColumn = new ColumnDescriptor( + m_xMutex, m_conn, m_pSettings ); + pColumn->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pColumn ); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xcolumn.hxx b/connectivity/source/drivers/postgresql/pq_xcolumn.hxx new file mode 100644 index 000000000..794b5851d --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xcolumn.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> + +#include "pq_connection.hxx" +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class Column : public ReflectionBase +{ +public: + Column( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + +class ColumnDescriptor : public ReflectionBase +{ +public: + ColumnDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xcolumns.cxx b/connectivity/source/drivers/postgresql/pq_xcolumns.cxx new file mode 100644 index 000000000..f1d3c0a53 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xcolumns.cxx @@ -0,0 +1,560 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/config.h> + +#include <string_view> + +#include <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> + +#include <cppuhelper/exc_hlp.hxx> + +#include "pq_xcolumns.hxx" +#include "pq_xcolumn.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; +using com::sun::star::uno::RuntimeException; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XDatabaseMetaData; +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ + +static Any isCurrency( std::u16string_view typeName ) +{ + return Any( o3tl::equalsIgnoreAsciiCase(typeName, u"money") ); +} + +// static sal_Bool isAutoIncrement8( const OUString & typeName ) +// { +// return typeName.equalsIgnoreAsciiCase("serial8") || +// typeName.equalsIgnoreAsciiCase("bigserial"); +// } + +static Any isAutoIncrement( std::u16string_view defaultValue ) +{ + bool ret = o3tl::starts_with( defaultValue, u"nextval(" ); +// printf( "%s %d\n", +// OUStringToOString(defaultValue, RTL_TEXTENCODING_ASCII_US).getStr(), +// ret ); +// { +// static const char * const serials[] = +// { +// "serial", "serial4", "serial8", "bigserial", 0 +// }; +// s sal_Bool b = sal_False; +// for( int i = 0; !b && serials[i] ; i ++ ) +// { +// b = b || typeName.equalsIgnoreAsciiCaseAscii( serials[i] ); +// } + return Any ( ret ); +} + +Columns::Columns( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName) + : Container( refMutex, origin, pSettings, "COLUMN" ), + m_schemaName( schemaName ), + m_tableName( tableName ) +{} + +Columns::~Columns() +{} + +OUString columnMetaData2SDBCX( + ReflectionBase *pBase, const css::uno::Reference< css::sdbc::XRow > &xRow ) +{ + Statics & st = getStatics(); + + // 1. TABLE_CAT string => table catalog (may be NULL) + // => not supported + // 2. TABLE_SCHEM string => table schema (may be NULL) + // => pg_namespace.nspname + // 3. TABLE_NAME string => table name + // => pg_class.relname + // 4. COLUMN_NAME string => column name + // => pg_attribute.attname + // 5. DATA_TYPE short => SQL type from java.sql.Types + // => pg_type.typname => sdbc.DataType + // 6. TYPE_NAME string => Data source dependent type name, for a UDT the + // type name is fully qualified + // => pg_type.typname + // 7. COLUMN_SIZE long => column size. For char or date types this is + // the maximum number of characters, for numeric + // or decimal types this is precision. + // => pg_type.typlen ( TODO: What is about variable size ? ) + // 8. BUFFER_LENGTH is not used. + // => not used + // 9. DECIMAL_DIGITS long => the number of fractional digits + // => don't know ! TODO ! + // 10. NUM_PREC_RADIX long => Radix (typically either 10 or 2) + // => TODO ?? + // 11. NULLABLE long => is NULL allowed? + // NO_NULLS - might not allow NULL values + // NULABLE - definitely allows NULL values + // NULLABLE_UNKNOWN - nullability unknown + // => pg_attribute.attnotnull + // 12. REMARKS string => comment describing column (may be NULL ) + // => Don't know, there does not seem to exist something like + // that in postgres + // 13. COLUMN_DEF string => default value (may be NULL) + // => pg_type.typdefault + // 14. SQL_DATA_TYPE long => unused + // => empty + // 15. SQL_DATETIME_SUB long => unused + // => empty + // 16. CHAR_OCTET_LENGTH long => for char types the maximum number of + // bytes in the column + // => pg_type.typlen + // 17. ORDINAL_POSITION int => index of column in table (starting at 1) + // pg_attribute.attnum + // 18. IS_NULLABLE string => "NO" means column definitely does not allow + // NULL values; "YES" means the column might + // allow NULL values. An empty string means + // nobody knows. + // => pg_attribute.attnotnull + + static const int COLUMN_NAME = 4; + static const int DATA_TYPE = 5; + static const int TYPE_NAME = 6; + static const int COLUMN_SIZE = 7; + static const int DECIMAL_DIGITS = 9; + static const int IS_NULLABLE = 11; + static const int DESCRIPTION = 12; + static const int DEFAULT_VALUE = 13; + + OUString name = xRow->getString( COLUMN_NAME ); + OUString typeName = xRow->getString( TYPE_NAME ); + + pBase->setPropertyValue_NoBroadcast_public( + st.NAME, Any( name ) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.TYPE, Any( xRow->getInt( DATA_TYPE ) ) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.TYPE_NAME, Any( typeName ) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.PRECISION, Any( xRow->getInt( COLUMN_SIZE ) ) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.SCALE, Any( xRow->getInt( DECIMAL_DIGITS ) ) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.IS_NULLABLE, Any( xRow->getInt( IS_NULLABLE ) ) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.DEFAULT_VALUE, Any( xRow->getString( DEFAULT_VALUE ) ) ); + +// pBase->setPropertyValue_NoBroadcast_public( +// st.DESCRIPTION, makeAny( xRow->getString( DESCRIPTION ) ) ); + +// if( pBase->getPropertySetInfo()->hasPropertyByName( st.HELP_TEXT ) ) +// pBase->setPropertyValue_NoBroadcast_public( +// st.HELP_TEXT, makeAny( xRow->getString( DESCRIPTION ) ) ); +// else // for key columns, etc. ... + pBase->setPropertyValue_NoBroadcast_public( + st.DESCRIPTION, Any( xRow->getString( DESCRIPTION ) ) ); + + + // maybe a better criterion than the type name can be found in future + pBase->setPropertyValue_NoBroadcast_public( + st.IS_AUTO_INCREMENT, isAutoIncrement(xRow->getString( DEFAULT_VALUE )) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.IS_CURRENCY, isCurrency( typeName)); + return name; +} + + +// class CommentChanger : public cppu::WeakImplHelper< XPropertyChangeListener > +// { +// ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; +// css::uno::Reference< css::sdbc::XConnection > m_connection; +// ConnectionSettings *m_pSettings; +// OUString m_schema; +// OUString m_table; +// OUString m_column; + +// public: +// CommentChanger( +// const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, +// const css::uno::Reference< css::sdbc::XConnection > & connection, +// ConnectionSettings *pSettings, +// const OUString & schema, +// const OUString & table, +// const OUString & column ) : +// m_xMutex( refMutex ), +// m_connection( connection ), +// m_pSettings( pSettings ), +// m_schema ( schema ), +// m_table ( table ), +// m_column ( column ) +// {} + + +// // Methods +// virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) throw (css::uno::RuntimeException) +// { +// osl::MutexGuard guard( m_xMutex->GetMutex() ); +// m_connection.clear(); +// } +// // Methods +// virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) throw (css::uno::RuntimeException) +// { +// osl::MutexGuard guard( m_xMutex->GetMutex() ); +// OUStringBuffer buf( 128 ); +// OUString comment; +// evt.NewValue >>= comment; +// buf.append( "COMMENT ON COLUMN" ); +// bufferQuoteQualifiedIdentifier( buf, m_schema, m_table , m_column ); +// buf.append( "IS " ); +// bufferQuoteConstant( buf, comment,m_pSettings->encoding); + +// printf( "changing comment of column %s to %s\n", +// OUStringToOString( m_column, RTL_TEXTENCODING_ASCII_US ).getStr(), +// OUStringToOString( comment, RTL_TEXTENCODING_ASCII_US ).getStr() ); + +// m_connection->createStatement()->executeUpdate( buf.makeStringAndClear() ); +// } +// }; + +void Columns::refresh() +{ + try + { + SAL_INFO("connectivity.postgresql", "sdbcx.Columns get refreshed for table " << m_schemaName << "." << m_tableName); + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + Statics &st = getStatics(); + Reference< XDatabaseMetaData > meta = m_origin->getMetaData(); + + Reference< XResultSet > rs = + meta->getColumns( Any(), m_schemaName, m_tableName, st.cPERCENT ); + + DisposeGuard disposeIt( rs ); + Reference< XRow > xRow( rs , UNO_QUERY ); + + String2IntMap map; + + m_values.clear(); + int columnIndex = 0; + while( rs->next() ) + { + rtl::Reference<Column> pColumn = + new Column( m_xMutex, m_origin, m_pSettings ); + Reference< css::beans::XPropertySet > prop = pColumn; + + OUString name = columnMetaData2SDBCX( pColumn.get(), xRow ); +// pColumn->addPropertyChangeListener( +// st.HELP_TEXT, +// new CommentChanger( +// m_xMutex, +// m_origin, +// m_pSettings, +// m_schemaName, +// m_tableName, +// name ) ); + + { + m_values.push_back( Any( prop ) ); + map[ name ] = columnIndex; + ++columnIndex; + } + } + m_name2index.swap( map ); + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + nullptr, anyEx ); + } + fire( RefreshedBroadcaster( *this ) ); +} + + +void alterColumnByDescriptor( + std::u16string_view schemaName, + std::u16string_view tableName, + ConnectionSettings *settings, + const Reference< XStatement > &stmt, + const css::uno::Reference< css::beans::XPropertySet > & past, + const css::uno::Reference< css::beans::XPropertySet > & future) +{ + Statics & st = getStatics(); + +// if( past->getPropertyValue( st.TABLE_NAME ) != future->getPropertyValue( st.TABLE_NAME ) || +// past->getPropertyValue( st.SCHEMA_NAME ) != future->getPropertyValue( st.SCHEMA_NAME )) +// { +// OUStringBuffer buf(128); +// buf.append( "Can't move column " ); +// buf.append( extractStringProperty( past, st.COLUMN_NAME ) ); +// buf.append( " from table " ); +// buf.append( extractStringProperty( past, st.TABLE_NAME ) ); +// buf.append( " to table " ); +// buf.append( extractStringProperty( past, st.TABLE_NAME ) ); +// throw SQLException( buf.makeStringAndClear() ); +// } + +// OUString tableName = extractStringProperty( past, st.TABLE_NAME ); +// OUString schemaName = extractStringProperty( past, st.SCHEMA_NAME ); + OUString pastColumnName = extractStringProperty( past, st.NAME ); + OUString futureColumnName = extractStringProperty( future, st.NAME ); + OUString pastTypeName = sqltype2string( past ); + OUString futureTypeName = sqltype2string( future ); + + TransactionGuard transaction( stmt ); + + OUStringBuffer buf( 128 ); + if( ! pastColumnName.getLength()) + { + // create a new column + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schemaName, tableName, settings ); + buf.append( "ADD COLUMN" ); + bufferQuoteIdentifier( buf, futureColumnName, settings ); + buf.append( futureTypeName ); + transaction.executeUpdate( buf.makeStringAndClear() ); + } + else + { + if( pastTypeName != futureTypeName ) + { + throw RuntimeException( + "Can't modify column types, drop the column and create a new one" ); + } + + if( pastColumnName != futureColumnName ) + { + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schemaName, tableName, settings ); + buf.append( "RENAME COLUMN" ); + bufferQuoteIdentifier( buf, pastColumnName, settings ); + buf.append( "TO" ); + bufferQuoteIdentifier( buf, futureColumnName, settings ); + transaction.executeUpdate( buf.makeStringAndClear() ); + } + } + + OUString futureDefaultValue = extractStringProperty( future, st.DEFAULT_VALUE ); + OUString pastDefaultValue = extractStringProperty( past, st.DEFAULT_VALUE ); + if( futureDefaultValue != pastDefaultValue ) + { + buf.truncate(); + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schemaName, tableName, settings ); + buf.append( "ALTER COLUMN" ); + bufferQuoteIdentifier( buf, futureColumnName, settings ); + buf.append( "SET DEFAULT " ); + // LEM TODO: check out + // default value is not quoted, caller needs to quote himself (otherwise + // how to pass e.g. nextval('something' ) ???? + buf.append( futureDefaultValue ); +// bufferQuoteConstant( buf, defaultValue, encoding ); + transaction.executeUpdate( buf.makeStringAndClear() ); + } + + sal_Int32 futureNullable = extractIntProperty( future, st.IS_NULLABLE ); + sal_Int32 pastNullable = extractIntProperty( past, st.IS_NULLABLE ); + if( futureNullable != pastNullable ) + { + buf.truncate(); + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schemaName, tableName, settings ); + buf.append( "ALTER COLUMN" ); + bufferQuoteIdentifier( buf, futureColumnName, settings ); + if( futureNullable == css::sdbc::ColumnValue::NO_NULLS ) + { + buf.append( "SET" ); + } + else + { + buf.append( "DROP" ); + } + buf.append( " NOT NULL" ); + transaction.executeUpdate( buf.makeStringAndClear() ); + } + +// OUString futureComment = extractStringProperty( future, st.HELP_TEXT ); +// OUString pastComment = extractStringProperty( past, st.HELP_TEXT ); +// printf( "past Comment %s, futureComment %s\n", +// OUStringToOString( pastComment, RTL_TEXTENCODING_ASCII_US ).getStr(), +// OUStringToOString( futureComment, RTL_TEXTENCODING_ASCII_US ).getStr() ); + OUString futureComment = extractStringProperty( future, st.DESCRIPTION ); + OUString pastComment = extractStringProperty( past, st.DESCRIPTION ); + + if( futureComment != pastComment ) + { + buf.truncate(); + buf.append( "COMMENT ON COLUMN" ); + bufferQuoteQualifiedIdentifier( buf, schemaName, tableName , futureColumnName, settings ); + buf.append( "IS " ); + bufferQuoteConstant( buf, futureComment, settings ); + transaction.executeUpdate( buf.makeStringAndClear() ); + } + transaction.commit(); +} + +void Columns::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& future ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + Reference< XPropertySet > past = createDataDescriptor(); + past->setPropertyValue( st.IS_NULLABLE, Any( css::sdbc::ColumnValue::NULLABLE ) ); + alterColumnByDescriptor( + m_schemaName, m_tableName, m_pSettings, m_origin->createStatement() , past, future ); + + refresh(); +} + +// void Columns::dropByName( const OUString& elementName ) +// throw (css::sdbc::SQLException, +// css::container::NoSuchElementException, +// css::uno::RuntimeException) +// { +// String2IntMap::const_iterator ii = m_name2index.find( elementName ); +// if( ii == m_name2index.end() ) +// { +// OUStringBuffer buf( 128 ); +// buf.appendAscii( "Column " ); +// buf.append( elementName ); +// buf.appendAscii( " is unknown in table " ); +// buf.append( m_schemaName ); +// buf.appendAscii( "." ); +// buf.append( m_tableName ); +// buf.appendAscii( ", so it can't be dropped" ); +// throw css::container::NoSuchElementException( +// buf.makeStringAndClear(), *this ); +// } +// dropByIndex( ii->second ); +// } + +void Columns::dropByIndex( sal_Int32 index ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || o3tl::make_unsigned(index) >= m_values.size() ) + { + throw css::lang::IndexOutOfBoundsException( + "COLUMNS: Index out of range (allowed 0 to " + + OUString::number(m_values.size() -1) + + ", got " + OUString::number( index ) + ")", + *this ); + } + + Reference< XPropertySet > set; + m_values[index] >>= set; + Statics &st = getStatics(); + OUString name; + set->getPropertyValue( st.NAME ) >>= name; + + OUStringBuffer update( 128 ); + update.append( "ALTER TABLE ONLY"); + bufferQuoteQualifiedIdentifier( update, m_schemaName, m_tableName, m_pSettings ); + update.append( "DROP COLUMN" ); + bufferQuoteIdentifier( update, name, m_pSettings ); + Reference< XStatement > stmt = m_origin->createStatement( ); + DisposeGuard disposeIt( stmt ); + stmt->executeUpdate( update.makeStringAndClear() ); + + Container::dropByIndex( index ); +} + + +css::uno::Reference< css::beans::XPropertySet > Columns::createDataDescriptor() +{ + return new ColumnDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > Columns::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + rtl::Reference<Columns> *ppColumns) +{ + *ppColumns = new Columns( + refMutex, origin, pSettings, schemaName, tableName ); + (*ppColumns)->refresh(); + + return *ppColumns; +} + + +ColumnDescriptors::ColumnDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) + : Container( refMutex, origin, pSettings, "COLUMN-DESCRIPTOR" ) +{} + + +Reference< css::beans::XPropertySet > ColumnDescriptors::createDataDescriptor() +{ + return new ColumnDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xcolumns.hxx b/connectivity/source/drivers/postgresql/pq_xcolumns.hxx new file mode 100644 index 000000000..aa91a9754 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xcolumns.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <sal/config.h> + +#include <string_view> + +#include <rtl/ref.hxx> + +#include "pq_xcontainer.hxx" +#include "pq_xbase.hxx" + +namespace com::sun::star::sdbc { class XRow; } + +namespace pq_sdbc_driver +{ + +void alterColumnByDescriptor( + std::u16string_view schemaName, + std::u16string_view tableName, + ConnectionSettings *settings, + const css::uno::Reference< css::sdbc::XStatement > &stmt, + const css::uno::Reference< css::beans::XPropertySet > & past, + const css::uno::Reference< css::beans::XPropertySet > & future); + +OUString columnMetaData2SDBCX( + ReflectionBase *pBase, const css::uno::Reference< css::sdbc::XRow > &xRow ); + +class Columns final : public Container +{ + OUString m_schemaName; + OUString m_tableName; + +public: // instances Columns 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + rtl::Reference<Columns> *pColumns); + +private: + Columns( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + + + virtual ~Columns() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +// public: // XDrop +// virtual void SAL_CALL dropByName( const OUString& elementName ) +// throw (css::sdbc::SQLException, +// css::container::NoSuchElementException, +// css::uno::RuntimeException); + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + + +class ColumnDescriptors : public Container +{ +public: + ColumnDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xcontainer.cxx b/connectivity/source/drivers/postgresql/pq_xcontainer.cxx new file mode 100644 index 000000000..fea88b682 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xcontainer.cxx @@ -0,0 +1,409 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <com/sun/star/container/ElementExistException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <cppuhelper/implbase.hxx> +#include <o3tl/safeint.hxx> + +#include "pq_xcontainer.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::RuntimeException; + +using com::sun::star::container::NoSuchElementException; +using com::sun::star::container::XEnumeration; +using com::sun::star::container::XContainerListener; +using com::sun::star::container::ContainerEvent; +using com::sun::star::lang::IndexOutOfBoundsException; +using com::sun::star::lang::XEventListener; + + +namespace pq_sdbc_driver +{ + +namespace { + +class ReplacedBroadcaster : public EventBroadcastHelper +{ + ContainerEvent m_event; +public: + ReplacedBroadcaster( + const Reference< XInterface > & source, + const OUString & name, + const Any & newElement, + const OUString & oldElement ) : + m_event( source, Any( name ), newElement, Any(oldElement) ) + {} + + virtual void fire( XEventListener * listener ) const override + { + static_cast<XContainerListener*>(listener)->elementReplaced( m_event ); + } + virtual Type getType() const override + { + return cppu::UnoType<XContainerListener>::get(); + } +}; + +class InsertedBroadcaster : public EventBroadcastHelper +{ +public: + ContainerEvent m_event; + InsertedBroadcaster( + const Reference< XInterface > & source, + const OUString & name, + const Any & newElement ) : + m_event( source, Any( name ), newElement, Any() ) + {} + + virtual void fire( XEventListener * listener ) const override + { + static_cast<XContainerListener*>(listener)->elementInserted( m_event ); + } + + virtual Type getType() const override + { + return cppu::UnoType<XContainerListener>::get(); + } +}; + +class RemovedBroadcaster : public EventBroadcastHelper +{ +public: + ContainerEvent m_event; + RemovedBroadcaster( + const Reference< XInterface > & source, + const OUString & name) : + m_event( source, Any( name ), Any(), Any() ) + {} + + virtual void fire( XEventListener * listener ) const override + { + static_cast<XContainerListener*>(listener)->elementRemoved( m_event ); + } + + virtual Type getType() const override + { + return cppu::UnoType<XContainerListener>::get(); + } +}; + +} + +Container::Container( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &type) + : ContainerBase( refMutex->GetMutex() ), + m_xMutex( refMutex ), + m_pSettings( pSettings ), + m_origin( origin ), + m_type( type ) +{ +} + +Any Container::getByName( const OUString& aName ) +{ + String2IntMap::const_iterator ii = m_name2index.find( aName ); + if( ii == m_name2index.end() ) + { + throw NoSuchElementException( + "Element " + aName + " unknown in " + m_type + "-Container", + *this ); + } + OSL_ASSERT( ii->second >= 0 && o3tl::make_unsigned(ii->second) < m_values.size() ); + return m_values[ ii->second ]; +} + +Sequence< OUString > Container::getElementNames( ) +{ + Sequence< OUString > ret( m_values.size() ); + auto retRange = asNonConstRange(ret); + for( const auto& [rName, rIndex] : m_name2index ) + { + // give element names in index order ! + retRange[rIndex] = rName; + } + return ret; +} + +sal_Bool Container::hasByName( const OUString& aName ) +{ + return m_name2index.find( aName ) != m_name2index.end(); +} + // Methods +Type Container::getElementType( ) +{ + return Type(); +} + +sal_Bool Container::hasElements( ) +{ + return ! m_name2index.empty(); +} + +Any Container::getByIndex( sal_Int32 Index ) +{ + if( Index < 0 || o3tl::make_unsigned(Index) >= m_values.size() ) + { + throw IndexOutOfBoundsException( + "Index " + OUString::number( Index ) + + " out of range for " + m_type + "-Container, expected 0 <= x <= " + + OUString::number(m_values.size() -1), + *this ); + } + return m_values[Index]; +} + +sal_Int32 Container::getCount() +{ + return m_values.size(); +} + +namespace { + +class ContainerEnumeration : public ::cppu::WeakImplHelper< XEnumeration > +{ + std::vector< css::uno::Any > m_vec; + sal_Int32 m_index; +public: + explicit ContainerEnumeration( std::vector< css::uno::Any >&& vec ) + : m_vec( std::move(vec) ), + m_index( -1 ) + {} + +public: + // XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements( ) override; + virtual css::uno::Any SAL_CALL nextElement( ) override; + +}; + +} + +sal_Bool ContainerEnumeration::hasMoreElements() +{ + return static_cast<int>(m_vec.size()) > m_index +1; +} + +css::uno::Any ContainerEnumeration::nextElement() +{ + if( ! hasMoreElements() ) + { + throw NoSuchElementException( + "NoSuchElementException during enumeration", *this ); + } + m_index ++; + return m_vec[m_index]; +} + +Reference< XEnumeration > Container::createEnumeration( ) +{ + return new ContainerEnumeration( std::vector(m_values) ); +} + +void Container::addRefreshListener( + const css::uno::Reference< css::util::XRefreshListener >& l ) +{ + rBHelper.addListener( cppu::UnoType<decltype(l)>::get() , l ); +} + +void Container::removeRefreshListener( + const css::uno::Reference< css::util::XRefreshListener >& l ) +{ + rBHelper.removeListener( cppu::UnoType<decltype(l)>::get() , l ); +} + +void Container::disposing() +{ + m_origin.clear(); +} + +void Container::rename( const OUString &oldName, const OUString &newName ) +{ + Any newValue; + { + osl::MutexGuard guard ( m_xMutex->GetMutex() ); + String2IntMap::iterator ii = m_name2index.find( oldName ); + if( ii != m_name2index.end() ) + { + sal_Int32 nIndex = ii->second; + newValue = m_values[nIndex]; + m_name2index.erase( ii ); + m_name2index[ newName ] = nIndex; + } + } + fire( ReplacedBroadcaster( *this, newName, newValue, oldName ) ); + fire( RefreshedBroadcaster( *this ) ); +} + +void Container::dropByName( const OUString& elementName ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + String2IntMap::const_iterator ii = m_name2index.find( elementName ); + if( ii == m_name2index.end() ) + { + throw css::container::NoSuchElementException( + "Column " + elementName + " is unknown in " + + m_type + " container, so it can't be dropped", + *this ); + } + dropByIndex( ii->second ); +} + +void Container::dropByIndex( sal_Int32 index ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || o3tl::make_unsigned(index) >=m_values.size() ) + { + throw css::lang::IndexOutOfBoundsException( + "Index out of range (allowed 0 to " + + OUString::number(m_values.size() -1) + + ", got " + OUString::number( index ) + + ") in " + m_type, + *this ); + } + + OUString name; + String2IntMap::iterator ii = std::find_if(m_name2index.begin(), m_name2index.end(), + [&index](const String2IntMap::value_type& rEntry) { return rEntry.second == index; }); + if (ii != m_name2index.end()) + { + name = ii->first; + m_name2index.erase( ii ); + } + + for( int i = index +1 ; i < static_cast<int>(m_values.size()) ; i ++ ) + { + m_values[i-1] = m_values[i]; + + // I know, this is expensive, but don't want to maintain another map ... + ii = std::find_if(m_name2index.begin(), m_name2index.end(), + [&i](const String2IntMap::value_type& rEntry) { return rEntry.second == i; }); + if (ii != m_name2index.end()) + { + ii->second = i-1; + } + } + m_values.resize( m_values.size() - 1 ); + + fire( RemovedBroadcaster( *this, name ) ); +} + +void Container::append( + const OUString & name, + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) + +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + if( hasByName( name ) ) + { + throw css::container::ElementExistException( + "a " + m_type + " with name " + name + " already exists in this container", + *this ); + } + + int index = m_values.size(); + m_values.push_back( Any( descriptor ) ); + m_name2index[name] = index; + + fire( InsertedBroadcaster( *this, name, Any( descriptor ) ) ); +} + +void Container::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor) +{ + append( extractStringProperty( descriptor, getStatics().NAME ), descriptor ); +} + + +void Container::addContainerListener( + const css::uno::Reference< css::container::XContainerListener >& l ) +{ + rBHelper.addListener( cppu::UnoType<decltype(l)>::get() , l ); +} + +void Container::removeContainerListener( + const css::uno::Reference< css::container::XContainerListener >& l ) +{ + rBHelper.removeListener( cppu::UnoType<decltype(l)>::get() , l ); +} + + +void Container::fire( const EventBroadcastHelper &helper ) +{ + cppu::OInterfaceContainerHelper *container = rBHelper.getContainer( helper.getType() ); + if( !container ) + return; + + cppu::OInterfaceIteratorHelper iterator( * container ); + while( iterator.hasMoreElements() ) + { + try + { + helper.fire( static_cast<XEventListener *>(iterator.next()) ); + } + catch ( css::uno::RuntimeException & ) + { + OSL_ENSURE( false, "exception caught" ); + // loose coupling, a runtime exception shall not break anything + // TODO: log away as warning ! + } + catch( css::uno::Exception & ) + { + OSL_ENSURE( false, "exception from listener flying through" ); + throw; + } + } + +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xcontainer.hxx b/connectivity/source/drivers/postgresql/pq_xcontainer.hxx new file mode 100644 index 000000000..fd9d432bf --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xcontainer.hxx @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XContainer.hpp> + +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbcx/XDrop.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> + +#include <com/sun/star/util/XRefreshable.hpp> + +#include <comphelper/refcountedmutex.hxx> +#include <cppuhelper/compbase.hxx> +#include <rtl/ref.hxx> + +#include <unordered_map> + +namespace pq_sdbc_driver +{ + +struct ConnectionSettings; + +class EventBroadcastHelper +{ +public: + virtual void fire(css::lang::XEventListener * listener) const = 0; + virtual css::uno::Type getType() const = 0; + virtual ~EventBroadcastHelper(){}; +}; + +class RefreshedBroadcaster : public EventBroadcastHelper +{ + css::lang::EventObject m_event; +public: + explicit RefreshedBroadcaster(const css::uno::Reference< css::uno::XInterface > & source ) : + m_event( source ) + {} + + virtual void fire( css::lang::XEventListener * listener ) const override + { + static_cast<css::util::XRefreshListener*>(listener)->refreshed( m_event ); + } + + virtual css::uno::Type getType() const override + { + return cppu::UnoType< + css::util::XRefreshListener>::get(); + } +}; + +typedef std::unordered_map +< + OUString, + sal_Int32 +> String2IntMap; + +typedef ::cppu::WeakComponentImplHelper +< + css::container::XNameAccess, + css::container::XIndexAccess, + css::container::XEnumerationAccess, + css::sdbcx::XAppend, + css::sdbcx::XDrop, + css::util::XRefreshable, + css::sdbcx::XDataDescriptorFactory, + css::container::XContainer +> ContainerBase; + +class /* abstract */ Container : public ContainerBase +{ +protected: + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + ConnectionSettings *m_pSettings; + css::uno::Reference< css::sdbc::XConnection > m_origin; + String2IntMap m_name2index; // maps the element name to an index + std::vector< css::uno::Any > m_values; // contains the real values + OUString m_type; + +public: + Container( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString & type // for exception messages + ); + +public: // XIndexAccess + virtual sal_Int32 SAL_CALL getCount( ) override; + virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override; + +public: // XEnumerationAccess + virtual css::uno::Reference< css::container::XEnumeration > + SAL_CALL createEnumeration( ) override; + +public: // XNameAccess + virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override; + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override; + // Methods + virtual css::uno::Type SAL_CALL getElementType( ) override; + virtual sal_Bool SAL_CALL hasElements( ) override; + + +public: // XAppend + // Must be overridden in Non-Descriptors. May be overridden in descriptors, when + // PropertySet.NAME != container name + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + + // helper method ! + /// @throws css::container::ElementExistException + void append( + const OUString & str, + const css::uno::Reference< css::beans::XPropertySet >& descriptor ); + + +public: // XDrop + virtual void SAL_CALL dropByName( const OUString& elementName ) override; + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override = 0; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override {} + virtual void SAL_CALL addRefreshListener( + const css::uno::Reference< css::util::XRefreshListener >& l ) override; + virtual void SAL_CALL removeRefreshListener( + const css::uno::Reference< css::util::XRefreshListener >& l ) override; + +public: + // Methods + virtual void SAL_CALL addContainerListener( + const css::uno::Reference< css::container::XContainerListener >& xListener ) override; + virtual void SAL_CALL removeContainerListener( + const css::uno::Reference< css::container::XContainerListener >& xListener ) override; + +public: + virtual void SAL_CALL disposing() override; + +public: + void rename( const OUString & oldName, const OUString &newName ); + +protected: + void fire( const EventBroadcastHelper & helper ); +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindex.cxx b/connectivity/source/drivers/postgresql/pq_xindex.cxx new file mode 100644 index 000000000..5a96eeeb1 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindex.cxx @@ -0,0 +1,186 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <rtl/ref.hxx> + +#include "pq_xindex.hxx" +#include "pq_xindexcolumns.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +using com::sun::star::container::XNameAccess; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::beans::XPropertySet; + + +namespace pq_sdbc_driver +{ +Index::Index( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings, + const OUString & schemaName, + const OUString & tableName ) + : ReflectionBase( + getStatics().refl.index.implName, + getStatics().refl.index.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.index.pProps ), + m_schemaName( schemaName ), + m_tableName( tableName ) +{} + +Reference< XPropertySet > Index::createDataDescriptor( ) +{ + rtl::Reference<IndexDescriptor> pIndex = new IndexDescriptor( + m_xMutex, m_conn, m_pSettings ); + pIndex->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pIndex ); +} + +Reference< XNameAccess > Index::getColumns( ) +{ + if( ! m_indexColumns.is() ) + { + Sequence< OUString > columnNames; + getPropertyValue( getStatics().PRIVATE_COLUMN_INDEXES ) >>= columnNames; + OUString indexName = extractStringProperty( this, getStatics().NAME ); + m_indexColumns = IndexColumns::create( + m_xMutex, m_conn, m_pSettings, m_schemaName, + m_tableName, indexName, columnNames ); + } + return m_indexColumns; +} + +Sequence<Type > Index::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> Index::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any Index::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XColumnsSupplier * > ( this ) ); + return ret; +} + + +IndexDescriptor::IndexDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ) + : ReflectionBase( + getStatics().refl.indexDescriptor.implName, + getStatics().refl.indexDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.indexDescriptor.pProps ) +{} + +Reference< XPropertySet > IndexDescriptor::createDataDescriptor( ) +{ + rtl::Reference<IndexDescriptor> pIndex = new IndexDescriptor( + m_xMutex, m_conn, m_pSettings ); + pIndex->copyValuesFrom( this ); + return Reference< XPropertySet > ( pIndex ); +} + +Reference< XNameAccess > IndexDescriptor::getColumns( ) +{ + if( ! m_indexColumns.is() ) + { + m_indexColumns = IndexColumnDescriptors::create( + m_xMutex, m_conn, m_pSettings ); +// Sequence< OUString > columnNames; +// getPropertyValue( getStatics().PRIVATE_COLUMN_INDEXES ) >>= columnNames; +// OUString indexName = extractStringProperty( this, getStatics().NAME ); +// m_indexColumns = IndexColumns::create( +// m_xMutex, m_conn, m_pSettings, m_schemaName, +// m_tableName, indexName, columnNames ); + } + return m_indexColumns; +} + +Sequence<Type > IndexDescriptor::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> IndexDescriptor::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any IndexDescriptor::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XColumnsSupplier * > ( this ) ); + return ret; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindex.hxx b/connectivity/source/drivers/postgresql/pq_xindex.hxx new file mode 100644 index 000000000..46275ad3a --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindex.hxx @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> + +#include "pq_connection.hxx" +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class Index : public ReflectionBase, + public css::sdbcx::XColumnsSupplier +{ + css::uno::Reference< css::container::XNameAccess > m_indexColumns; + + OUString m_schemaName; + OUString m_tableName; + +public: + Index( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + +public: // XInterface + virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getColumns( ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + + +class IndexDescriptor : public ReflectionBase, + public css::sdbcx::XColumnsSupplier +{ + css::uno::Reference< css::container::XNameAccess > m_indexColumns; + +public: + IndexDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XInterface + virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getColumns( ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindexcolumn.cxx b/connectivity/source/drivers/postgresql/pq_xindexcolumn.cxx new file mode 100644 index 000000000..fe72059bc --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindexcolumn.cxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/config.h> + +#include <rtl/ref.hxx> + +#include "pq_statics.hxx" +#include "pq_xindexcolumn.hxx" + +using com::sun::star::uno::Reference; + +using com::sun::star::beans::XPropertySet; + +namespace pq_sdbc_driver +{ +IndexColumn::IndexColumn( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ) + : ReflectionBase( + getStatics().refl.indexColumn.implName, + getStatics().refl.indexColumn.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.indexColumn.pProps ) +{} + +Reference< XPropertySet > IndexColumn::createDataDescriptor( ) +{ + rtl::Reference<IndexColumnDescriptor> pIndexColumn = new IndexColumnDescriptor( + m_xMutex, m_conn, m_pSettings ); + pIndexColumn->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pIndexColumn ); +} + + +IndexColumnDescriptor::IndexColumnDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ) + : ReflectionBase( + getStatics().refl.indexColumnDescriptor.implName, + getStatics().refl.indexColumnDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.indexColumnDescriptor.pProps ) +{} + +Reference< XPropertySet > IndexColumnDescriptor::createDataDescriptor( ) +{ + rtl::Reference<IndexColumnDescriptor> pIndexColumn = new IndexColumnDescriptor( + m_xMutex, m_conn, m_pSettings ); + pIndexColumn->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pIndexColumn ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindexcolumn.hxx b/connectivity/source/drivers/postgresql/pq_xindexcolumn.hxx new file mode 100644 index 000000000..7872985ec --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindexcolumn.hxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> + +#include "pq_connection.hxx" +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class IndexColumn : public ReflectionBase +{ +public: + IndexColumn( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + +class IndexColumnDescriptor : public ReflectionBase +{ +public: + IndexColumnDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindexcolumns.cxx b/connectivity/source/drivers/postgresql/pq_xindexcolumns.cxx new file mode 100644 index 000000000..841ea9805 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindexcolumns.cxx @@ -0,0 +1,267 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/log.hxx> + +#include <string_view> +#include <vector> + +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <rtl/ref.hxx> + +#include "pq_xcolumns.hxx" +#include "pq_xindexcolumns.hxx" +#include "pq_xindexcolumn.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XDatabaseMetaData; +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ + +IndexColumns::IndexColumns( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const OUString &indexName, + const css::uno::Sequence< OUString > &columns ) + : Container( refMutex, origin, pSettings, "INDEX_COLUMN" ), + m_schemaName( schemaName ), + m_tableName( tableName ), + m_indexName( indexName ), + m_columns( columns ) +{} + +IndexColumns::~IndexColumns() +{} + +static sal_Int32 findInSequence( const Sequence< OUString > & seq , std::u16string_view str) +{ + int index; + for( index = 0 ; index < seq.getLength() ; index ++ ) + { + if( str == seq[index] ) + break; + } + return index; +} + +void IndexColumns::refresh() +{ + try + { + SAL_INFO("connectivity.postgresql", "sdbcx.IndexColumns get refreshed for index " << m_indexName); + + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + Statics &st = getStatics(); + Reference< XDatabaseMetaData > meta = m_origin->getMetaData(); + + Reference< XResultSet > rs = + meta->getColumns( Any(), m_schemaName, m_tableName, st.cPERCENT ); + + DisposeGuard disposeIt( rs ); + Reference< XRow > xRow( rs , UNO_QUERY ); + m_values.clear(); + m_values.resize( m_columns.getLength() ); + + while( rs->next() ) + { + OUString columnName = xRow->getString( 4 ); + + sal_Int32 index = findInSequence( m_columns, columnName ); + if( index >= m_columns.getLength() ) + continue; + + rtl::Reference<IndexColumn> pIndexColumn = + new IndexColumn( m_xMutex, m_origin, m_pSettings ); + Reference< css::beans::XPropertySet > prop = pIndexColumn; + + columnMetaData2SDBCX( pIndexColumn.get(), xRow ); + pIndexColumn->setPropertyValue_NoBroadcast_public( + st.IS_ASCENDING , Any( false ) ); + + m_values[ index ] <<= prop; + m_name2index[ columnName ] = index; + } + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + fire( RefreshedBroadcaster( *this ) ); +} + + +void IndexColumns::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& /*future*/ ) +{ + throw css::sdbc::SQLException( + "SDBC-POSTGRESQL: IndexesColumns.appendByDescriptor not yet implemented", + *this, OUString(), 1, Any() ); +// osl::MutexGuard guard( m_xMutex->GetMutex() ); +// Statics & st = getStatics(); +// Reference< XPropertySet > past = createDataDescriptor(); +// past->setPropertyValue( st.IS_NULLABLE, makeAny( css::sdbc::ColumnValue::NULLABLE ) ); +// alterColumnByDescriptor( +// m_schemaName, m_tableName, m_pSettings->encoding, m_origin->createStatement() , past, future ); + +} + +void IndexColumns::dropByName( const OUString& ) +{ + throw css::sdbc::SQLException( + "SDBC-POSTGRESQL: IndexesColumns.dropByName not yet implemented", + *this, OUString(), 1, Any() ); +// String2IntMap::const_iterator ii = m_name2index.find( elementName ); +// if( ii == m_name2index.end() ) +// { +// OUStringBuffer buf( 128 ); +// buf.appendAscii( "Column " ); +// buf.append( elementName ); +// buf.appendAscii( " is unknown in table " ); +// buf.append( m_schemaName ); +// buf.appendAscii( "." ); +// buf.append( m_tableName ); +// buf.appendAscii( ", so it can't be dropped" ); +// throw css::container::NoSuchElementException( +// buf.makeStringAndClear(), *this ); +// } +// dropByIndex( ii->second ); +} + +void IndexColumns::dropByIndex( sal_Int32 ) +{ + throw css::sdbc::SQLException( + "SDBC-POSTGRESQL: IndexesColumns.dropByIndex not yet implemented", + *this, OUString(), 1, Any() ); +// osl::MutexGuard guard( m_xMutex->GetMutex() ); +// if( index < 0 || index >= m_values.getLength() ) +// { +// OUStringBuffer buf( 128 ); +// buf.appendAscii( "COLUMNS: Index out of range (allowed 0 to " ); +// buf.append((sal_Int32)(m_values.getLength() -1) ); +// buf.appendAscii( ", got " ); +// buf.append( index ); +// buf.appendAscii( ")" ); +// throw css::lang::IndexOutOfBoundsException( +// buf.makeStringAndClear(), *this ); +// } + +// Reference< XPropertySet > set; +// m_values[index] >>= set; +// Statics &st = getStatics(); +// OUString name; +// set->getPropertyValue( st.NAME ) >>= name; + +// OUStringBuffer update( 128 ); +// update.appendAscii( "ALTER TABLE ONLY"); +// bufferQuoteQualifiedIdentifier( update, m_schemaName, m_tableName ); +// update.appendAscii( "DROP COLUMN" ); +// bufferQuoteIdentifier( update, name ); +// Reference< XStatement > stmt = m_origin->createStatement( ); +// DisposeGuard disposeIt( stmt ); +// stmt->executeUpdate( update.makeStringAndClear() ); + +} + + +Reference< css::beans::XPropertySet > IndexColumns::createDataDescriptor() +{ + return new IndexColumnDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > IndexColumns::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const OUString &indexName, + const Sequence< OUString > &columns ) +{ + rtl::Reference<IndexColumns> pIndexColumns = new IndexColumns( + refMutex, origin, pSettings, schemaName, tableName, indexName, columns ); + pIndexColumns->refresh(); + + return pIndexColumns; +} + + +IndexColumnDescriptors::IndexColumnDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings) + : Container( refMutex, origin, pSettings, getStatics().INDEX_COLUMN ) +{} + +Reference< css::container::XNameAccess > IndexColumnDescriptors::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings) +{ + return new IndexColumnDescriptors( refMutex, origin, pSettings ); +} + +css::uno::Reference< css::beans::XPropertySet > IndexColumnDescriptors::createDataDescriptor() +{ + return new IndexColumnDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindexcolumns.hxx b/connectivity/source/drivers/postgresql/pq_xindexcolumns.hxx new file mode 100644 index 000000000..eaaa709e6 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindexcolumns.hxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ + +class IndexColumns final : public Container +{ + OUString m_schemaName; + OUString m_tableName; + OUString m_indexName; + css::uno::Sequence< OUString > m_columns; + +public: // instances IndexColumns 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const OUString &indexName, + const css::uno::Sequence< OUString > &columns ); + +private: + IndexColumns( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const OUString &indexName, + const css::uno::Sequence< OUString > &columns ); + + virtual ~IndexColumns() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +public: // XDrop + virtual void SAL_CALL dropByName( const OUString& elementName ) override; + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + + +class IndexColumnDescriptors final : public Container +{ + +public: // instances IndexColumns 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +private: + IndexColumnDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindexes.cxx b/connectivity/source/drivers/postgresql/pq_xindexes.cxx new file mode 100644 index 000000000..ef1e7116a --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindexes.cxx @@ -0,0 +1,302 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <o3tl/safeint.hxx> + +#include "pq_xindexes.hxx" +#include "pq_xindex.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; + +using com::sun::star::container::XEnumerationAccess; +using com::sun::star::container::XEnumeration; + + +using com::sun::star::sdbcx::XColumnsSupplier; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XParameters; +using com::sun::star::sdbc::XPreparedStatement; + +namespace pq_sdbc_driver +{ + +Indexes::Indexes( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName) + : Container( refMutex, origin, pSettings, getStatics().KEY ), + m_schemaName( schemaName ), + m_tableName( tableName ) +{ +} + +Indexes::~Indexes() +{} + +void Indexes::refresh() +{ + try + { + SAL_INFO("connectivity.postgresql", "sdbcx.Indexes get refreshed for table " << m_schemaName << "." << m_tableName); + + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + + Int2StringMap column2NameMap; + fillAttnum2attnameMap( column2NameMap, m_origin, m_schemaName, m_tableName ); + + // see XDatabaseMetaData::getIndexInfo() + Reference< XPreparedStatement > stmt = m_origin->prepareStatement( + "SELECT nspname, " // 1 + "pg_class.relname, " // 2 + "class2.relname, " // 3 + "indisclustered, " // 4 + "indisunique, " // 5 + "indisprimary, " // 6 + "indkey " // 7 + "FROM pg_index INNER JOIN pg_class ON indrelid = pg_class.oid " + "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid " + "INNER JOIN pg_class as class2 ON pg_index.indexrelid = class2.oid " + "WHERE nspname = ? AND pg_class.relname = ?" ); + + Reference< XParameters > params( stmt, UNO_QUERY); + params->setString( 1, m_schemaName ); + params->setString( 2, m_tableName ); + Reference< XResultSet > rs = stmt->executeQuery(); + + Reference< XRow > row( rs, UNO_QUERY ); + String2IntMap map; + m_values.clear(); + sal_Int32 index = 0; + while( rs->next() ) + { + // C_SCHEMA = 1 + // C_TABLENAME = 2 + static const sal_Int32 C_INDEXNAME = 3; + static const sal_Int32 C_IS_CLUSTERED = 4; + static const sal_Int32 C_IS_UNIQUE = 5; + static const sal_Int32 C_IS_PRIMARY = 6; + static const sal_Int32 C_COLUMNS = 7; + OUString currentIndexName = row->getString( C_INDEXNAME ); + rtl::Reference<Index> pIndex = + new Index( m_xMutex, m_origin, m_pSettings, + m_schemaName, m_tableName ); + + bool isUnique = row->getBoolean( C_IS_UNIQUE ); + bool isPrimary = row->getBoolean( C_IS_PRIMARY ); + bool isClusterd = row->getBoolean( C_IS_CLUSTERED ); + Reference< css::beans::XPropertySet > prop = pIndex; + pIndex->setPropertyValue_NoBroadcast_public( + st.IS_UNIQUE, Any( isUnique ) ); + pIndex->setPropertyValue_NoBroadcast_public( + st.IS_PRIMARY_KEY_INDEX, Any( isPrimary ) ); + pIndex->setPropertyValue_NoBroadcast_public( + st.IS_CLUSTERED, Any( isClusterd ) ); + pIndex->setPropertyValue_NoBroadcast_public( + st.NAME, Any( currentIndexName ) ); + + std::vector< sal_Int32 > seq = parseIntArray( row->getString( C_COLUMNS ) ); + Sequence< OUString > columnNames(seq.size()); + auto columnNamesRange = asNonConstRange(columnNames); + for( size_t columns = 0 ; columns < seq.size() ; columns ++ ) + { + columnNamesRange[columns] = column2NameMap[ seq[columns] ]; + } + + pIndex->setPropertyValue_NoBroadcast_public( + st.PRIVATE_COLUMN_INDEXES, Any( columnNames )); + + { + m_values.push_back( Any( prop ) ); + map[ currentIndexName ] = index; + ++index; + } + } + m_name2index.swap( map ); + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + fire( RefreshedBroadcaster( *this ) ); +} + + +void Indexes::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) +{ + Statics & st = getStatics(); + OUString name = extractStringProperty( descriptor, st.NAME ); + + bool isUnique = extractBoolProperty( descriptor, st.IS_UNIQUE ); + + OUStringBuffer buf( 128 ); + + buf.append( "CREATE " ); + if( isUnique ) + buf.append( "UNIQUE " ); + buf.append( "INDEX " ); + bufferQuoteIdentifier( buf, name, m_pSettings ); + buf.append( " ON " ); + bufferQuoteQualifiedIdentifier( buf, m_schemaName, m_tableName, m_pSettings ); + + buf.append( " ( " ); + + Reference< XColumnsSupplier > columns( descriptor, UNO_QUERY ); + if( columns.is() ) + { + Reference< XEnumerationAccess > access( columns->getColumns(), UNO_QUERY ); + if( access.is() ) + { + Reference< XEnumeration > xEnum( access->createEnumeration() ); + bool first = true; + while( xEnum.is() && xEnum->hasMoreElements() ) + { + Reference< XPropertySet > column( xEnum->nextElement(), UNO_QUERY ); + if( first ) + { + first = false; + } + else + { + buf.append( ", " ); + } + buf.append( extractStringProperty( column, st.NAME ) ); + } + } + } + buf.append( " ) " ); + + m_origin->createStatement()->executeUpdate( buf.makeStringAndClear() ); + refresh(); +} + +void Indexes::dropByIndex( sal_Int32 index ) +{ + + + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || o3tl::make_unsigned(index) >= m_values.size() ) + { + throw css::lang::IndexOutOfBoundsException( + "Indexes: Index out of range (allowed 0 to " + + OUString::number( m_values.size() -1 ) + + ", got " + OUString::number( index ) + + ")", + *this ); + } + + Reference< XPropertySet > set; + m_values[index] >>= set; + Statics &st = getStatics(); + + OUStringBuffer buf( 128 ); + buf.append( "DROP INDEX " ); + bufferQuoteIdentifier( buf, extractStringProperty( set, st.NAME ), m_pSettings ); + m_origin->createStatement()->executeUpdate( buf.makeStringAndClear() ); + + Container::dropByIndex( index ); +} + + +css::uno::Reference< css::beans::XPropertySet > Indexes::createDataDescriptor() +{ + return new IndexDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > Indexes::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString & schemaName, + const OUString & tableName) +{ + rtl::Reference<Indexes> pIndexes + = new Indexes( refMutex, origin, pSettings, schemaName, tableName ); + pIndexes->refresh(); + return pIndexes; +} + + +IndexDescriptors::IndexDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings) + : Container( refMutex, origin, pSettings, getStatics().INDEX ) +{} + +Reference< css::container::XNameAccess > IndexDescriptors::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings) +{ + return new IndexDescriptors( refMutex, origin, pSettings ); +} + +css::uno::Reference< css::beans::XPropertySet > IndexDescriptors::createDataDescriptor() +{ + return new IndexDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindexes.hxx b/connectivity/source/drivers/postgresql/pq_xindexes.hxx new file mode 100644 index 000000000..c2e81f617 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindexes.hxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ +class Indexes final : public Container +{ + OUString m_schemaName; + OUString m_tableName; + +public: // instances Columns 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + +private: + Indexes( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + + virtual ~Indexes() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +public: // XDrop + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + + +class IndexDescriptors final : public Container +{ +public: // instances IndexDescriptors 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +private: + IndexDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; + +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkey.cxx b/connectivity/source/drivers/postgresql/pq_xkey.cxx new file mode 100644 index 000000000..e27778245 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkey.cxx @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <rtl/ref.hxx> + +#include "pq_xkey.hxx" +#include "pq_xkeycolumns.hxx" +#include "pq_statics.hxx" + +using com::sun::star::container::XNameAccess; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::beans::XPropertySet; + + +namespace pq_sdbc_driver +{ +Key::Key( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings, + const OUString & schemaName, + const OUString & tableName ) + : ReflectionBase( + getStatics().refl.key.implName, + getStatics().refl.key.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.key.pProps ), + m_schemaName( schemaName ), + m_tableName( tableName ) +{} + +Reference< XPropertySet > Key::createDataDescriptor( ) +{ + rtl::Reference<KeyDescriptor> pKeyDescriptor = new KeyDescriptor( + m_xMutex, m_conn, m_pSettings ); + pKeyDescriptor->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pKeyDescriptor ); +} + +Reference< XNameAccess > Key::getColumns( ) +{ + // TODO: cash columns object ! + if( !m_keyColumns.is() ) + { + Sequence< OUString > columnNames, foreignColumnNames; + getPropertyValue( getStatics().PRIVATE_COLUMNS ) >>= columnNames; + getPropertyValue( getStatics().PRIVATE_FOREIGN_COLUMNS ) >>= foreignColumnNames; + + m_keyColumns = KeyColumns::create( + m_xMutex, m_conn, m_pSettings, m_schemaName, + m_tableName, columnNames, foreignColumnNames ); + } + return m_keyColumns; +} + +Sequence<Type > Key::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> Key::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any Key::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XColumnsSupplier * > ( this ) ); + return ret; +} + + +KeyDescriptor::KeyDescriptor( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ) + : ReflectionBase( + getStatics().refl.keyDescriptor.implName, + getStatics().refl.keyDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.keyDescriptor.pProps ) +{ +} + +Reference< XPropertySet > KeyDescriptor::createDataDescriptor( ) +{ + rtl::Reference<KeyDescriptor> pKeyDescriptor = new KeyDescriptor( + m_xMutex, m_conn, m_pSettings ); + pKeyDescriptor->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pKeyDescriptor ); +} + +Reference< XNameAccess > KeyDescriptor::getColumns( ) +{ + // TODO: cash columns object ! + if( !m_keyColumns.is() ) + { + m_keyColumns = new KeyColumnDescriptors( m_xMutex, m_conn, m_pSettings ); + } + return m_keyColumns; +} + +Sequence<Type > KeyDescriptor::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> KeyDescriptor::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any KeyDescriptor::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XColumnsSupplier * > ( this ) ); + return ret; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkey.hxx b/connectivity/source/drivers/postgresql/pq_xkey.hxx new file mode 100644 index 000000000..d231e1e89 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkey.hxx @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> + +#include "pq_connection.hxx" +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class Key : public ReflectionBase, + public css::sdbcx::XColumnsSupplier +{ + css::uno::Reference< css::container::XNameAccess > m_keyColumns; + + OUString m_schemaName; + OUString m_tableName; + +public: + Key( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + +public: // XInterface + virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getColumns( ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + + +class KeyDescriptor : public ReflectionBase, public css::sdbcx::XColumnsSupplier +{ + css::uno::Reference< css::container::XNameAccess > m_keyColumns; + +public: + KeyDescriptor( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ); + +public: // XInterface + virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getColumns( ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; +}; + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkeycolumn.cxx b/connectivity/source/drivers/postgresql/pq_xkeycolumn.cxx new file mode 100644 index 000000000..30eef1797 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkeycolumn.cxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/config.h> + +#include <rtl/ref.hxx> + +#include "pq_statics.hxx" +#include "pq_xkeycolumn.hxx" + +using com::sun::star::uno::Reference; + +using com::sun::star::beans::XPropertySet; + +namespace pq_sdbc_driver +{ +KeyColumn::KeyColumn( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.keycolumn.implName, + getStatics().refl.keycolumn.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.keycolumn.pProps ) +{} + +Reference< XPropertySet > KeyColumn::createDataDescriptor( ) +{ + rtl::Reference<KeyColumnDescriptor> pKeyColumn = new KeyColumnDescriptor( + m_xMutex, m_conn, m_pSettings ); + pKeyColumn->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pKeyColumn ); +} + +KeyColumnDescriptor::KeyColumnDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.keycolumnDescriptor.implName, + getStatics().refl.keycolumnDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.keycolumnDescriptor.pProps ) +{} + +Reference< XPropertySet > KeyColumnDescriptor::createDataDescriptor( ) +{ + rtl::Reference<KeyColumnDescriptor> pKeyColumn = new KeyColumnDescriptor( + m_xMutex, m_conn, m_pSettings ); + pKeyColumn->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pKeyColumn ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkeycolumn.hxx b/connectivity/source/drivers/postgresql/pq_xkeycolumn.hxx new file mode 100644 index 000000000..7d49d5d26 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkeycolumn.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> + +#include "pq_connection.hxx" +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class KeyColumn : public ReflectionBase +{ +public: + KeyColumn( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + +class KeyColumnDescriptor : public ReflectionBase +{ +public: + KeyColumnDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkeycolumns.cxx b/connectivity/source/drivers/postgresql/pq_xkeycolumns.cxx new file mode 100644 index 000000000..8b62f2842 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkeycolumns.cxx @@ -0,0 +1,238 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <rtl/ref.hxx> + +#include "pq_xcolumns.hxx" +#include "pq_xkeycolumns.hxx" +#include "pq_xkeycolumn.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XDatabaseMetaData; +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ + +KeyColumns::KeyColumns( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const Sequence< OUString > &columnNames, + const Sequence< OUString > &foreignColumnNames ) + : Container( refMutex, origin, pSettings, "KEY_COLUMN" ), + m_schemaName( schemaName ), + m_tableName( tableName ), + m_columnNames( columnNames ), + m_foreignColumnNames( foreignColumnNames ) +{} + +KeyColumns::~KeyColumns() +{} + + +void KeyColumns::refresh() +{ + try + { + SAL_INFO("connectivity.postgresql", "sdbcx.KeyColumns get refreshed for table " << m_schemaName << "." << m_tableName); + + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + Statics &st = getStatics(); + Reference< XDatabaseMetaData > meta = m_origin->getMetaData(); + + Reference< XResultSet > rs = + meta->getColumns( Any(), m_schemaName, m_tableName, st.cPERCENT ); + + DisposeGuard disposeIt( rs ); + Reference< XRow > xRow( rs , UNO_QUERY ); + + String2IntMap map; + + m_values.clear(); + sal_Int32 columnIndex = 0; + while( rs->next() ) + { + OUString columnName = xRow->getString( 4 ); + + int keyindex; + for( keyindex = 0 ; keyindex < m_columnNames.getLength() ; keyindex ++ ) + { + if( columnName == m_columnNames[keyindex] ) + break; + } + if( m_columnNames.getLength() == keyindex ) + continue; + + rtl::Reference<KeyColumn> pKeyColumn = + new KeyColumn( m_xMutex, m_origin, m_pSettings ); + Reference< css::beans::XPropertySet > prop = pKeyColumn; + + OUString name = columnMetaData2SDBCX( pKeyColumn.get(), xRow ); + if( keyindex < m_foreignColumnNames.getLength() ) + { + pKeyColumn->setPropertyValue_NoBroadcast_public( + st.RELATED_COLUMN, Any( m_foreignColumnNames[keyindex]) ); + } + + { + m_values.push_back( Any( prop ) ); + map[ name ] = columnIndex; + ++columnIndex; + } + } + m_name2index.swap( map ); + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + fire( RefreshedBroadcaster( *this ) ); +} + + +void KeyColumns::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& ) +{ + throw css::sdbc::SQLException( + "KeyColumns::appendByDescriptor not implemented yet", + *this, OUString(), 1, Any() ); + +// osl::MutexGuard guard( m_xMutex->GetMutex() ); +// Statics & st = getStatics(); +// Reference< XPropertySet > past = createDataDescriptor(); +// past->setPropertyValue( st.IS_NULLABLE, makeAny( css::sdbc::ColumnValue::NULLABLE ) ); +// alterColumnByDescriptor( +// m_schemaName, m_tableName, m_pSettings->encoding, m_origin->createStatement() , past, future ); + +} + + +void KeyColumns::dropByIndex( sal_Int32 ) +{ + throw css::sdbc::SQLException( + "KeyColumns::dropByIndex not implemented yet", + *this, OUString(), 1, Any() ); +// osl::MutexGuard guard( m_xMutex->GetMutex() ); +// if( index < 0 || index >= m_values.getLength() ) +// { +// OUStringBuffer buf( 128 ); +// buf.appendAscii( "COLUMNS: Index out of range (allowed 0 to " ); +// buf.append((sal_Int32)(m_values.getLength() -1) ); +// buf.appendAscii( ", got " ); +// buf.append( index ); +// buf.appendAscii( ")" ); +// throw css::lang::IndexOutOfBoundsException( +// buf.makeStringAndClear(), *this ); +// } + +// Reference< XPropertySet > set; +// m_values[index] >>= set; +// Statics &st = getStatics(); +// OUString name; +// set->getPropertyValue( st.NAME ) >>= name; + +// OUStringBuffer update( 128 ); +// update.appendAscii( "ALTER TABLE ONLY"); +// bufferQuoteQualifiedIdentifier( update, m_schemaName, m_tableName ); +// update.appendAscii( "DROP COLUMN" ); +// bufferQuoteIdentifier( update, name ); +// Reference< XStatement > stmt = m_origin->createStatement( ); +// DisposeGuard disposeIt( stmt ); +// stmt->executeUpdate( update.makeStringAndClear() ); + +} + + +Reference< css::beans::XPropertySet > KeyColumns::createDataDescriptor() +{ + return new KeyColumnDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > KeyColumns::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const Sequence< OUString > &columnNames , + const Sequence< OUString > &foreignColumnNames ) +{ + rtl::Reference<KeyColumns> pKeyColumns = new KeyColumns( + refMutex, origin, pSettings, schemaName, tableName, columnNames, foreignColumnNames ); + pKeyColumns->refresh(); + + return pKeyColumns; +} + + +KeyColumnDescriptors::KeyColumnDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) + : Container( refMutex, origin, pSettings, "KEY_COLUMN" ) +{} + +Reference< css::beans::XPropertySet > KeyColumnDescriptors::createDataDescriptor() +{ + return new KeyColumnDescriptor( m_xMutex, m_origin, m_pSettings ); +} +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkeycolumns.hxx b/connectivity/source/drivers/postgresql/pq_xkeycolumns.hxx new file mode 100644 index 000000000..0c56fd189 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkeycolumns.hxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ + +class KeyColumns final : public Container +{ + OUString m_schemaName; + OUString m_tableName; + css::uno::Sequence< OUString > m_columnNames; + css::uno::Sequence< OUString > m_foreignColumnNames; + +public: // instances KeyColumns 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const css::uno::Sequence< OUString > &keyColumns, + const css::uno::Sequence< OUString > &foreignColumnNames ); + +private: + KeyColumns( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const css::uno::Sequence< OUString > &keyColumns, + const css::uno::Sequence< OUString > &foreignColumnNames); + + virtual ~KeyColumns() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +public: // XDrop + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + + +class KeyColumnDescriptors : public Container +{ +public: + KeyColumnDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkeys.cxx b/connectivity/source/drivers/postgresql/pq_xkeys.cxx new file mode 100644 index 000000000..dced2bc9b --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkeys.cxx @@ -0,0 +1,294 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/config.h> + +#include <string_view> + +#include <sal/log.hxx> +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/KeyRule.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <o3tl/safeint.hxx> + +#include "pq_xkeys.hxx" +#include "pq_xkey.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + + +using css::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; + + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XParameters; +using com::sun::star::sdbc::XPreparedStatement; + +namespace pq_sdbc_driver +{ + +Keys::Keys( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName) + : Container( refMutex, origin, pSettings, getStatics().KEY ), + m_schemaName( schemaName ), + m_tableName( tableName ) +{} + +Keys::~Keys() +{} + +static sal_Int32 string2keytype( std::u16string_view type ) +{ + sal_Int32 ret = css::sdbcx::KeyType::UNIQUE; + if ( type == u"p" ) + ret = css::sdbcx::KeyType::PRIMARY; + else if ( type == u"f" ) + ret = css::sdbcx::KeyType::FOREIGN; + return ret; +} + +static sal_Int32 string2keyrule( std::u16string_view rule ) +{ + sal_Int32 ret = css::sdbc::KeyRule::NO_ACTION; + if( rule == u"r" ) + ret = css::sdbc::KeyRule::RESTRICT; + else if( rule == u"c" ) + ret = css::sdbc::KeyRule::CASCADE; + else if( rule == u"n" ) + ret = css::sdbc::KeyRule::SET_NULL; + else if( rule == u"d" ) + ret = css::sdbc::KeyRule::SET_DEFAULT; + return ret; +} + +void Keys::refresh() +{ + try + { + SAL_INFO("connectivity.postgresql", "sdbcx.Keys get refreshed for table " << m_schemaName << "." << m_tableName); + + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + + Int2StringMap mainMap; + fillAttnum2attnameMap( mainMap, m_origin, m_schemaName, m_tableName ); + + Reference< XPreparedStatement > stmt = m_origin->prepareStatement( + "SELECT conname, " // 1 + "contype, " // 2 + "confupdtype, " // 3 + "confdeltype, " // 4 + "class2.relname, " // 5 + "nmsp2.nspname, " // 6 + "conkey," // 7 + "confkey " // 8 + "FROM pg_constraint INNER JOIN pg_class ON conrelid = pg_class.oid " + "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid " + "LEFT JOIN pg_class AS class2 ON confrelid = class2.oid " + "LEFT JOIN pg_namespace AS nmsp2 ON class2.relnamespace=nmsp2.oid " + "WHERE pg_class.relname = ? AND pg_namespace.nspname = ?" ); + + Reference< XParameters > paras( stmt, UNO_QUERY ); + paras->setString( 1 , m_tableName ); + paras->setString( 2 , m_schemaName ); + Reference< XResultSet > rs = stmt->executeQuery(); + + Reference< XRow > xRow( rs , UNO_QUERY ); + + String2IntMap map; + m_values.clear(); + int keyIndex = 0; + while( rs->next() ) + { + rtl::Reference<Key> pKey = + new Key( m_xMutex, m_origin, m_pSettings , m_schemaName, m_tableName ); + Reference< css::beans::XPropertySet > prop = pKey; + + pKey->setPropertyValue_NoBroadcast_public( + st.NAME, Any( xRow->getString( 1 ) ) ); + sal_Int32 keyType = string2keytype( xRow->getString(2) ); + pKey->setPropertyValue_NoBroadcast_public( st.TYPE, Any( keyType ) ); + pKey->setPropertyValue_NoBroadcast_public( + st.UPDATE_RULE, Any( string2keyrule( xRow->getString(3) ) ) ); + pKey->setPropertyValue_NoBroadcast_public( + st.DELETE_RULE, Any( string2keyrule( xRow->getString(4) ) ) ); + pKey->setPropertyValue_NoBroadcast_public( + st.PRIVATE_COLUMNS, + Any( + convertMappedIntArray2StringArray( + mainMap, + string2intarray( xRow->getString( 7 ) ) ) ) ); + + if( css::sdbcx::KeyType::FOREIGN == keyType ) + { + OUString buf = xRow->getString( 6 ) + "." + xRow->getString( 5 ); + pKey->setPropertyValue_NoBroadcast_public( + st.REFERENCED_TABLE, Any( buf ) ); + + Int2StringMap foreignMap; + fillAttnum2attnameMap( foreignMap, m_origin, xRow->getString(6), xRow->getString(5)); + pKey->setPropertyValue_NoBroadcast_public( + st.PRIVATE_FOREIGN_COLUMNS, + Any( + convertMappedIntArray2StringArray( + foreignMap, + string2intarray( xRow->getString(8) ) ) ) ); + } + + + { + map[ xRow->getString( 1 ) ] = keyIndex; + m_values.push_back( Any( prop ) ); + ++keyIndex; + } + } + m_name2index.swap( map ); + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + fire( RefreshedBroadcaster( *this ) ); +} + + +void Keys::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + OUStringBuffer buf( 128 ); + buf.append( "ALTER TABLE " ); + bufferQuoteQualifiedIdentifier( buf, m_schemaName, m_tableName, m_pSettings ); + buf.append( " ADD " ); + bufferKey2TableConstraint( buf, descriptor, m_pSettings ); + + Reference< XStatement > stmt = + m_origin->createStatement(); + stmt->executeUpdate( buf.makeStringAndClear() ); +} + + +void Keys::dropByIndex( sal_Int32 index ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || o3tl::make_unsigned(index) >= m_values.size() ) + { + throw css::lang::IndexOutOfBoundsException( + "TABLES: Index out of range (allowed 0 to " + OUString::number(m_values.size() -1) + + ", got " + OUString::number( index ) + ")", + *this ); + } + + + Reference< XPropertySet > set; + m_values[index] >>= set; + + OUStringBuffer buf( 128 ); + buf.append( "ALTER TABLE " ); + bufferQuoteQualifiedIdentifier( buf, m_schemaName, m_tableName, m_pSettings ); + buf.append( " DROP CONSTRAINT " ); + bufferQuoteIdentifier( buf, extractStringProperty( set , getStatics().NAME ), m_pSettings ); + m_origin->createStatement()->executeUpdate( buf.makeStringAndClear() ); + + + Container::dropByIndex( index ); +} + + +css::uno::Reference< css::beans::XPropertySet > Keys::createDataDescriptor() +{ + return new KeyDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XIndexAccess > Keys::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString & schemaName, + const OUString & tableName) +{ + rtl::Reference<Keys> pKeys = new Keys( refMutex, origin, pSettings, schemaName, tableName ); + pKeys->refresh(); + + return pKeys; +} + +KeyDescriptors::KeyDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings) + : Container( refMutex, origin, pSettings, getStatics().KEY ) +{} + +Reference< css::container::XIndexAccess > KeyDescriptors::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings) +{ + return new KeyDescriptors( refMutex, origin, pSettings ); +} + +css::uno::Reference< css::beans::XPropertySet > KeyDescriptors::createDataDescriptor() +{ + return new KeyDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkeys.hxx b/connectivity/source/drivers/postgresql/pq_xkeys.hxx new file mode 100644 index 000000000..fe1afef35 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkeys.hxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ +class Keys final : public Container +{ + OUString m_schemaName; + OUString m_tableName; + +public: // instances Columns 'exception safe' + static css::uno::Reference< css::container::XIndexAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + +private: + Keys( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + + virtual ~Keys() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +public: // XDrop + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + + +class KeyDescriptors final : public Container +{ +public: // instances Columns 'exception safe' + static css::uno::Reference< css::container::XIndexAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +private: + KeyDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xtable.cxx b/connectivity/source/drivers/postgresql/pq_xtable.cxx new file mode 100644 index 000000000..4a659ffb9 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xtable.cxx @@ -0,0 +1,394 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <com/sun/star/sdbc/SQLException.hpp> + +#include "pq_xtable.hxx" +#include "pq_xtables.hxx" +#include "pq_xviews.hxx" +#include "pq_xindexes.hxx" +#include "pq_xkeys.hxx" +#include "pq_xcolumns.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +using osl::MutexGuard; + +using com::sun::star::container::XNameAccess; +using com::sun::star::container::XIndexAccess; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ +Table::Table( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.table.implName, + getStatics().refl.table.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.table.pProps ) +{} + +Reference< XPropertySet > Table::createDataDescriptor( ) +{ + rtl::Reference<TableDescriptor> pTable = new TableDescriptor( + m_xMutex, m_conn, m_pSettings ); + pTable->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pTable ); +} + +Reference< XNameAccess > Table::getColumns( ) +{ + if( ! m_columns.is() ) + { + m_columns = Columns::create( + m_xMutex, + m_conn, + m_pSettings, + extractStringProperty( this, getStatics().SCHEMA_NAME ), + extractStringProperty( this, getStatics().NAME ), + &m_pColumns); + } + return m_columns; +} + +Reference< XNameAccess > Table::getIndexes() +{ + if( ! m_indexes.is() ) + { + m_indexes = ::pq_sdbc_driver::Indexes::create( + m_xMutex, + m_conn, + m_pSettings, + extractStringProperty( this, getStatics().SCHEMA_NAME ), + extractStringProperty( this, getStatics().NAME ) ); + } + return m_indexes; +} + +Reference< XIndexAccess > Table::getKeys( ) +{ + if( ! m_keys.is() ) + { + m_keys = ::pq_sdbc_driver::Keys::create( + m_xMutex, + m_conn, + m_pSettings, + extractStringProperty( this, getStatics().SCHEMA_NAME ), + extractStringProperty( this, getStatics().NAME ) ); + } + return m_keys; +} + +void Table::rename( const OUString& newName ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + + OUString oldName = extractStringProperty(this,st.NAME ); + OUString schema = extractStringProperty(this,st.SCHEMA_NAME ); + OUString fullOldName = concatQualified( schema, oldName ); + + OUString newTableName; + OUString newSchemaName; + // OOo2.0 passes schema + dot + new-table-name while + // OO1.1.x passes new Name without schema + // in case name contains a dot, it is interpreted as schema.tablename + if( newName.indexOf( '.' ) >= 0 ) + { + splitConcatenatedIdentifier( newName, &newSchemaName, &newTableName ); + } + else + { + newTableName = newName; + newSchemaName = schema; + } + OUString fullNewName = concatQualified( newSchemaName, newTableName ); + + if( extractStringProperty( this, st.TYPE ) == st.VIEW && m_pSettings->views.is() ) + { + // maintain view list (really strange API !) + Any a = m_pSettings->pViewsImpl->getByName( fullOldName ); + Reference< css::sdbcx::XRename > Xrename; + a >>= Xrename; + if( Xrename.is() ) + { + Xrename->rename( newName ); + setPropertyValue_NoBroadcast_public( st.SCHEMA_NAME, Any(newSchemaName) ); + } + } + else + { + if( newSchemaName != schema ) + { + // try new schema name first + try + { + OUStringBuffer buf(128); + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier(buf, schema, oldName, m_pSettings ); + buf.append( "SET SCHEMA" ); + bufferQuoteIdentifier( buf, newSchemaName, m_pSettings ); + Reference< XStatement > statement = m_conn->createStatement(); + statement->executeUpdate( buf.makeStringAndClear() ); + setPropertyValue_NoBroadcast_public( st.SCHEMA_NAME, Any(newSchemaName) ); + disposeNoThrow( statement ); + schema = newSchemaName; + } + catch( css::sdbc::SQLException &e ) + { + OUString buf( e.Message + "(NOTE: Only postgresql server >= V8.1 support changing a table's schema)" ); + e.Message = buf; + throw; + } + + } + if( newTableName != oldName ) // might also be just the change of a schema name + { + OUStringBuffer buf(128); + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier(buf, schema, oldName, m_pSettings ); + buf.append( "RENAME TO" ); + bufferQuoteIdentifier( buf, newTableName, m_pSettings ); + Reference< XStatement > statement = m_conn->createStatement(); + statement->executeUpdate( buf.makeStringAndClear() ); + disposeNoThrow( statement ); + } + } + setPropertyValue_NoBroadcast_public( st.NAME, Any(newTableName) ); + // inform the container of the name change ! + if( m_pSettings->tables.is() ) + { + m_pSettings->pTablesImpl->rename( fullOldName, fullNewName ); + } +} + +void Table::alterColumnByName( + const OUString& colName, + const Reference< XPropertySet >& descriptor ) +{ + Reference< css::container::XNameAccess > columns = getColumns(); + + OUString newName = extractStringProperty(descriptor, getStatics().NAME ); + ::pq_sdbc_driver::alterColumnByDescriptor( + extractStringProperty( this, getStatics().SCHEMA_NAME ), + extractStringProperty( this, getStatics().NAME ), + m_pSettings, + m_conn->createStatement(), + Reference< css::beans::XPropertySet>( columns->getByName( colName ), UNO_QUERY) , + descriptor ); + + if( colName != newName ) + { +// m_pColumns->rename( colName, newName ); + m_pColumns->refresh(); + } +} + +void Table::alterColumnByIndex( + sal_Int32 index, + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) +{ + Reference< css::container::XIndexAccess > columns( getColumns(), UNO_QUERY ); + Reference< css::beans::XPropertySet> column(columns->getByIndex( index ), UNO_QUERY ); + ::pq_sdbc_driver::alterColumnByDescriptor( + extractStringProperty( this, getStatics().SCHEMA_NAME ), + extractStringProperty( this, getStatics().NAME ), + m_pSettings, + m_conn->createStatement(), + column, + descriptor ); + m_pColumns->refresh(); +} + +Sequence<Type > Table::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XIndexesSupplier>::get(), + cppu::UnoType<css::sdbcx::XKeysSupplier>::get(), + cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(), + cppu::UnoType<css::sdbcx::XRename>::get(), + cppu::UnoType<css::sdbcx::XAlterTable>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> Table::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any Table::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XIndexesSupplier * > ( this ), + static_cast< css::sdbcx::XKeysSupplier * > ( this ), + static_cast< css::sdbcx::XColumnsSupplier * > ( this ), + static_cast< css::sdbcx::XRename * > ( this ), + static_cast< css::sdbcx::XAlterTable * > ( this ) + ); + return ret; +} + +OUString Table::getName( ) +{ + Statics & st = getStatics(); + return concatQualified( + extractStringProperty( this, st.SCHEMA_NAME ), + extractStringProperty( this, st.NAME ) ); +} + +void Table::setName( const OUString& aName ) +{ + rename( aName ); +} + + +TableDescriptor::TableDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.tableDescriptor.implName, + getStatics().refl.tableDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.tableDescriptor.pProps ) +{ +} + +Reference< XNameAccess > TableDescriptor::getColumns( ) +{ + if( ! m_columns.is() ) + { + m_columns = new ColumnDescriptors(m_xMutex, m_conn, m_pSettings ); + } + return m_columns; +} + +Reference< XNameAccess > TableDescriptor::getIndexes() +{ + if( ! m_indexes.is() ) + { + m_indexes = ::pq_sdbc_driver::IndexDescriptors::create( + m_xMutex, + m_conn, + m_pSettings); + } + return m_indexes; +} + +Reference< XIndexAccess > TableDescriptor::getKeys( ) +{ + if( ! m_keys.is() ) + { + m_keys = ::pq_sdbc_driver::KeyDescriptors::create( + m_xMutex, + m_conn, + m_pSettings ); + } + return m_keys; +} + + +Sequence<Type > TableDescriptor::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XIndexesSupplier>::get(), + cppu::UnoType<css::sdbcx::XKeysSupplier>::get(), + cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> TableDescriptor::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any TableDescriptor::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XIndexesSupplier * > ( this ), + static_cast< css::sdbcx::XKeysSupplier * > ( this ), + static_cast< css::sdbcx::XColumnsSupplier * > ( this )); + return ret; +} + + +Reference< XPropertySet > TableDescriptor::createDataDescriptor( ) +{ + rtl::Reference<TableDescriptor> pTable = new TableDescriptor( + m_xMutex, m_conn, m_pSettings ); + + // TODO: deep copies + pTable->m_values = m_values; + + return Reference< XPropertySet > ( pTable ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xtable.hxx b/connectivity/source/drivers/postgresql/pq_xtable.hxx new file mode 100644 index 000000000..7c8ca73f5 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xtable.hxx @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XIndexesSupplier.hpp> +#include <com/sun/star/sdbcx/XKeysSupplier.hpp> +#include <com/sun/star/sdbcx/XRename.hpp> +#include <com/sun/star/sdbcx/XAlterTable.hpp> + +#include "pq_xbase.hxx" +#include "pq_xcolumns.hxx" + +namespace pq_sdbc_driver +{ + +class Columns; + +class Table : public ReflectionBase, + public css::sdbcx::XColumnsSupplier, + public css::sdbcx::XIndexesSupplier, + public css::sdbcx::XKeysSupplier, + public css::sdbcx::XRename, + public css::sdbcx::XAlterTable +{ + css::uno::Reference< css::container::XNameAccess > m_columns; + css::uno::Reference< css::container::XIndexAccess > m_keys; + css::uno::Reference< css::container::XNameAccess > m_indexes; + rtl::Reference<Columns> m_pColumns; + +public: + Table( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + + // XInterface + virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + + // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + + // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + + // XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getColumns( ) override; + + // XIndexesSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getIndexes( ) override; + + // XKeysSupplier + virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL + getKeys( ) override; + + // XRename + virtual void SAL_CALL rename( const OUString& newName ) override; + + // XAlterTable + virtual void SAL_CALL alterColumnByName( + const OUString& colName, + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + + virtual void SAL_CALL alterColumnByIndex( + sal_Int32 index, + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + + // XNamed + virtual OUString SAL_CALL getName( ) override; + virtual void SAL_CALL setName( const OUString& aName ) override; +}; + + +class TableDescriptor + : public ReflectionBase, + public css::sdbcx::XColumnsSupplier, + public css::sdbcx::XIndexesSupplier, + public css::sdbcx::XKeysSupplier +{ + css::uno::Reference< css::container::XNameAccess > m_columns; + css::uno::Reference< css::container::XIndexAccess > m_keys; + css::uno::Reference< css::container::XNameAccess > m_indexes; + +public: + TableDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XInterface + virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getColumns( ) override; + +public: // XIndexesSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getIndexes( ) override; + +public: // XKeysSupplier + virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL + getKeys( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; +}; + + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xtables.cxx b/connectivity/source/drivers/postgresql/pq_xtables.cxx new file mode 100644 index 000000000..423ec81f2 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xtables.cxx @@ -0,0 +1,369 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <o3tl/safeint.hxx> + +#include "pq_xtables.hxx" +#include "pq_xviews.hxx" +#include "pq_xtable.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; + +using com::sun::star::container::XEnumerationAccess; +using com::sun::star::container::XEnumeration; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XDatabaseMetaData; +using com::sun::star::sdbcx::XColumnsSupplier; +using com::sun::star::sdbcx::XKeysSupplier; + +namespace pq_sdbc_driver +{ +Tables::Tables( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) + : Container( refMutex, origin, pSettings, getStatics().TABLE ) +{} + +Tables::~Tables() +{} + +void Tables::refresh() +{ + try + { + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + + Reference< XDatabaseMetaData > meta = m_origin->getMetaData(); + + Reference< XResultSet > rs = + meta->getTables( Any(), st.cPERCENT,st.cPERCENT, Sequence< OUString > () ); + + Reference< XRow > xRow( rs , UNO_QUERY ); + + String2IntMap map; + + m_values.clear(); + sal_Int32 tableIndex = 0; + while( rs->next() ) + { + // if creating all these tables turns out to have too bad performance, we might + // instead offer a factory interface + rtl::Reference<Table> pTable = + new Table( m_xMutex, m_origin, m_pSettings ); + Reference< css::beans::XPropertySet > prop = pTable; + + OUString name = xRow->getString( TABLE_INDEX_NAME+1); + OUString schema = xRow->getString( TABLE_INDEX_SCHEMA+1); + pTable->setPropertyValue_NoBroadcast_public( + st.CATALOG_NAME , Any(xRow->getString( TABLE_INDEX_CATALOG+1) ) ); + pTable->setPropertyValue_NoBroadcast_public( st.NAME , Any( name ) ); + pTable->setPropertyValue_NoBroadcast_public( st.SCHEMA_NAME , Any( schema )); + pTable->setPropertyValue_NoBroadcast_public( + st.TYPE , Any( xRow->getString( TABLE_INDEX_TYPE+1) ) ); + pTable->setPropertyValue_NoBroadcast_public( + st.DESCRIPTION , Any( xRow->getString( TABLE_INDEX_REMARKS+1) ) ); + pTable->setPropertyValue_NoBroadcast_public( + st.PRIVILEGES , + Any( sal_Int32( css::sdbcx::Privilege::SELECT | + css::sdbcx::Privilege::INSERT | + css::sdbcx::Privilege::UPDATE | + css::sdbcx::Privilege::DELETE | + css::sdbcx::Privilege::READ | + css::sdbcx::Privilege::CREATE | + css::sdbcx::Privilege::ALTER | + css::sdbcx::Privilege::REFERENCE | + css::sdbcx::Privilege::DROP ) ) ); + + { + m_values.push_back( Any( prop ) ); + map[ schema + "." + name ] = tableIndex; + ++tableIndex; + } + } + m_name2index.swap( map ); + } + catch ( const css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + fire( RefreshedBroadcaster( *this ) ); +} + + +static void appendColumnList( + OUStringBuffer &buf, const Reference< XColumnsSupplier > & columnSupplier, ConnectionSettings *settings ) +{ + if( !columnSupplier.is() ) + return; + + Reference< XEnumerationAccess > columns( columnSupplier->getColumns(),UNO_QUERY ); + if( !columns.is() ) + return; + + Reference< XEnumeration > xEnum( columns->createEnumeration() ); + bool first = true; + Statics & st = getStatics(); + + while( xEnum.is() && xEnum->hasMoreElements() ) + { + if( first ) + { + first = false; + } + else + { + buf.append( ", " ); + } + Reference< XPropertySet > column( xEnum->nextElement(), UNO_QUERY ); + OUString name = extractStringProperty( column, st.NAME ); + OUString defaultValue = extractStringProperty( column, st.DEFAULT_VALUE ); + bool isNullable = extractBoolProperty( column, st.IS_NULLABLE ); + bool isAutoIncrement = extractBoolProperty( column, st.IS_AUTO_INCREMENT ); + + bufferQuoteIdentifier( buf, name, settings ); + + OUString type = sqltype2string( column ); + if( isAutoIncrement ) + { + sal_Int32 dataType = 0; + column->getPropertyValue( st.TYPE ) >>= dataType; + if( css::sdbc::DataType::INTEGER == dataType ) + { + buf.append( " serial "); + isNullable = false; + } + else if( css::sdbc::DataType::BIGINT == dataType ) + { + buf.append( " serial8 " ); + isNullable = false; + } + else + buf.append( type ); + } + else + { + buf.append( type ); + } + if( !defaultValue.isEmpty() ) + { + bufferQuoteConstant( buf, defaultValue, settings ); + } + + if( ! isNullable ) + buf.append( " NOT NULL " ); + + } +} + +static void appendKeyList( + OUStringBuffer & buf, const Reference< XKeysSupplier > &keySupplier, ConnectionSettings *settings ) +{ + if( !keySupplier.is() ) + return; + + Reference< XEnumerationAccess > keys( keySupplier->getKeys(), UNO_QUERY ); + if(keys.is() ) + { + Reference< XEnumeration > xEnum = keys->createEnumeration(); + while( xEnum.is() && xEnum->hasMoreElements() ) + { + buf.append( ", " ); + Reference< XPropertySet > key( xEnum->nextElement(), UNO_QUERY ); + bufferKey2TableConstraint( buf, key, settings ); + } + } +} + +void Tables::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Reference< XStatement > stmt = + m_origin->createStatement(); + + Statics &st = getStatics(); + OUString name,schema; + descriptor->getPropertyValue( st.SCHEMA_NAME ) >>= schema; + descriptor->getPropertyValue( st.NAME ) >>= name; + + TransactionGuard transaction( stmt ); + + OUStringBuffer buf( 128 ); + buf.append( "CREATE TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schema, name , m_pSettings); + buf.append( "(" ); + + // columns + Reference< XColumnsSupplier > supplier( descriptor, UNO_QUERY ); + appendColumnList( buf, supplier, m_pSettings ); + + appendKeyList( buf, Reference< XKeysSupplier >( descriptor, UNO_QUERY ), m_pSettings ); + + buf.append( ") " ); + // execute the creation ! + transaction.executeUpdate( buf.makeStringAndClear() ); + + // description... + OUString description = extractStringProperty( descriptor, st.DESCRIPTION ); + if( !description.isEmpty() ) + { + buf.truncate(); + buf.append( "COMMENT ON TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schema, name, m_pSettings ); + buf.append( "IS " ); + bufferQuoteConstant( buf, description, m_pSettings); + + transaction.executeUpdate( buf.makeStringAndClear() ); + } + + // column descriptions + if( supplier.is() ) + { + Reference< XEnumerationAccess > columns( supplier->getColumns(),UNO_QUERY ); + if( columns.is() ) + { + Reference< XEnumeration > xEnum( columns->createEnumeration() ); + while( xEnum.is() && xEnum->hasMoreElements() ) + { + Reference< XPropertySet > column( xEnum->nextElement(), UNO_QUERY ); + description = extractStringProperty( column,st.DESCRIPTION ); + if( !description.isEmpty() ) + { + buf.truncate(); + buf.append( "COMMENT ON COLUMN " ); + bufferQuoteQualifiedIdentifier( + buf, schema, name, extractStringProperty( column, st.NAME ), m_pSettings ); + buf.append( "IS " ); + bufferQuoteConstant( buf, description, m_pSettings ); + transaction.executeUpdate( buf.makeStringAndClear() ); + } + } + } + } + + transaction.commit(); + + disposeNoThrow( stmt ); + // TODO: cheaper recalculate +// Container::append( concatQualified( schema, name ), descriptor ); // maintain the lists + refresh(); +} + +void Tables::dropByIndex( sal_Int32 index ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || o3tl::make_unsigned(index) >= m_values.size() ) + { + throw css::lang::IndexOutOfBoundsException( + "TABLES: Index out of range (allowed 0 to " + OUString::number(m_values.size() -1) + + ", got " + OUString::number( index ) + ")", + *this ); + } + + Reference< XPropertySet > set; + m_values[index] >>= set; + Statics &st = getStatics(); + OUString name,schema; + set->getPropertyValue( st.SCHEMA_NAME ) >>= schema; + set->getPropertyValue( st.NAME ) >>= name; + if( extractStringProperty( set, st.TYPE ) == st.VIEW && m_pSettings->views.is() ) + { + m_pSettings->pViewsImpl->dropByName( concatQualified( schema, name ) ); + } + else + { + OUStringBuffer update( 128 ); + update.append( "DROP " ); + if( extractStringProperty( set, st.TYPE ) == st.VIEW ) + update.append( "VIEW " ); + else + update.append( "TABLE " ); + bufferQuoteQualifiedIdentifier( update, schema, name, m_pSettings ); + Reference< XStatement > stmt = m_origin->createStatement( ); + DisposeGuard dispGuard( stmt ); + stmt->executeUpdate( update.makeStringAndClear() ); + } + + Container::dropByIndex( index ); +} + + +css::uno::Reference< css::beans::XPropertySet > Tables::createDataDescriptor() +{ + return new TableDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > Tables::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + rtl::Reference<Tables> *ppTables) +{ + *ppTables = new Tables( refMutex, origin, pSettings ); + (*ppTables)->refresh(); + + return *ppTables; +} + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xtables.hxx b/connectivity/source/drivers/postgresql/pq_xtables.hxx new file mode 100644 index 000000000..9222db82c --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xtables.hxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <sal/config.h> + +#include <rtl/ref.hxx> + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ + +struct ConnectionSettings; + +class Tables : public Container +{ + +public: // instances Tables 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + rtl::Reference<Tables> * ppTables); + +protected: + Tables( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + + virtual ~Tables() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +public: // XDrop +// virtual void SAL_CALL dropByName( const OUString& elementName ) +// throw (css::sdbc::SQLException, +// css::container::NoSuchElementException, +// css::uno::RuntimeException); + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; + +protected: + using Container::disposing; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xuser.cxx b/connectivity/source/drivers/postgresql/pq_xuser.cxx new file mode 100644 index 000000000..4d0a01f63 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xuser.cxx @@ -0,0 +1,172 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <com/sun/star/sdbc/SQLException.hpp> + +#include "pq_xuser.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ + +User::User( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ) + : ReflectionBase( + getStatics().refl.user.implName, + getStatics().refl.user.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.user.pProps ) +{} + +Reference< XPropertySet > User::createDataDescriptor( ) +{ + rtl::Reference<UserDescriptor> pUser = new UserDescriptor( m_xMutex, m_conn, m_pSettings ); + pUser->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pUser ); +} + + +Sequence<Type > User::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XUser>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> User::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any User::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XUser * > ( this ) ); + return ret; +} + + +void User::changePassword( + const OUString&, const OUString& newPassword ) +{ + OUStringBuffer buf(128); + buf.append( "ALTER USER " ); + bufferQuoteIdentifier( buf, extractStringProperty( this, getStatics().NAME ), m_pSettings ); + buf.append( " PASSWORD " ); + bufferQuoteConstant( buf, newPassword, m_pSettings ); + Reference< XStatement > stmt = m_conn->createStatement(); + DisposeGuard guard( stmt ); + stmt->executeUpdate( buf.makeStringAndClear() ); +} + +sal_Int32 User::getPrivileges( const OUString& objName, sal_Int32 objType ) +{ + SAL_INFO("connectivity.postgresql", "User::getPrivileges[\"Name\"] got called for " << objName << "(type=" << objType << ")"); + // all privileges + return 0xffffffff; +} + +sal_Int32 User::getGrantablePrivileges( const OUString&, sal_Int32 ) +{ + // all privileges + return 0xffffffff; +} + +void User::grantPrivileges( const OUString&, sal_Int32, sal_Int32 ) +{ + throw css::sdbc::SQLException("pq_driver: privilege change not implemented yet", + *this, OUString(), 1, Any() ); +} + +void User::revokePrivileges( const OUString&, sal_Int32, sal_Int32 ) +{ + throw css::sdbc::SQLException("pq_driver: privilege change not implemented yet", + *this, OUString(), 1, Any() ); +} + + +UserDescriptor::UserDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ) + : ReflectionBase( + getStatics().refl.userDescriptor.implName, + getStatics().refl.userDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.userDescriptor.pProps ) +{} + +Reference< XPropertySet > UserDescriptor::createDataDescriptor( ) +{ + rtl::Reference<UserDescriptor> pUser = new UserDescriptor( m_xMutex, m_conn, m_pSettings ); + pUser->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pUser ); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xuser.hxx b/connectivity/source/drivers/postgresql/pq_xuser.hxx new file mode 100644 index 000000000..702787a67 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xuser.hxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <com/sun/star/sdbcx/XUser.hpp> + +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class User : public ReflectionBase, + public css::sdbcx::XUser +{ + +public: + User( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + + // XInterface + virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + + // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + + // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + + // XUser : XAuthorizable + virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override; + virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override; + virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override; + virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override; + virtual void SAL_CALL changePassword( const OUString& oldPassword, const OUString& newPassword ) override; +}; + +class UserDescriptor : public ReflectionBase +{ +public: + UserDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; +}; + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xusers.cxx b/connectivity/source/drivers/postgresql/pq_xusers.cxx new file mode 100644 index 000000000..08cdf2d1c --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xusers.cxx @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <o3tl/safeint.hxx> + +#include "pq_xusers.hxx" +#include "pq_xuser.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; + +using com::sun::star::container::NoSuchElementException; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XResultSet; + +namespace pq_sdbc_driver +{ +Users::Users( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) + : Container( refMutex, origin, pSettings, getStatics().USER ) +{} + +Users::~Users() +{} + +void Users::refresh() +{ + try + { + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + + Reference< XStatement > stmt = m_origin->createStatement(); + + Reference< XResultSet > rs = stmt->executeQuery( "SELECT usename FROM pg_shadow" ); + + Reference< XRow > xRow( rs , UNO_QUERY ); + + String2IntMap map; + + m_values.clear(); + sal_Int32 tableIndex = 0; + while( rs->next() ) + { + rtl::Reference<User> pUser = + new User( m_xMutex, m_origin, m_pSettings ); + Reference< css::beans::XPropertySet > prop = pUser; + + OUString name = xRow->getString( 1); + pUser->setPropertyValue_NoBroadcast_public( + st.NAME , Any(xRow->getString( TABLE_INDEX_CATALOG+1) ) ); + + { + m_values.push_back( Any( prop ) ); + map[ name ] = tableIndex; + ++tableIndex; + } + } + m_name2index.swap( map ); + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + fire( RefreshedBroadcaster( *this ) ); +} + + +void Users::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + OUStringBuffer update( 128 ); + update.append( "CREATE USER " ); + bufferQuoteIdentifier( update, extractStringProperty( descriptor, getStatics().NAME ), m_pSettings ); + update.append( " PASSWORD " ); + bufferQuoteConstant( update, extractStringProperty( descriptor, getStatics().PASSWORD ), m_pSettings ); + + Reference< XStatement > stmt = m_origin->createStatement( ); + DisposeGuard disposeGuard( stmt ); + stmt->executeUpdate( update.makeStringAndClear() ); +} + +void Users::dropByName( const OUString& elementName ) +{ + String2IntMap::const_iterator ii = m_name2index.find( elementName ); + if( ii == m_name2index.end() ) + { + throw css::container::NoSuchElementException( + "User " + elementName + " is unknown, so it can't be dropped", + *this ); + } + dropByIndex( ii->second ); +} + +void Users::dropByIndex( sal_Int32 index ) +{ + + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || o3tl::make_unsigned(index) >= m_values.size() ) + { + throw css::lang::IndexOutOfBoundsException( + "USERS: Index out of range (allowed 0 to " + + OUString::number( m_values.size() -1 ) + + ", got " + OUString::number( index ) + + ")", + *this ); + } + + Reference< XPropertySet > set; + m_values[index] >>= set; + OUString name; + set->getPropertyValue( getStatics().NAME ) >>= name; + + OUStringBuffer update( 128 ); + update.append( "DROP USER " ); + bufferQuoteIdentifier( update, name, m_pSettings ); + + Reference< XStatement > stmt = m_origin->createStatement( ); + DisposeGuard disposeGuard( stmt ); + stmt->executeUpdate( update.makeStringAndClear() ); +} + + +css::uno::Reference< css::beans::XPropertySet > Users::createDataDescriptor() +{ + return new UserDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > Users::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) +{ + rtl::Reference<Users> pUsers = new Users( refMutex, origin, pSettings ); + pUsers->refresh(); + + return pUsers; +} + +void Users::disposing() +{ +} + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xusers.hxx b/connectivity/source/drivers/postgresql/pq_xusers.hxx new file mode 100644 index 000000000..f95ec1749 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xusers.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ + +class Users final : public Container +{ + +public: // instances Tables 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +private: + Users( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + + virtual ~Users() override; + +public: + // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + + // XDrop + virtual void SAL_CALL dropByName( const OUString& elementName ) override; + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + + // XRefreshable + virtual void SAL_CALL refresh( ) override; + + // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; + +private: + virtual void SAL_CALL disposing() override; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xview.cxx b/connectivity/source/drivers/postgresql/pq_xview.cxx new file mode 100644 index 000000000..2b8f61be7 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xview.cxx @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <com/sun/star/sdbc/SQLException.hpp> + +#include "pq_xview.hxx" +#include "pq_xviews.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ + +View::View( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.view.implName, + getStatics().refl.view.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.view.pProps ) +{} + +Reference< XPropertySet > View::createDataDescriptor( ) +{ + rtl::Reference<ViewDescriptor> pView = new ViewDescriptor( + m_xMutex, m_conn, m_pSettings ); + pView->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pView ); +} + +void View::rename( const OUString& newName ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + + Statics & st = getStatics(); + + OUString oldName = extractStringProperty(this,st.NAME ); + OUString schema = extractStringProperty(this,st.SCHEMA_NAME ); + OUString fullOldName = concatQualified( schema, oldName ); + + OUString newTableName; + OUString newSchemaName; + // OOo2.0 passes schema + dot + new-table-name while + // OO1.1.x passes new Name without schema + // in case name contains a dot, it is interpreted as schema.tablename + if( newName.indexOf( '.' ) >= 0 ) + { + splitConcatenatedIdentifier( newName, &newSchemaName, &newTableName ); + } + else + { + newTableName = newName; + newSchemaName = schema; + } + OUString fullNewName = concatQualified( newSchemaName, newTableName ); + + if( schema != newSchemaName ) + { + try + { + OUStringBuffer buf(128); + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier(buf, schema, oldName, m_pSettings ); + buf.append( "SET SCHEMA" ); + bufferQuoteIdentifier( buf, newSchemaName, m_pSettings ); + Reference< XStatement > statement = m_conn->createStatement(); + statement->executeUpdate( buf.makeStringAndClear() ); + setPropertyValue_NoBroadcast_public( st.SCHEMA_NAME, Any(newSchemaName) ); + disposeNoThrow( statement ); + schema = newSchemaName; + } + catch( css::sdbc::SQLException &e ) + { + OUString buf( e.Message + "(NOTE: Only postgresql server >= V8.1 support changing a table's schema)" ); + e.Message = buf; + throw; + } + + } + if( oldName != newTableName ) + { + OUStringBuffer buf(128); + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schema, oldName, m_pSettings ); + buf.append( "RENAME TO" ); + bufferQuoteIdentifier( buf, newTableName, m_pSettings ); + Reference< XStatement > statement = m_conn->createStatement(); + statement->executeUpdate( buf.makeStringAndClear() ); + setPropertyValue_NoBroadcast_public( st.NAME, Any(newTableName) ); + } + + // inform the container of the name change ! + if( m_pSettings->views.is() ) + { + m_pSettings->pViewsImpl->rename( fullOldName, fullNewName ); + } +} + +Sequence<Type > View::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XRename>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> View::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any View::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XRename * > ( this ) + ); + return ret; +} + +OUString View::getName( ) +{ + Statics & st = getStatics(); + return concatQualified( + extractStringProperty( this, st.SCHEMA_NAME ), + extractStringProperty( this, st.NAME ) ); +} + +void View::setName( const OUString& aName ) +{ + rename( aName ); +} + + +ViewDescriptor::ViewDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.viewDescriptor.implName, + getStatics().refl.viewDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.viewDescriptor.pProps ) +{} + +Reference< XPropertySet > ViewDescriptor::createDataDescriptor( ) +{ + rtl::Reference<ViewDescriptor> pView = new ViewDescriptor( + m_xMutex, m_conn, m_pSettings ); + pView->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pView ); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xview.hxx b/connectivity/source/drivers/postgresql/pq_xview.hxx new file mode 100644 index 000000000..f68b5535a --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xview.hxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <com/sun/star/sdbcx/XRename.hpp> + +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ +class View : public ReflectionBase, + public css::sdbcx::XRename +{ +public: + View( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + + // XInterface + virtual void SAL_CALL acquire() noexcept override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() noexcept override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + + // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + + // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + + // XRename + virtual void SAL_CALL rename( const OUString& newName ) override; + + // XNamed + virtual OUString SAL_CALL getName( ) override; + virtual void SAL_CALL setName( const OUString& aName ) override; + +}; + + +class ViewDescriptor : public ReflectionBase +{ +public: + ViewDescriptor( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + + // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; +}; + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xviews.cxx b/connectivity/source/drivers/postgresql/pq_xviews.cxx new file mode 100644 index 000000000..1f5b6c4fa --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xviews.cxx @@ -0,0 +1,219 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <o3tl/safeint.hxx> + +#include "pq_xviews.hxx" +#include "pq_xview.hxx" +#include "pq_xtables.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; + +using com::sun::star::container::NoSuchElementException; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XResultSet; + + +namespace pq_sdbc_driver +{ +Views::Views( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) + : Container( refMutex, origin, pSettings, getStatics().VIEW ) +{} + +Views::~Views() +{} + +void Views::refresh() +{ + try + { + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + + Reference< XStatement > stmt = m_origin->createStatement(); + + Reference< XResultSet > rs = stmt->executeQuery("SELECT " + "DISTINCT ON( pg_namespace.nspname, relname) " // needed because of duplicates + "pg_namespace.nspname," // 1 + "relname," // 2 + "pg_get_viewdef(ev_class) " // 3 + "FROM pg_namespace, pg_class, pg_rewrite " + "WHERE pg_namespace.oid = relnamespace " + "AND pg_class.oid = ev_class " + "AND relkind=\'v\'" ); + + Reference< XRow > xRow( rs , UNO_QUERY ); + + m_values.clear(); + String2IntMap map; + sal_Int32 viewIndex = 0; + + while( rs->next() ) + { + OUString table, schema, command; + schema = xRow->getString( 1 ); + table = xRow->getString( 2 ); + command = xRow->getString( 3 ); + + rtl::Reference<View> pView = new View (m_xMutex, m_origin, m_pSettings ); + Reference< css::beans::XPropertySet > prop = pView; + + pView->setPropertyValue_NoBroadcast_public(st.NAME , Any(table) ); + pView->setPropertyValue_NoBroadcast_public(st.SCHEMA_NAME, Any(schema) ); + pView->setPropertyValue_NoBroadcast_public(st.COMMAND, Any(command) ); + + { + m_values.push_back( Any( prop ) ); + map[ schema + "." + table ] = viewIndex; + ++viewIndex; + } + } + m_name2index.swap( map ); + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + fire( RefreshedBroadcaster( *this ) ); +} + + +void Views::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + Statics &st = getStatics(); + OUString name,schema,command; + descriptor->getPropertyValue( st.SCHEMA_NAME ) >>= schema; + descriptor->getPropertyValue( st.NAME ) >>= name; + descriptor->getPropertyValue( st.COMMAND ) >>= command; + + Reference< XStatement > stmt = m_origin->createStatement(); + + OUStringBuffer buf( 128 ); + + buf.append( "CREATE VIEW "); + bufferQuoteQualifiedIdentifier( buf, schema, name, m_pSettings ); + buf.append(" AS " + command ); + + stmt->executeUpdate( buf.makeStringAndClear() ); + + disposeNoThrow( stmt ); + refresh(); + if( m_pSettings->tables.is() ) + { + m_pSettings->pTablesImpl->refresh(); + } +} + +void Views::dropByName( const OUString& elementName ) +{ + String2IntMap::const_iterator ii = m_name2index.find( elementName ); + if( ii == m_name2index.end() ) + { + throw css::container::NoSuchElementException( + "View " + elementName + " is unknown, so it can't be dropped", *this ); + } + dropByIndex( ii->second ); +} + +void Views::dropByIndex( sal_Int32 index ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || o3tl::make_unsigned(index) >= m_values.size() ) + { + throw css::lang::IndexOutOfBoundsException( + "VIEWS: Index out of range (allowed 0 to " + OUString::number(m_values.size() -1) + + ", got " + OUString::number( index ) + ")", + *this ); + } + + Reference< XPropertySet > set; + m_values[index] >>= set; + Statics &st = getStatics(); + OUString name,schema; + set->getPropertyValue( st.SCHEMA_NAME ) >>= schema; + set->getPropertyValue( st.NAME ) >>= name; + + Reference< XStatement > stmt = m_origin->createStatement( ); + + stmt->executeUpdate( "DROP VIEW \"" + schema + "\".\"" + name + "\"" ); +} + + +css::uno::Reference< css::beans::XPropertySet > Views::createDataDescriptor() +{ + return new ViewDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > Views::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + rtl::Reference<Views> *ppViews) +{ + *ppViews = new Views( refMutex, origin, pSettings ); + (*ppViews)->refresh(); + + return *ppViews; +} + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xviews.hxx b/connectivity/source/drivers/postgresql/pq_xviews.hxx new file mode 100644 index 000000000..04137b686 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xviews.hxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + ************************************************************************/ + +#pragma once + +#include <sal/config.h> + +#include <rtl/ref.hxx> + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ + +struct ConnectionSettings; + +class Views : public Container +{ + +public: // instances Views 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + rtl::Reference<Views> *ppViews ); + +protected: + Views( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings); + + virtual ~Views() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +public: // XDrop + virtual void SAL_CALL dropByName( const OUString& elementName ) override; + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; + +protected: + using Container::disposing; + +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |