Files
libreoffice/connectivity/source/drivers/postgresql/pq_baseresultset.cxx
2011-11-17 21:15:13 +01:00

743 lines
22 KiB
C++

/*************************************************************************
*
* $RCSfile: pq_baseresultset.cxx,v $
*
* $Revision: 1.1.2.4 $
*
* last change: $Author: jbu $ $Date: 2004/08/29 08:33:28 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* 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
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source License Version 1.1 (the "License"); You may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at http://www.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: Joerg Budischewski
*
* Copyright: 2000 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): Joerg Budischewski
*
*
************************************************************************/
#include <osl/thread.h>
#include <rtl/ustrbuf.hxx>
#include <cppuhelper/typeprovider.hxx>
#include <cppuhelper/queryinterface.hxx>
#include "pq_tools.hxx"
#include "pq_array.hxx"
#include "pq_statement.hxx"
#include "pq_baseresultset.hxx"
#include "pq_resultsetmetadata.hxx"
#include <com/sun/star/lang/DisposedException.hpp>
using osl::Mutex;
using osl::MutexGuard;
using rtl::OUString;
using rtl::OUStringToOString;
using rtl::OUStringBuffer;
using rtl::OString;
using com::sun::star::beans::XPropertySetInfo;
using com::sun::star::beans::XPropertySet;
using com::sun::star::beans::XMultiPropertySet;
using com::sun::star::beans::XFastPropertySet;
using com::sun::star::uno::Any;
using com::sun::star::uno::makeAny;
using com::sun::star::uno::Type;
using com::sun::star::uno::RuntimeException;
using com::sun::star::uno::Exception;
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::XWarningsSupplier;
using com::sun::star::sdbc::XCloseable;
using com::sun::star::sdbc::XStatement;
using com::sun::star::sdbc::XResultSet;
using com::sun::star::sdbc::XConnection;
using com::sun::star::sdbc::SQLException;
using com::sun::star::sdbc::XRow;
using com::sun::star::sdbc::XColumnLocate;
using com::sun::star::sdbc::XResultSetMetaData;
using com::sun::star::sdbc::XResultSetMetaDataSupplier;
using com::sun::star::beans::Property;
namespace pq_sdbc_driver
{
#define ASCII_STR(x) OUString( RTL_CONSTASCII_USTRINGPARAM( x ) )
static ::cppu::IPropertyArrayHelper & getResultSetPropertyArrayHelper()
{
static ::cppu::IPropertyArrayHelper *pArrayHelper;
if( ! pArrayHelper )
{
MutexGuard guard( Mutex::getGlobalMutex() );
if( ! pArrayHelper )
{
static Property aTable[] =
{
Property(
OUString( RTL_CONSTASCII_USTRINGPARAM("CursorName") ), 0,
::getCppuType( (OUString *)0) , 0 ),
Property(
OUString( RTL_CONSTASCII_USTRINGPARAM("EscapeProcessing") ), 0,
::getBooleanCppuType() , 0 ),
Property(
OUString( RTL_CONSTASCII_USTRINGPARAM("FetchDirection") ), 0,
::getCppuType( (sal_Int32 *)0) , 0 ),
Property(
OUString( RTL_CONSTASCII_USTRINGPARAM("FetchSize") ), 0,
::getCppuType( (sal_Int32 *)0) , 0 ),
Property(
OUString( RTL_CONSTASCII_USTRINGPARAM("ResultSetConcurrency") ), 0,
::getCppuType( (sal_Int32 *)0) , 0 ),
Property(
OUString( RTL_CONSTASCII_USTRINGPARAM("ResultSetType") ), 0,
::getCppuType( (sal_Int32 *)0) , 0 )
};
OSL_ASSERT( sizeof(aTable) / sizeof(Property) == BASERESULTSET_SIZE );
static ::cppu::OPropertyArrayHelper arrayHelper( aTable, BASERESULTSET_SIZE, sal_True );
pArrayHelper = &arrayHelper;
}
}
return *pArrayHelper;
}
BaseResultSet::BaseResultSet(
const ::rtl::Reference< RefCountedMutex > & refMutex,
const Reference< XInterface > & owner,
sal_Int32 rowCount,
sal_Int32 colCount,
const Reference< com::sun::star::script::XTypeConverter > & tc )
: OComponentHelper( refMutex->mutex ),
OPropertySetHelper( OComponentHelper::rBHelper ),
m_refMutex( refMutex ),
m_owner( owner ),
m_row( -1 ),
m_rowCount( rowCount ),
m_fieldCount( colCount ),
m_tc( tc )
{
POSTGRE_TRACE( "ctor BaseResultSet" );
}
BaseResultSet::~BaseResultSet()
{
POSTGRE_TRACE( "dtor BaseResultSet" );
}
Any BaseResultSet::queryInterface( const Type & reqType ) throw (RuntimeException)
{
Any ret;
ret = OComponentHelper::queryInterface( reqType );
if( ! ret.hasValue() )
ret = ::cppu::queryInterface( reqType,
static_cast< XResultSet * > ( this ),
static_cast< XResultSetMetaDataSupplier * > ( this ),
static_cast< XRow * > ( this ),
static_cast< XColumnLocate * > ( this ),
static_cast< XCloseable * > ( this ),
static_cast< XPropertySet * > ( this ),
static_cast< XMultiPropertySet * > ( this ),
static_cast< XFastPropertySet * > ( this ) );
return ret;
}
// 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() throw( RuntimeException )
{
static cppu::OTypeCollection *pCollection;
if( ! pCollection )
{
MutexGuard guard( osl::Mutex::getGlobalMutex() );
if( !pCollection )
{
static cppu::OTypeCollection collection(
getCppuType( (Reference< XResultSet> *) 0 ),
getCppuType( (Reference< XResultSetMetaDataSupplier> *) 0 ),
getCppuType( (Reference< XRow> *) 0 ),
getCppuType( (Reference< XColumnLocate> *) 0 ),
getCppuType( (Reference< XCloseable> *) 0 ),
getCppuType( (Reference< XPropertySet >*) 0 ),
getCppuType( (Reference< XFastPropertySet > *) 0 ),
getCppuType( (Reference< XMultiPropertySet > *) 0 ),
OComponentHelper::getTypes());
pCollection = &collection;
}
}
return pCollection->getTypes();
}
Sequence< sal_Int8> BaseResultSet::getImplementationId() throw( RuntimeException )
{
static cppu::OImplementationId *pId;
if( ! pId )
{
MutexGuard guard( osl::Mutex::getGlobalMutex() );
if( ! pId )
{
static cppu::OImplementationId id(sal_False);
pId = &id;
}
}
return pId->getImplementationId();
}
// Reference< XResultSetMetaData > BaseResultSet::getMetaData( ) throw (SQLException, RuntimeException)
// {
// ResultSetGuard guard(*this);
// checkClosed();
// return new ResultSetMetaData( m_refMutex, this, &m_result );
// }
sal_Bool BaseResultSet::next( ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
m_row ++;
return m_row < m_rowCount;
}
sal_Bool BaseResultSet::isBeforeFirst( ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
return m_row == -1;
}
sal_Bool BaseResultSet::isAfterLast( ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
return m_row >= m_rowCount;
}
sal_Bool BaseResultSet::isFirst( ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
return m_row == 0 && m_rowCount;
}
sal_Bool BaseResultSet::isLast( ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
return m_row >= 0 && m_row + 1 == m_rowCount;
}
void BaseResultSet::beforeFirst( ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
m_row = -1;
}
void BaseResultSet::afterLast( ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
m_row = m_rowCount;
}
sal_Bool BaseResultSet::first( ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
sal_Bool bRet = ( m_rowCount > 0 );
if( bRet )
m_row = 0;
return bRet;
}
sal_Bool BaseResultSet::last( ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
sal_Bool bRet = ( m_rowCount > 0 );
if( bRet )
m_row = m_rowCount -1;
return bRet;
}
sal_Int32 BaseResultSet::getRow( ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
return m_row +1;
}
sal_Bool BaseResultSet::absolute( sal_Int32 row ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
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 sal_True;
}
sal_Bool BaseResultSet::relative( sal_Int32 rows ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
m_row += rows;
if( m_row > m_rowCount )
m_row = m_rowCount;
else if ( m_row < -1 )
m_row = -1;
return sal_True;
}
sal_Bool BaseResultSet::previous( ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
sal_Bool bRet = ( m_row != -1 );
if( bRet )
m_row --;
return bRet;
}
void BaseResultSet::refreshRow( ) throw (SQLException, RuntimeException)
{
// TODO: not supported for now
}
sal_Bool BaseResultSet::rowUpdated( ) throw (SQLException, RuntimeException)
{
return sal_False;
}
sal_Bool BaseResultSet::rowInserted( ) throw (SQLException, RuntimeException)
{
return sal_False;
}
sal_Bool BaseResultSet::rowDeleted( ) throw (SQLException, RuntimeException)
{
return sal_False;
}
Reference< XInterface > BaseResultSet::getStatement() throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
return m_owner;
}
//----------------- XRow interface ----------------------------------------------------
sal_Bool BaseResultSet::wasNull( ) throw (SQLException, RuntimeException)
{
return m_wasNull;
}
Any BaseResultSet::convertTo( const Any & val , const Type & type )
{
Any aRet;
try
{
aRet = m_tc->convertTo( val , type );
}
catch( com::sun::star::lang::IllegalArgumentException & e )
{}
catch( com::sun::star::script::CannotConvertException & e )
{}
return aRet;
}
sal_Bool BaseResultSet::getBoolean( sal_Int32 columnIndex ) throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
checkColumnIndex( columnIndex );
checkRowIndex( sal_True /* must be on row */ );
sal_Bool b = sal_False;
OUString str = getString( columnIndex );
if( str.getLength() > 0 )
{
switch(str[0])
{
case '1':
case 't':
case 'T':
case 'y':
case 'Y':
return sal_True;
}
}
return sal_False;
}
sal_Int8 BaseResultSet::getByte( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
checkColumnIndex( columnIndex );
checkRowIndex( sal_True /* must be on row */ );
sal_Int8 b = 0;
convertTo( getValue( columnIndex ), getCppuType( &b )) >>= b;
return b;
}
sal_Int16 BaseResultSet::getShort( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
checkColumnIndex( columnIndex );
checkRowIndex( sal_True /* must be on row */ );
sal_Int16 i = 0;
convertTo( getValue( columnIndex ), getCppuType( &i )) >>= i;
return i;
}
OUString BaseResultSet::getString( sal_Int32 columnIndex ) throw (SQLException, RuntimeException)
{
MutexGuard guard(m_refMutex->mutex);
checkClosed();
checkColumnIndex( columnIndex );
checkRowIndex( sal_True /* must be on row */ );
OUString ret;
convertTo( getValue( columnIndex ), getCppuType( &ret ) ) >>= ret;
// printf( "BaseResultSet::getString() %s\n" , OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ).getStr() );
return ret;
}
sal_Int32 BaseResultSet::getInt( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
checkColumnIndex( columnIndex );
checkRowIndex( sal_True /* must be on row */ );
sal_Int32 i = 0;
convertTo( getValue( columnIndex ), getCppuType( &i )) >>= i;
return i;
}
sal_Int64 BaseResultSet::getLong( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
checkColumnIndex( columnIndex );
checkRowIndex( sal_True /* must be on row */ );
sal_Int64 i = 0;
convertTo( getValue( columnIndex ), getCppuType( &i )) >>= i;
return i;
}
float BaseResultSet::getFloat( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
checkColumnIndex( columnIndex );
checkRowIndex( sal_True /* must be on row */ );
float f = 0.;
convertTo( getValue( columnIndex ), getCppuType( &f )) >>= f;
return f;
}
double BaseResultSet::getDouble( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
checkColumnIndex( columnIndex );
double d = 0.;
convertTo( getValue( columnIndex ), getCppuType( &d )) >>= d;
return d;
}
Sequence< sal_Int8 > BaseResultSet::getBytes( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
MutexGuard guard( m_refMutex->mutex );
checkClosed();
checkColumnIndex( columnIndex );
checkRowIndex( sal_True /* must be on row */ );
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 = rtl::OUStringToOString( ustr, RTL_TEXTENCODING_ASCII_US );
size_t length;
char * res = (char*) PQunescapeBytea( (unsigned char *)val.getStr() , &length);
ret = Sequence< sal_Int8 > ( (sal_Int8*)res, length );
if( res )
free( res );
}
return ret;
}
::com::sun::star::util::Date BaseResultSet::getDate( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
return string2Date( getString( columnIndex ) );
}
::com::sun::star::util::Time BaseResultSet::getTime( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
return string2Time( getString( columnIndex ) );
}
::com::sun::star::util::DateTime BaseResultSet::getTimestamp( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
return string2DateTime( getString( columnIndex ) );
}
Reference< ::com::sun::star::io::XInputStream > BaseResultSet::getBinaryStream( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
return 0;
}
Reference< ::com::sun::star::io::XInputStream > BaseResultSet::getCharacterStream( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
return 0;
}
Any BaseResultSet::getObject(
sal_Int32 columnIndex,
const Reference< ::com::sun::star::container::XNameAccess >& typeMap )
throw (SQLException, RuntimeException)
{
return Any();
}
Reference< ::com::sun::star::sdbc::XRef > BaseResultSet::getRef( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
return Reference< com::sun::star::sdbc::XRef > ();
}
Reference< ::com::sun::star::sdbc::XBlob > BaseResultSet::getBlob( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
return Reference< com::sun::star::sdbc::XBlob > ();
}
Reference< ::com::sun::star::sdbc::XClob > BaseResultSet::getClob( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
return Reference< com::sun::star::sdbc::XClob > ();
}
Reference< ::com::sun::star::sdbc::XArray > BaseResultSet::getArray( sal_Int32 columnIndex )
throw (SQLException, RuntimeException)
{
return new Array( m_refMutex, 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 )
throw (IllegalArgumentException)
{
sal_Bool bRet;
switch( nHandle )
{
case BASERESULTSET_CURSOR_NAME:
{
OUString val;
bRet = ( rValue >>= val );
m_props[nHandle] = makeAny( val );
break;
}
case BASERESULTSET_ESCAPE_PROCESSING:
{
sal_Bool val;
bRet = ( rValue >>= val );
m_props[nHandle] = makeAny( 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] = makeAny( val );
break;
}
default:
{
OUStringBuffer buf(128);
buf.appendAscii( "pq_resultset: Invalid property handle (" );
buf.append( nHandle );
buf.appendAscii( ")" );
throw IllegalArgumentException( buf.makeStringAndClear(), *this, 2 );
}
}
return bRet;
}
void BaseResultSet::setFastPropertyValue_NoBroadcast(
sal_Int32 nHandle,const Any& rValue ) throw (Exception)
{
m_props[nHandle] = rValue;
}
void BaseResultSet::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
{
rValue = m_props[nHandle];
}
Reference < XPropertySetInfo > BaseResultSet::getPropertySetInfo()
throw(RuntimeException)
{
return OPropertySetHelper::createPropertySetInfo( getResultSetPropertyArrayHelper() );
}
void BaseResultSet::disposing()
{
close();
}
void BaseResultSet::checkColumnIndex(sal_Int32 index ) throw ( SQLException, RuntimeException )
{
if( index < 1 || index > m_fieldCount )
{
OUStringBuffer buf(128);
buf.appendAscii( "pq_resultset: index out of range (" );
buf.append( index );
buf.appendAscii( ", allowed range is 1 to " );
buf.append( m_fieldCount );
buf.appendAscii( ")" );
throw SQLException( buf.makeStringAndClear(), *this, OUString(), 1, Any() );
}
}
void BaseResultSet::checkRowIndex( sal_Bool mustBeOnValidRow )
{
OUStringBuffer buf( 128 );
buf.appendAscii( "pq_baseresultset: row index out of range, allowed is " );
if( mustBeOnValidRow )
{
if( m_row < 0 || m_row >= m_rowCount )
{
buf.appendAscii( "0 to " );
buf.append( ((sal_Int32)(m_rowCount -1)) );
buf.appendAscii( ", got " );
buf.append( m_row );
throw SQLException( buf.makeStringAndClear(), *this, OUString(),1, Any() );
}
}
else
{
if( m_row < -1 || m_row > m_rowCount )
{
buf.appendAscii( "-1 to " );
buf.append( m_rowCount );
buf.appendAscii( ", got " );
buf.append( m_row );
throw SQLException( buf.makeStringAndClear(), *this, OUString(),1, Any() );
}
}
}
}