<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: BookmarkSet.cxx,v $
 * $Revision: 1.21 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dbaccess.hxx"
#include "WrappedResultSet.hxx"
#include "core_resource.hxx"
#include "core_resource.hrc"
#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
#include <connectivity/dbexception.hxx>
#include <rtl/logfile.hxx>

#include <limits>

using namespace dbaccess;
using namespace ::connectivity;
using namespace ::dbtools;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sdbc;
//  using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;
//  using namespace ::cppu;
using namespace ::osl;

void WrappedResultSet::construct(const Reference< XResultSet>& _xDriverSet,const ::rtl::OUString& i_sRowSetFilter)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::construct" );
    OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
    m_xUpd.set(_xDriverSet,UNO_QUERY_THROW);
    m_xRowLocate.set(_xDriverSet,UNO_QUERY_THROW);
    m_xUpdRow.set(_xDriverSet,UNO_QUERY_THROW);
}
// -----------------------------------------------------------------------------
Any SAL_CALL WrappedResultSet::getBookmark() throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::getBookmark" );
    if ( m_xRowLocate.is() )
    {
        return m_xRowLocate->getBookmark( );
    }
    return makeAny(m_xDriverSet->getRow());
}
// -------------------------------------------------------------------------
sal_Bool SAL_CALL WrappedResultSet::moveToBookmark( const Any& bookmark ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::moveToBookmark" );
    return m_xRowLocate->moveToBookmark( bookmark );
}
// -------------------------------------------------------------------------
sal_Bool SAL_CALL WrappedResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::moveRelativeToBookmark" );
    return m_xRowLocate->moveRelativeToBookmark( bookmark,rows );
}
// -------------------------------------------------------------------------
sal_Int32 SAL_CALL WrappedResultSet::compareBookmarks( const Any& _first, const Any& _second ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::compareBookmarks" );
    return m_xRowLocate->compareBookmarks( _first,_second );
}
// -------------------------------------------------------------------------
sal_Bool SAL_CALL WrappedResultSet::hasOrderedBookmarks(  ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::hasOrderedBookmarks" );
    return m_xRowLocate->hasOrderedBookmarks();
}
// -------------------------------------------------------------------------
sal_Int32 SAL_CALL WrappedResultSet::hashBookmark( const Any& bookmark ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::hashBookmark" );
    return m_xRowLocate->hashBookmark(bookmark);
}
// -------------------------------------------------------------------------
// ::com::sun::star::sdbcx::XDeleteRows
Sequence< sal_Int32 > SAL_CALL WrappedResultSet::deleteRows( const Sequence< Any >& rows ,const connectivity::OSQLTable& /*_xTable*/) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::deleteRows" );
    Reference< ::com::sun::star::sdbcx::XDeleteRows> xDeleteRow(m_xRowLocate,UNO_QUERY);
    if(xDeleteRow.is())
    {
        return xDeleteRow->deleteRows(rows);
    }
    return Sequence< sal_Int32 >();
}
// -------------------------------------------------------------------------
void SAL_CALL WrappedResultSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::insertRow" );

    m_xUpd->moveToInsertRow();
    sal_Int32 i = 1;
    connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->get().end();
    for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->get().begin()+1;aIter != aEnd;++aIter,++i)
    {
        aIter->setSigned(m_aSignedFlags[i-1]);
        updateColumn(i,m_xUpdRow,*aIter);
    }
    m_xUpd->insertRow();
    (*_rInsertRow->get().begin()) = m_xDriverSet->getRow();
}
// -------------------------------------------------------------------------
void SAL_CALL WrappedResultSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOrginalRow,const connectivity::OSQLTable& /*_xTable*/  ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::updateRow" );
    sal_Int32 i = 1;
    connectivity::ORowVector< ORowSetValue > ::Vector::const_iterator aOrgIter = _rOrginalRow->get().begin()+1;
    connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->get().end();
    for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->get().begin()+1;aIter != aEnd;++aIter,++i,++aOrgIter)
    {
        aIter->setSigned(aOrgIter->isSigned());
        updateColumn(i,m_xUpdRow,*aIter);
    }
    m_xUpd->updateRow();
}
// -------------------------------------------------------------------------
void SAL_CALL WrappedResultSet::deleteRow(const ORowSetRow& /*_rDeleteRow*/ ,const connectivity::OSQLTable& /*_xTable*/  ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::deleteRow" );
    m_xUpd->deleteRow();
}
// -------------------------------------------------------------------------
void SAL_CALL WrappedResultSet::cancelRowUpdates(  ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::cancelRowUpdates" );
    m_xUpd->cancelRowUpdates();
}
// -------------------------------------------------------------------------
void SAL_CALL WrappedResultSet::moveToInsertRow(  ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::moveToInsertRow" );
    m_xUpd->moveToInsertRow();
}
// -------------------------------------------------------------------------
void SAL_CALL WrappedResultSet::moveToCurrentRow(  ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::moveToCurrentRow" );
}
// -------------------------------------------------------------------------
void WrappedResultSet::fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::fillValueRow" );
    OCacheSet::fillValueRow(_rRow,_nPosition);
}
// -------------------------------------------------------------------------
void WrappedResultSet::updateColumn(sal_Int32 nPos,Reference< XRowUpdate > _xParameter,const ORowSetValue& _rValue)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::updateColumn" );
    if(_rValue.isBound() && _rValue.isModified())
    {
        if(_rValue.isNull())
            _xParameter->updateNull(nPos);
        else
        {

            switch(_rValue.getTypeKind())
            {
                case DataType::DECIMAL:
                case DataType::NUMERIC:
                    _xParameter->updateNumericObject(nPos,_rValue.makeAny(),m_xSetMetaData->getScale(nPos));
                    break;
                case DataType::CHAR:
                case DataType::VARCHAR:
                //case DataType::DECIMAL:
                //case DataType::NUMERIC:
                    _xParameter->updateString(nPos,_rValue);
                    break;
                case DataType::BIGINT:
                    if ( _rValue.isSigned() )
                        _xParameter->updateLong(nPos,_rValue);
                    else
                        _xParameter->updateString(nPos,_rValue);
                    break;
                case DataType::BIT:
                case DataType::BOOLEAN:
                    _xParameter->updateBoolean(nPos,_rValue);
                    break;
                case DataType::TINYINT:
                    if ( _rValue.isSigned() )
                        _xParameter->updateByte(nPos,_rValue);
                    else
                        _xParameter->updateShort(nPos,_rValue);
                    break;
                case DataType::SMALLINT:
                    if ( _rValue.isSigned() )
                        _xParameter->updateShort(nPos,_rValue);
                    else
                        _xParameter->updateInt(nPos,_rValue);
                    break;
                case DataType::INTEGER:
                    if ( _rValue.isSigned() )
                        _xParameter->updateInt(nPos,_rValue);
                    else
                        _xParameter->updateLong(nPos,_rValue);
                    break;
                case DataType::FLOAT:
                    _xParameter->updateFloat(nPos,_rValue);
                    break;
                case DataType::DOUBLE:
                case DataType::REAL:
                    _xParameter->updateDouble(nPos,_rValue);
                    break;
                case DataType::DATE:
                    _xParameter->updateDate(nPos,_rValue);
                    break;
                case DataType::TIME:
                    _xParameter->updateTime(nPos,_rValue);
                    break;
                case DataType::TIMESTAMP:
                    _xParameter->updateTimestamp(nPos,_rValue);
                    break;
                case DataType::BINARY:
                case DataType::VARBINARY:
                case DataType::LONGVARBINARY:
                    _xParameter->updateBytes(nPos,_rValue);
                    break;
                case DataType::BLOB:
                case DataType::CLOB:
                    _xParameter->updateObject(nPos,_rValue.getAny());
                    break;
            }
        }
    }
}

<commit_msg>dba33g: handle bookmark corrected after insertrow<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: BookmarkSet.cxx,v $
 * $Revision: 1.21 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dbaccess.hxx"
#include "WrappedResultSet.hxx"
#include "core_resource.hxx"
#include "core_resource.hrc"
#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
#include <connectivity/dbexception.hxx>
#include <rtl/logfile.hxx>

#include <limits>

using namespace dbaccess;
using namespace ::connectivity;
using namespace ::dbtools;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sdbc;
//  using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;
//  using namespace ::cppu;
using namespace ::osl;

void WrappedResultSet::construct(const Reference< XResultSet>& _xDriverSet,const ::rtl::OUString& i_sRowSetFilter)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::construct" );
    OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
    m_xUpd.set(_xDriverSet,UNO_QUERY_THROW);
    m_xRowLocate.set(_xDriverSet,UNO_QUERY_THROW);
    m_xUpdRow.set(_xDriverSet,UNO_QUERY_THROW);
}
// -----------------------------------------------------------------------------
Any SAL_CALL WrappedResultSet::getBookmark() throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::getBookmark" );
    if ( m_xRowLocate.is() )
    {
        return m_xRowLocate->getBookmark( );
    }
    return makeAny(m_xDriverSet->getRow());
}
// -------------------------------------------------------------------------
sal_Bool SAL_CALL WrappedResultSet::moveToBookmark( const Any& bookmark ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::moveToBookmark" );
    return m_xRowLocate->moveToBookmark( bookmark );
}
// -------------------------------------------------------------------------
sal_Bool SAL_CALL WrappedResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::moveRelativeToBookmark" );
    return m_xRowLocate->moveRelativeToBookmark( bookmark,rows );
}
// -------------------------------------------------------------------------
sal_Int32 SAL_CALL WrappedResultSet::compareBookmarks( const Any& _first, const Any& _second ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::compareBookmarks" );
    return m_xRowLocate->compareBookmarks( _first,_second );
}
// -------------------------------------------------------------------------
sal_Bool SAL_CALL WrappedResultSet::hasOrderedBookmarks(  ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::hasOrderedBookmarks" );
    return m_xRowLocate->hasOrderedBookmarks();
}
// -------------------------------------------------------------------------
sal_Int32 SAL_CALL WrappedResultSet::hashBookmark( const Any& bookmark ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::hashBookmark" );
    return m_xRowLocate->hashBookmark(bookmark);
}
// -------------------------------------------------------------------------
// ::com::sun::star::sdbcx::XDeleteRows
Sequence< sal_Int32 > SAL_CALL WrappedResultSet::deleteRows( const Sequence< Any >& rows ,const connectivity::OSQLTable& /*_xTable*/) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::deleteRows" );
    Reference< ::com::sun::star::sdbcx::XDeleteRows> xDeleteRow(m_xRowLocate,UNO_QUERY);
    if(xDeleteRow.is())
    {
        return xDeleteRow->deleteRows(rows);
    }
    return Sequence< sal_Int32 >();
}
// -------------------------------------------------------------------------
void SAL_CALL WrappedResultSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::insertRow" );

    m_xUpd->moveToInsertRow();
    sal_Int32 i = 1;
    connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->get().end();
    for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->get().begin()+1;aIter != aEnd;++aIter,++i)
    {
        aIter->setSigned(m_aSignedFlags[i-1]);
        updateColumn(i,m_xUpdRow,*aIter);
    }
    m_xUpd->insertRow();
    (*_rInsertRow->get().begin()) = getBookmark();
}
// -------------------------------------------------------------------------
void SAL_CALL WrappedResultSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOrginalRow,const connectivity::OSQLTable& /*_xTable*/  ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::updateRow" );
    sal_Int32 i = 1;
    connectivity::ORowVector< ORowSetValue > ::Vector::const_iterator aOrgIter = _rOrginalRow->get().begin()+1;
    connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->get().end();
    for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->get().begin()+1;aIter != aEnd;++aIter,++i,++aOrgIter)
    {
        aIter->setSigned(aOrgIter->isSigned());
        updateColumn(i,m_xUpdRow,*aIter);
    }
    m_xUpd->updateRow();
}
// -------------------------------------------------------------------------
void SAL_CALL WrappedResultSet::deleteRow(const ORowSetRow& /*_rDeleteRow*/ ,const connectivity::OSQLTable& /*_xTable*/  ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::deleteRow" );
    m_xUpd->deleteRow();
}
// -------------------------------------------------------------------------
void SAL_CALL WrappedResultSet::cancelRowUpdates(  ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::cancelRowUpdates" );
    m_xUpd->cancelRowUpdates();
}
// -------------------------------------------------------------------------
void SAL_CALL WrappedResultSet::moveToInsertRow(  ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::moveToInsertRow" );
    m_xUpd->moveToInsertRow();
}
// -------------------------------------------------------------------------
void SAL_CALL WrappedResultSet::moveToCurrentRow(  ) throw(SQLException, RuntimeException)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::moveToCurrentRow" );
    m_xUpd->moveToCurrentRow();
}
// -------------------------------------------------------------------------
void WrappedResultSet::fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::fillValueRow" );
    OCacheSet::fillValueRow(_rRow,_nPosition);
}
// -------------------------------------------------------------------------
void WrappedResultSet::updateColumn(sal_Int32 nPos,Reference< XRowUpdate > _xParameter,const ORowSetValue& _rValue)
{
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::updateColumn" );
    if(_rValue.isBound() && _rValue.isModified())
    {
        if(_rValue.isNull())
            _xParameter->updateNull(nPos);
        else
        {

            switch(_rValue.getTypeKind())
            {
                case DataType::DECIMAL:
                case DataType::NUMERIC:
                    _xParameter->updateNumericObject(nPos,_rValue.makeAny(),m_xSetMetaData->getScale(nPos));
                    break;
                case DataType::CHAR:
                case DataType::VARCHAR:
                //case DataType::DECIMAL:
                //case DataType::NUMERIC:
                    _xParameter->updateString(nPos,_rValue);
                    break;
                case DataType::BIGINT:
                    if ( _rValue.isSigned() )
                        _xParameter->updateLong(nPos,_rValue);
                    else
                        _xParameter->updateString(nPos,_rValue);
                    break;
                case DataType::BIT:
                case DataType::BOOLEAN:
                    _xParameter->updateBoolean(nPos,_rValue);
                    break;
                case DataType::TINYINT:
                    if ( _rValue.isSigned() )
                        _xParameter->updateByte(nPos,_rValue);
                    else
                        _xParameter->updateShort(nPos,_rValue);
                    break;
                case DataType::SMALLINT:
                    if ( _rValue.isSigned() )
                        _xParameter->updateShort(nPos,_rValue);
                    else
                        _xParameter->updateInt(nPos,_rValue);
                    break;
                case DataType::INTEGER:
                    if ( _rValue.isSigned() )
                        _xParameter->updateInt(nPos,_rValue);
                    else
                        _xParameter->updateLong(nPos,_rValue);
                    break;
                case DataType::FLOAT:
                    _xParameter->updateFloat(nPos,_rValue);
                    break;
                case DataType::DOUBLE:
                case DataType::REAL:
                    _xParameter->updateDouble(nPos,_rValue);
                    break;
                case DataType::DATE:
                    _xParameter->updateDate(nPos,_rValue);
                    break;
                case DataType::TIME:
                    _xParameter->updateTime(nPos,_rValue);
                    break;
                case DataType::TIMESTAMP:
                    _xParameter->updateTimestamp(nPos,_rValue);
                    break;
                case DataType::BINARY:
                case DataType::VARBINARY:
                case DataType::LONGVARBINARY:
                    _xParameter->updateBytes(nPos,_rValue);
                    break;
                case DataType::BLOB:
                case DataType::CLOB:
                    _xParameter->updateObject(nPos,_rValue.getAny());
                    break;
            }
        }
    }
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
 *   @author Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "tls-cert-verifier-op.h"

#include <TelepathyQt/PendingVariantMap>

#include <KMessageBox>
#include <KLocalizedString>
#include <KDebug>

#include <QSslCertificate>

TlsCertVerifierOp::TlsCertVerifierOp(const Tp::AccountPtr &account,
        const Tp::ConnectionPtr &connection,
        const Tp::ChannelPtr &channel)
    : Tp::PendingOperation(channel),
      m_account(account),
      m_connection(connection),
      m_channel(channel)
{
    QDBusObjectPath certificatePath = qdbus_cast<QDBusObjectPath>(channel->immutableProperties().value(
                TP_QT_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION + QLatin1String(".ServerCertificate")));
    m_hostname = qdbus_cast<QString>(channel->immutableProperties().value(
                TP_QT_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION + QLatin1String(".Hostname")));
    m_referenceIdentities = qdbus_cast<QStringList>(channel->immutableProperties().value(
                TP_QT_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION + QLatin1String(".ReferenceIdentities")));

    m_authTLSCertificateIface = new Tp::Client::AuthenticationTLSCertificateInterface(
            channel->dbusConnection(), channel->busName(), certificatePath.path());
    connect(m_authTLSCertificateIface->requestAllProperties(),
            SIGNAL(finished(Tp::PendingOperation*)),
            SLOT(gotProperties(Tp::PendingOperation*)));
}

TlsCertVerifierOp::~TlsCertVerifierOp()
{
}

void TlsCertVerifierOp::gotProperties(Tp::PendingOperation *op)
{
    if (op->isError()) {
        kWarning() << "Unable to retrieve properties from AuthenticationTLSCertificate object at" <<
            m_authTLSCertificateIface->path();
        m_channel->requestClose();
        setFinishedWithError(op->errorName(), op->errorMessage());
        return;
    }

    // everything ok, we can return from handleChannels now
    Q_EMIT ready(this);

    Tp::PendingVariantMap *pvm = qobject_cast<Tp::PendingVariantMap*>(op);
    QVariantMap props = qdbus_cast<QVariantMap>(pvm->result());
    m_certType = qdbus_cast<QString>(props.value(QLatin1String("CertificateType")));
    m_certData = qdbus_cast<CertificateDataList>(props.value(QLatin1String("CertificateChainData")));

    if(m_certType.compare(QLatin1String("x509"), Qt::CaseInsensitive)) {
        kWarning() << "This is not an x509 certificate";
    }

    Q_FOREACH (const QByteArray &data, m_certData) {
        // FIXME How to chech if it is QSsl::Pem or QSsl::Der? QSsl::Der works for kdetalk
        QList<QSslCertificate> certs = QSslCertificate::fromData(data, QSsl::Der);
        Q_FOREACH (const QSslCertificate &cert, certs) {
            kDebug() << cert;
        }
    }

    //TODO Show a nice dialog
    if (KMessageBox::questionYesNo(0,
                                   i18n("Accept this certificate?
%1").arg(QString::fromLatin1(m_certData.first().toHex())),
                                   i18n("Untrusted certificate")) == KMessageBox::Yes) {
        // TODO Remember value
        m_authTLSCertificateIface->Accept().waitForFinished();
        setFinished();
    } else {
        Tp::TLSCertificateRejectionList rejections;
        // TODO Add reason
        m_authTLSCertificateIface->Reject(rejections);
        m_channel->requestClose();
        setFinishedWithError(QLatin1String("Cert.Untrusted"),
                             QLatin1String("Certificate rejected by the user"));
    }
}

#include "tls-cert-verifier-op.moc"
<commit_msg>Print some more debugging output for certificate in tls-handler<commit_after>/*
 * Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
 *   @author Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "tls-cert-verifier-op.h"

#include <TelepathyQt/PendingVariantMap>

#include <KMessageBox>
#include <KLocalizedString>
#include <KDebug>

#include <QSslCertificate>

TlsCertVerifierOp::TlsCertVerifierOp(const Tp::AccountPtr &account,
        const Tp::ConnectionPtr &connection,
        const Tp::ChannelPtr &channel)
    : Tp::PendingOperation(channel),
      m_account(account),
      m_connection(connection),
      m_channel(channel)
{
    QDBusObjectPath certificatePath = qdbus_cast<QDBusObjectPath>(channel->immutableProperties().value(
                TP_QT_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION + QLatin1String(".ServerCertificate")));
    m_hostname = qdbus_cast<QString>(channel->immutableProperties().value(
                TP_QT_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION + QLatin1String(".Hostname")));
    m_referenceIdentities = qdbus_cast<QStringList>(channel->immutableProperties().value(
                TP_QT_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION + QLatin1String(".ReferenceIdentities")));

    m_authTLSCertificateIface = new Tp::Client::AuthenticationTLSCertificateInterface(
            channel->dbusConnection(), channel->busName(), certificatePath.path());
    connect(m_authTLSCertificateIface->requestAllProperties(),
            SIGNAL(finished(Tp::PendingOperation*)),
            SLOT(gotProperties(Tp::PendingOperation*)));
}

TlsCertVerifierOp::~TlsCertVerifierOp()
{
}

void TlsCertVerifierOp::gotProperties(Tp::PendingOperation *op)
{
    if (op->isError()) {
        kWarning() << "Unable to retrieve properties from AuthenticationTLSCertificate object at" <<
            m_authTLSCertificateIface->path();
        m_channel->requestClose();
        setFinishedWithError(op->errorName(), op->errorMessage());
        return;
    }

    // everything ok, we can return from handleChannels now
    Q_EMIT ready(this);

    Tp::PendingVariantMap *pvm = qobject_cast<Tp::PendingVariantMap*>(op);
    QVariantMap props = qdbus_cast<QVariantMap>(pvm->result());
    m_certType = qdbus_cast<QString>(props.value(QLatin1String("CertificateType")));
    m_certData = qdbus_cast<CertificateDataList>(props.value(QLatin1String("CertificateChainData")));

    if(m_certType.compare(QLatin1String("x509"), Qt::CaseInsensitive)) {
        kWarning() << "This is not an x509 certificate";
    }

    Q_FOREACH (const QByteArray &data, m_certData) {
        // FIXME How to chech if it is QSsl::Pem or QSsl::Der? QSsl::Der works for kdetalk
        QList<QSslCertificate> certs = QSslCertificate::fromData(data, QSsl::Der);
        Q_FOREACH (const QSslCertificate &cert, certs) {
            kDebug() << cert;
            kDebug() << "Issuer Organization:" << cert.issuerInfo(QSslCertificate::Organization);
            kDebug() << "Issuer Common Name:" << cert.issuerInfo(QSslCertificate::CommonName);
            kDebug() << "Issuer Locality Name:" << cert.issuerInfo(QSslCertificate::LocalityName);
            kDebug() << "Issuer Organizational Unit Name:" << cert.issuerInfo(QSslCertificate::OrganizationalUnitName);
            kDebug() << "Issuer Country Name:" << cert.issuerInfo(QSslCertificate::CountryName);
            kDebug() << "Issuer State or Province Name:" << cert.issuerInfo(QSslCertificate::StateOrProvinceName);
            kDebug() << "Subject Organization:" << cert.subjectInfo(QSslCertificate::Organization);
            kDebug() << "Subject Common Name:" << cert.subjectInfo(QSslCertificate::CommonName);
            kDebug() << "Subject Locality Name:" << cert.subjectInfo(QSslCertificate::LocalityName);
            kDebug() << "Subject Organizational Unit Name:" << cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
            kDebug() << "Subject Country Name:" << cert.subjectInfo(QSslCertificate::CountryName);
            kDebug() << "Subject State Or Province Name:" << cert.subjectInfo(QSslCertificate::StateOrProvinceName);
            kDebug() << "Effective Date:" << cert.effectiveDate();
            kDebug() << "Expiry Date:" << cert.expiryDate();
            kDebug() << "Public Key:" << cert.publicKey();
            kDebug() << "Serial Number:" << cert.serialNumber();
            kDebug() << "Version" << cert.version();
            kDebug() << "Is Valid?" << cert.isValid();
        }
    }

    //TODO Show a nice dialog
    if (KMessageBox::questionYesNo(0,
                                   i18n("Accept this certificate from %1?
%2
").arg(m_hostname).arg(QString::fromLatin1(m_certData.first().toHex())),
                                   i18n("Untrusted certificate")) == KMessageBox::Yes) {
        // TODO Remember value
        m_authTLSCertificateIface->Accept().waitForFinished();
        setFinished();
    } else {
        Tp::TLSCertificateRejectionList rejections;
        // TODO Add reason
        m_authTLSCertificateIface->Reject(rejections);
        m_channel->requestClose();
        setFinishedWithError(QLatin1String("Cert.Untrusted"),
                             QLatin1String("Certificate rejected by the user"));
    }
}

#include "tls-cert-verifier-op.moc"
<|endoftext|>


<commit_before>/** @file

  A simple remap plugin for ATS

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

  @section description
    This is a very simple plugin: it will add headers that are specified on a remap line

    Example usage:
    map /foo http://127.0.0.1/ @plugin=remap_header_add.so @pparam=foo:"x" @pparam=@test:"c" @pparam=a:"b"

 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "ts/ts.h"
#include "ts/remap.h"

struct remap_line {
  int argc;
  char **argv; // store the originals

  int nvc; // the number of name value pairs, should be argc - 2.
  char **name; // at load we will parse out the name and values.
  char **val;
};

#define TAG "headeradd_remap"
#define NOWARN_UNUSED __attribute__ ((unused))
#define EXTERN extern "C"

EXTERN void ParseArgIntoNv(const char *arg, char **n, char **v) {
  const char *colon_pos = strchr(arg, ':');
  if (colon_pos == NULL) {
    *n = NULL;
    *v = NULL;
    TSDebug(TAG, "No name value pair since it was malformed");
    return;
  }

  size_t name_len = colon_pos - arg;
  *n = (char *) TSmalloc(name_len + 1);
  memcpy(*n, arg, colon_pos - arg);
  (*n)[name_len] = '\0';

  size_t val_len = strlen(colon_pos + 1); // skip past the ':'

  // check to see if the value is quoted.
  if (val_len > 1 && colon_pos[1] == '"' && colon_pos[val_len] == '"') {
    colon_pos++; // advance past the first quote
    val_len -= 2; // don't include the trailing quote
  }

  *v = (char *) TSmalloc(val_len + 1);
  memcpy(*v, colon_pos + 1, val_len);
  (*v)[val_len] = '\0';

  TSDebug(TAG, "\t name_len=%zu, val_len=%zu, %s=%s", name_len, val_len, *n, *v);
}

TSReturnCode TSRemapInit(NOWARN_UNUSED TSRemapInterface *api_info, NOWARN_UNUSED char *errbuf, NOWARN_UNUSED int errbuf_size) {
  return TS_SUCCESS;
}

TSReturnCode TSRemapNewInstance(int argc, char* argv[], void** ih, NOWARN_UNUSED char* errbuf, NOWARN_UNUSED int errbuf_size) {
  remap_line *rl = NULL;

  TSDebug(TAG, "TSRemapNewInstance()");

  if (!argv || !ih) {
    TSError(TAG ": Unable to load plugin because missing argv or ih.");
    return TS_ERROR;
  }

  // print all arguments for this particular remapping

  rl = (remap_line*) TSmalloc(sizeof(remap_line));
  rl->argc = argc;
  rl->argv = argv;
  rl->nvc = argc - 2; // the first two are the remap from and to
  if (rl->nvc) {
    rl->name = (char**) TSmalloc(sizeof(char *) * rl->nvc);
    rl->val = (char**) TSmalloc(sizeof(char *) * rl->nvc);
  }

  TSDebug(TAG, "NewInstance:");
  for (int i = 2; i < argc; i++) {
    ParseArgIntoNv(argv[i], &rl->name[i-2], &rl->val[i-2]);
  }

  *ih = (void *) rl;

  return TS_SUCCESS;
}

void TSRemapDeleteInstance(void* ih)
{
  TSDebug(TAG, "deleting instance %p", ih);

  if (ih) {
    remap_line *rl = (remap_line*)ih;
    for (int i = 0; i < rl->nvc; ++i)
    {
      TSfree(rl->name[i]);
      TSfree(rl->val[i]);
    }

    TSfree(rl->name);
    TSfree(rl->val);
  }
}

TSRemapStatus TSRemapDoRemap(void* ih, NOWARN_UNUSED TSHttpTxn txn, NOWARN_UNUSED TSRemapRequestInfo *rri) {
  remap_line *rl = (remap_line *) ih;

  if (!rl || !rri) {
    TSError(TAG ": rl or rri is null.");
    return TSREMAP_NO_REMAP;
  }

  TSDebug(TAG, "TSRemapDoRemap:");

  TSMBuffer req_bufp;
  TSMLoc req_loc;
  if (TSHttpTxnClientReqGet(txn, &req_bufp, &req_loc) != TS_SUCCESS) {
    TSError(TAG ": Error while retrieving client request header");
    return TSREMAP_NO_REMAP;
  }

  for (int i = 0; i < rl->nvc; ++i) {
    TSDebug(TAG, "Attaching header \"%s\" with value \"%s\".", rl->name[i], rl->val[i]);

    TSMLoc field_loc;
    if (TSMimeHdrFieldCreate(req_bufp, req_loc, &field_loc) == TS_SUCCESS) {
        TSMimeHdrFieldNameSet(req_bufp, req_loc, field_loc, rl->name[i], strlen(rl->name[i]));
        TSMimeHdrFieldAppend(req_bufp, req_loc, field_loc);
        TSMimeHdrFieldValueStringInsert(req_bufp, req_loc, field_loc, 0,  rl->val[i], strlen(rl->val[i]));
    } else {
      TSError(TAG ": Failure on TSMimeHdrFieldCreate");
    }
  }
  return TSREMAP_NO_REMAP;
}
<commit_msg>Clean up formatting slightly<commit_after>/** @file

  A simple remap plugin for ATS

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

  @section description
    This is a very simple plugin: it will add headers that are specified on a remap line

    Example usage:
    map /foo http://127.0.0.1/ @plugin=remap_header_add.so @pparam=foo:"x" @pparam=@test:"c" @pparam=a:"b"

 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "ts/ts.h"
#include "ts/remap.h"

struct remap_line
{
  int argc;
  char **argv; // store the originals

  int nvc; // the number of name value pairs, should be argc - 2.
  char **name; // at load we will parse out the name and values.
  char **val;
};

#define TAG "headeradd_remap"
#define NOWARN_UNUSED __attribute__ ((unused))
#define EXTERN extern "C"

EXTERN void
ParseArgIntoNv(const char *arg, char **n, char **v)
{
  const char *colon_pos = strchr(arg, ':');

  if (colon_pos == NULL) {
    *n = NULL;
    *v = NULL;
    TSDebug(TAG, "No name value pair since it was malformed");
    return;
  }

  size_t name_len = colon_pos - arg;
  *n = (char *) TSmalloc(name_len + 1);
  memcpy(*n, arg, colon_pos - arg);
  (*n)[name_len] = '\0';

  size_t val_len = strlen(colon_pos + 1); // skip past the ':'

  // check to see if the value is quoted.
  if (val_len > 1 && colon_pos[1] == '"' && colon_pos[val_len] == '"') {
    colon_pos++; // advance past the first quote
    val_len -= 2; // don't include the trailing quote
  }

  *v = (char *) TSmalloc(val_len + 1);
  memcpy(*v, colon_pos + 1, val_len);
  (*v)[val_len] = '\0';

  TSDebug(TAG, "\t name_len=%zu, val_len=%zu, %s=%s", name_len, val_len, *n, *v);
}

TSReturnCode
TSRemapInit(NOWARN_UNUSED TSRemapInterface *api_info, NOWARN_UNUSED char *errbuf, NOWARN_UNUSED int errbuf_size)
{
  return TS_SUCCESS;
}

TSReturnCode
TSRemapNewInstance(int argc, char* argv[], void** ih, NOWARN_UNUSED char* errbuf, NOWARN_UNUSED int errbuf_size)
{
  remap_line *rl = NULL;

  TSDebug(TAG, "TSRemapNewInstance()");

  if (!argv || !ih) {
    TSError(TAG ": Unable to load plugin because missing argv or ih.");
    return TS_ERROR;
  }

  // print all arguments for this particular remapping

  rl = (remap_line*) TSmalloc(sizeof(remap_line));
  rl->argc = argc;
  rl->argv = argv;
  rl->nvc = argc - 2; // the first two are the remap from and to
  if (rl->nvc) {
    rl->name = (char**) TSmalloc(sizeof(char *) * rl->nvc);
    rl->val = (char**) TSmalloc(sizeof(char *) * rl->nvc);
  }

  TSDebug(TAG, "NewInstance:");
  for (int i = 2; i < argc; i++) {
    ParseArgIntoNv(argv[i], &rl->name[i-2], &rl->val[i-2]);
  }

  *ih = (void *) rl;

  return TS_SUCCESS;
}

void
TSRemapDeleteInstance(void* ih)
{
  TSDebug(TAG, "deleting instance %p", ih);

  if (ih) {
    remap_line *rl = (remap_line*)ih;
    for (int i = 0; i < rl->nvc; ++i)
    {
      TSfree(rl->name[i]);
      TSfree(rl->val[i]);
    }

    TSfree(rl->name);
    TSfree(rl->val);
  }
}

TSRemapStatus
TSRemapDoRemap(void* ih, NOWARN_UNUSED TSHttpTxn txn, NOWARN_UNUSED TSRemapRequestInfo *rri)
{
  remap_line *rl = (remap_line *) ih;

  if (!rl || !rri) {
    TSError(TAG ": rl or rri is null.");
    return TSREMAP_NO_REMAP;
  }

  TSDebug(TAG, "TSRemapDoRemap:");

  TSMBuffer req_bufp;
  TSMLoc req_loc;
  if (TSHttpTxnClientReqGet(txn, &req_bufp, &req_loc) != TS_SUCCESS) {
    TSError(TAG ": Error while retrieving client request header");
    return TSREMAP_NO_REMAP;
  }

  for (int i = 0; i < rl->nvc; ++i) {
    TSDebug(TAG, "Attaching header \"%s\" with value \"%s\".", rl->name[i], rl->val[i]);

    TSMLoc field_loc;
    if (TSMimeHdrFieldCreate(req_bufp, req_loc, &field_loc) == TS_SUCCESS) {
        TSMimeHdrFieldNameSet(req_bufp, req_loc, field_loc, rl->name[i], strlen(rl->name[i]));
        TSMimeHdrFieldAppend(req_bufp, req_loc, field_loc);
        TSMimeHdrFieldValueStringInsert(req_bufp, req_loc, field_loc, 0,  rl->val[i], strlen(rl->val[i]));
    } else {
      TSError(TAG ": Failure on TSMimeHdrFieldCreate");
    }
  }

  return TSREMAP_NO_REMAP;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014-2020 Real Logic Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <array>
#include <atomic>
#include <thread>
#include <cstdint>

#include <gtest/gtest.h>

extern "C"
{
#include "util/aeron_error.h"
}

class ErrorTest : public testing::Test
{
public:
    ErrorTest()
    {
        aeron_err_clear();
    }
};

int functionA()
{
    AERON_SET_ERR(-EINVAL, "this is the root error: %d", 10);
    return -1;
}

int functionB()
{
    if (functionA() < 0)
    {
        AERON_APPEND_ERR("this is another error: %d", 20);
        return -1;
    }

    return 0;
}

int functionC()
{
    if (functionB() < 0)
    {
        AERON_APPEND_ERR("this got borked: %d", 30);
    }

    return 0;
}

static std::string::size_type assert_substring(
    const std::string &value, const std::string token, const std::string::size_type index)
{
    auto new_index = value.find(token, index);
    EXPECT_NE(new_index, std::string::npos);

    return new_index;
}

TEST_F(ErrorTest, shouldStackErrors)
{
    functionC();

    std::string err_msg = std::string(aeron_errmsg());

    auto index = assert_substring(err_msg, "(-22) unknown error code", 0);
    index = assert_substring(err_msg, "[functionA, aeron_error_test.cpp:", index);
    index = assert_substring(err_msg, "] this is the root error: 10", index);
    index = assert_substring(err_msg, "[functionB, aeron_error_test.cpp:", index);
    index = assert_substring(err_msg, "] this is another error: 20", index);
    index = assert_substring(err_msg, "[functionC, aeron_error_test.cpp:", index);
    index = assert_substring(err_msg, "] this got borked: 30", index);

    EXPECT_LT(index, err_msg.length());
}

TEST_F(ErrorTest, shouldHandleErrorsOverflow)
{
    AERON_SET_ERR(EINVAL, "%s", "this is the root error");

    for (int i = 0; i < 1000; i++)
    {
        AERON_APPEND_ERR("this is a nested error: %d", i);
    }

    std::string err_msg = std::string(aeron_errmsg());

    auto index = assert_substring(err_msg, "(22) Invalid argument", 0);
    index = assert_substring(err_msg, "[TestBody, aeron_error_test.cpp:", index);
    index = assert_substring(err_msg, "] this is the root error", index);
    index = assert_substring(err_msg, "[TestBody, aeron_error_test.cpp:", index);
    index = assert_substring(err_msg, "] this is a nested error: ", index);
    index = assert_substring(err_msg, "[TestBody, aeron_error_...", index);

    EXPECT_LT(index, err_msg.length());
}

TEST_F(ErrorTest, shouldReportZeroAsErrorForBackwardCompatibility)
{
    AERON_SET_ERR(0, "%s", "this is the root error");

    std::string err_msg = std::string(aeron_errmsg());

    auto index = assert_substring(err_msg, "(0) generic error, see message", 0);
    index = assert_substring(err_msg, "[TestBody, aeron_error_test.cpp:", index);
    index = assert_substring(err_msg, "] this is the root error", index);

    EXPECT_LT(index, err_msg.length());
}

#define CALLS_PER_THREAD (1000)
#define NUM_THREADS (2)
#define ITERATIONS (10)

static void test_concurrent_access()
{
    std::atomic<int> countDown(NUM_THREADS);
    std::vector<std::thread> threads;

    for (int i = 0; i < NUM_THREADS; i++)
    {
        threads.push_back(
            std::thread(
                [&]()
                {
                    const int thread_id = countDown.fetch_sub(1);
                    while (countDown > 0)
                    {
                        std::this_thread::yield();
                    }

                    const auto sleep_time = std::chrono::microseconds(thread_id);
                    const auto start("] [" + std::to_string(thread_id) + "] start");
                    const auto before("] [" + std::to_string(thread_id) + "] before sleep:");
                    const auto after("] [" + std::to_string(thread_id) + "] after sleep:");
                    for (int m = 0; m < CALLS_PER_THREAD; m++)
                    {
                        AERON_SET_ERR(0, "[%d] %s", thread_id, "start");
                        AERON_APPEND_ERR("[%d] before sleep: %d", thread_id, m);
                        std::this_thread::sleep_for(sleep_time);
                        AERON_APPEND_ERR("[%d] after sleep: %d", thread_id, m);

                        std::string err_msg = std::string(aeron_errmsg());

                        auto index = assert_substring(err_msg, "(0) generic error, see message", 0);
                        index = assert_substring(err_msg, "[operator(), aeron_error_test.cpp:", index);
                        index = assert_substring(err_msg, start, index);
                        index = assert_substring(err_msg, "[operator(), aeron_error_test.cpp:", index);
                        index = assert_substring(err_msg, before, index);
                        index = assert_substring(err_msg, "[operator(), aeron_error_test.cpp:", index);
                        index = assert_substring(err_msg, after, index);
                        EXPECT_LT(index, err_msg.length());

                        aeron_err_clear();
                    }
                }));
    }

    for (std::thread &thr: threads)
    {
        thr.join();
    }
}

/*
TEST_F(ErrorTest, shouldAllowConcurrentAccess)
{
    for (int i = 0; i < ITERATIONS; i++)
    {
        test_concurrent_access();
    }
}
*/
<commit_msg>[C] Fix warning.<commit_after>/*
 * Copyright 2014-2020 Real Logic Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <array>
#include <atomic>
#include <thread>
#include <cstdint>

#include <gtest/gtest.h>

extern "C"
{
#include "util/aeron_error.h"
}

class ErrorTest : public testing::Test
{
public:
    ErrorTest()
    {
        aeron_err_clear();
    }
};

int functionA()
{
    AERON_SET_ERR(-EINVAL, "this is the root error: %d", 10);
    return -1;
}

int functionB()
{
    if (functionA() < 0)
    {
        AERON_APPEND_ERR("this is another error: %d", 20);
        return -1;
    }

    return 0;
}

int functionC()
{
    if (functionB() < 0)
    {
        AERON_APPEND_ERR("this got borked: %d", 30);
    }

    return 0;
}

static std::string::size_type assert_substring(
    const std::string &value, const std::string token, const std::string::size_type index)
{
    auto new_index = value.find(token, index);
    EXPECT_NE(new_index, std::string::npos);

    return new_index;
}

TEST_F(ErrorTest, shouldStackErrors)
{
    functionC();

    std::string err_msg = std::string(aeron_errmsg());

    auto index = assert_substring(err_msg, "(-22) unknown error code", 0);
    index = assert_substring(err_msg, "[functionA, aeron_error_test.cpp:", index);
    index = assert_substring(err_msg, "] this is the root error: 10", index);
    index = assert_substring(err_msg, "[functionB, aeron_error_test.cpp:", index);
    index = assert_substring(err_msg, "] this is another error: 20", index);
    index = assert_substring(err_msg, "[functionC, aeron_error_test.cpp:", index);
    index = assert_substring(err_msg, "] this got borked: 30", index);

    EXPECT_LT(index, err_msg.length());
}

TEST_F(ErrorTest, shouldHandleErrorsOverflow)
{
    AERON_SET_ERR(EINVAL, "%s", "this is the root error");

    for (int i = 0; i < 1000; i++)
    {
        AERON_APPEND_ERR("this is a nested error: %d", i);
    }

    std::string err_msg = std::string(aeron_errmsg());

    auto index = assert_substring(err_msg, "(22) Invalid argument", 0);
    index = assert_substring(err_msg, "[TestBody, aeron_error_test.cpp:", index);
    index = assert_substring(err_msg, "] this is the root error", index);
    index = assert_substring(err_msg, "[TestBody, aeron_error_test.cpp:", index);
    index = assert_substring(err_msg, "] this is a nested error: ", index);
    index = assert_substring(err_msg, "[TestBody, aeron_error_...", index);

    EXPECT_LT(index, err_msg.length());
}

TEST_F(ErrorTest, shouldReportZeroAsErrorForBackwardCompatibility)
{
    AERON_SET_ERR(0, "%s", "this is the root error");

    std::string err_msg = std::string(aeron_errmsg());

    auto index = assert_substring(err_msg, "(0) generic error, see message", 0);
    index = assert_substring(err_msg, "[TestBody, aeron_error_test.cpp:", index);
    index = assert_substring(err_msg, "] this is the root error", index);

    EXPECT_LT(index, err_msg.length());
}

/*
#define CALLS_PER_THREAD (1000)
#define NUM_THREADS (2)
#define ITERATIONS (10)

static void test_concurrent_access()
{
    std::atomic<int> countDown(NUM_THREADS);
    std::vector<std::thread> threads;

    for (int i = 0; i < NUM_THREADS; i++)
    {
        threads.push_back(
            std::thread(
                [&]()
                {
                    const int thread_id = countDown.fetch_sub(1);
                    while (countDown > 0)
                    {
                        std::this_thread::yield();
                    }

                    const auto sleep_time = std::chrono::microseconds(thread_id);
                    const auto start("] [" + std::to_string(thread_id) + "] start");
                    const auto before("] [" + std::to_string(thread_id) + "] before sleep:");
                    const auto after("] [" + std::to_string(thread_id) + "] after sleep:");
                    for (int m = 0; m < CALLS_PER_THREAD; m++)
                    {
                        AERON_SET_ERR(0, "[%d] %s", thread_id, "start");
                        AERON_APPEND_ERR("[%d] before sleep: %d", thread_id, m);
                        std::this_thread::sleep_for(sleep_time);
                        AERON_APPEND_ERR("[%d] after sleep: %d", thread_id, m);

                        std::string err_msg = std::string(aeron_errmsg());

                        auto index = assert_substring(err_msg, "(0) generic error, see message", 0);
                        index = assert_substring(err_msg, "[operator(), aeron_error_test.cpp:", index);
                        index = assert_substring(err_msg, start, index);
                        index = assert_substring(err_msg, "[operator(), aeron_error_test.cpp:", index);
                        index = assert_substring(err_msg, before, index);
                        index = assert_substring(err_msg, "[operator(), aeron_error_test.cpp:", index);
                        index = assert_substring(err_msg, after, index);
                        EXPECT_LT(index, err_msg.length());

                        aeron_err_clear();
                    }
                }));
    }

    for (std::thread &thr: threads)
    {
        thr.join();
    }
}

TEST_F(ErrorTest, shouldAllowConcurrentAccess)
{
    for (int i = 0; i < ITERATIONS; i++)
    {
        test_concurrent_access();
    }
}
*/
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// IREE source.mlir -> execution output test runner.
// This is meant to be called from LIT for FileCheck tests, and tries to match
// the interface of mlir-opt (featuring -split-input-file, etc) so it's easier
// to work with there. If you want a more generalized runner for standalone
// precompiled IREE modules use //third_party/iree/tools:run_module.
//
// By default all exported functions in the module will be run in order.
// All input values, provided via -input-values, will be passed to the
// functions (this means all input signatures must match). Results from the
// executed functions will be printed to stdout for checking.
// Use -output_types to set the function output data types, which like args will
// be used for all functions executed.
//
// Example input:
// // RUN: iree-run %s | FileCheck %s
// // CHECK-LABEL: @foo
// // CHECK: 1xf32: 2
// func @foo() -> memref<f32> attributes {iree.module.export} {
//   %0 = "iree.constant"() {value: dense<tensor<f32>, 2.0>} : () -> memref<f32>
//   return %0 : memref<f32>
// }

#include "absl/flags/flag.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "iree/base/init.h"
#include "iree/base/source_location.h"
#include "iree/base/status.h"
#include "iree/compiler/Translation/Sequencer/SequencerModuleTranslation.h"
#include "iree/hal/buffer_view_string_util.h"
#include "iree/hal/driver_registry.h"
#include "iree/schemas/module_def_generated.h"
#include "iree/vm/bytecode_tables_sequencer.h"
#include "iree/vm/debug/debug_server_flags.h"
#include "iree/vm/fiber_state.h"
#include "iree/vm/instance.h"
#include "iree/vm/module.h"
#include "iree/vm/module_printer.h"
#include "iree/vm/sequencer_context.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/SourceMgr.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Function.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/Module.h"
#include "mlir/Parser.h"
#include "mlir/Support/FileUtilities.h"

ABSL_FLAG(bool, split_input_file, true,
          "Split the input file into multiple modules.");

ABSL_FLAG(std::string, target_backends, "",
          "Comma-separated list of target backends to translate executables "
          "into. Omit to translate using all linked-in backend translators.");
ABSL_FLAG(
    bool, export_all, true,
    "Automatically add the iree.module.export attribute to all functions.");

ABSL_FLAG(std::string, input_values, "", "Input shapes and optional values.");
ABSL_FLAG(std::string, output_types, "",
          "Output data types (comma delimited list of b/i/u/f for "
          "binary/signed int/unsigned int/float).");

// TODO(benvanik): is there a more canonical flag we can use?
ABSL_FLAG(bool, print_mlir, true, "Prints MLIR IR during translation.");

ABSL_FLAG(bool, print_bytecode, false,
          "Prints IREE bytecode after translation.");

ABSL_FLAG(bool, run, true,
          "Option to run the file. Setting it to false just compiles it.");

namespace iree {
namespace {

using ::iree::hal::BufferView;
using ::iree::vm::Function;
using ::iree::vm::Module;
using ::iree::vm::ModuleFile;

// Returns a driver name capable of handling input from the given backend.
std::string BackendToDriverName(std::string backend) {
  size_t dash = backend.find('-');
  if (dash == std::string::npos) {
    return backend;
  } else {
    return backend.substr(0, dash);
  }
}

// Prepares a module for evaluation by running MLIR import and IREE translation.
StatusOr<std::unique_ptr<Module>> PrepareModule(
    std::string target_backend,
    std::unique_ptr<llvm::MemoryBuffer> file_buffer) {
  mlir::MLIRContext context;

  // Parse input MLIR module.
  llvm::SourceMgr source_mgr;
  source_mgr.AddNewSourceBuffer(std::move(file_buffer), llvm::SMLoc());
  mlir::OwningModuleRef mlir_module =
      mlir::parseSourceFile(source_mgr, &context);

  if (absl::GetFlag(FLAGS_export_all)) {
    for (auto function : mlir_module->getOps<mlir::FuncOp>()) {
      function.setAttr("iree.module.export", mlir::UnitAttr::get(&context));
    }
  }

  // Translate from MLIR to IREE bytecode.
  mlir::iree_compiler::ModuleTranslationOptions options;
  options.print_mlir = absl::GetFlag(FLAGS_print_mlir);
  options.target_backends = {target_backend};
  auto iree_module_bytes =
      mlir::iree_compiler::translateMlirToIreeSequencerModule(mlir_module.get(),
                                                              options);
  if (iree_module_bytes.empty()) {
    return iree::InternalErrorBuilder(IREE_LOC)
           << "Error translating MLIR to an IREE sequencer module";
  }

  if (absl::GetFlag(FLAGS_print_mlir)) {
    mlir_module->dump();
  }

  // Wrap module in a file handle.
  ASSIGN_OR_RETURN(auto iree_module_file,
                   ModuleFile::FromBuffer(ModuleDefIdentifier(),
                                          std::move(iree_module_bytes)));
  return Module::FromFile(std::move(iree_module_file));
}

// Parses a list of input shapes and values from a string of newline-separated
// inputs. Expects the contents to have one value per line with each value
// listed as
//   [shape]xtype=[value]
// Example:
//   4x4xi8=0,1,2,3
StatusOr<std::vector<BufferView>> ParseInputsFromFlags(
    hal::Allocator* allocator) {
  std::string file_contents =
      absl::StrReplaceAll(absl::GetFlag(FLAGS_input_values), {{"\\n", "\n"}});
  std::vector<BufferView> inputs;
  for (const auto& line :
       absl::StrSplit(file_contents, '\n', absl::SkipWhitespace())) {
    ASSIGN_OR_RETURN(auto input,
                     hal::ParseBufferViewFromString(line, allocator));
    inputs.push_back(input);
  }
  return inputs;
}

// Outputs all results from the function to stdout in IREE BufferView format.
Status OutputFunctionResults(const Function& function,
                             absl::Span<BufferView> results) {
  std::vector<std::string> output_types =
      absl::StrSplit(absl::GetFlag(FLAGS_output_types),
                     absl::delimiter::AnyOf(", "), absl::SkipWhitespace());
  if (!output_types.empty() && output_types.size() != results.size()) {
    return InvalidArgumentErrorBuilder(IREE_LOC)
           << "--output_types= specified but has " << output_types.size()
           << " types when the function returns " << results.size();
  }

  for (int i = 0; i < results.size(); ++i) {
    const auto& result = results[i];
    auto print_mode = hal::BufferViewPrintMode::kFloatingPoint;
    if (!output_types.empty()) {
      ASSIGN_OR_RETURN(print_mode,
                       hal::ParseBufferViewPrintMode(output_types[i]));
    }
    ASSIGN_OR_RETURN(auto result_str,
                     hal::PrintBufferViewToString(result, print_mode, 1024));
    LOG(INFO) << "result[" << i << "]: " << result.buffer->DebugString();
    std::cout << result_str << "\n";
  }

  return OkStatus();
}

// Evaluates a single function in its own fiber, printing the results to stdout.
Status EvaluateFunction(std::shared_ptr<vm::Instance> instance,
                        vm::SequencerContext* context,
                        hal::Allocator* allocator, const Function& function) {
  // Setup our dummy fiber we will run with.
  vm::FiberState fiber_state(instance);

  std::cout << "EXEC @" << function.name() << std::endl;

  // Marshal inputs.
  ASSIGN_OR_RETURN(std::vector<BufferView> args,
                   ParseInputsFromFlags(allocator));
  std::vector<BufferView> results;
  results.resize(function.result_count());

  // Call into the main function.
  RETURN_IF_ERROR(context->Invoke(&fiber_state, function, absl::MakeSpan(args),
                                  absl::MakeSpan(results)));

  // Print outputs.
  RETURN_IF_ERROR(OutputFunctionResults(function, absl::MakeSpan(results)));

  return OkStatus();
}

// Evaluates all exported functions within given module.
Status EvaluateFunctions(absl::string_view target_backend,
                         std::unique_ptr<Module> module) {
  // Create the context we'll use for this (ensuring that we can't interfere
  // with other running evaluations, such as when in a multithreaded test
  // runner).
  ASSIGN_OR_RETURN(auto debug_server, vm::debug::CreateDebugServerFromFlags());
  auto instance = std::make_shared<vm::Instance>(std::move(debug_server));
  ASSIGN_OR_RETURN(auto driver, hal::DriverRegistry::shared_registry()->Create(
                                    target_backend));
  ASSIGN_OR_RETURN(auto device, driver->CreateDefaultDevice());
  RETURN_IF_ERROR(instance->device_manager()->RegisterDevice(device));
  vm::SequencerContext context(instance);

  if (absl::GetFlag(FLAGS_print_bytecode)) {
    vm::PrintModuleFlagBitfield print_flags = vm::PrintModuleFlag::kNone;
    RETURN_IF_ERROR(vm::PrintModuleToStream(vm::sequencer_opcode_table(),
                                            *module, print_flags, &std::cout));
  }

  // Register module with the context.
  RETURN_IF_ERROR(context.RegisterModule(std::move(module)));

  // Evaluate all exported functions.
  for (auto& module : context.modules()) {
    for (int function_ordinal : *module->def().function_table()->exports()) {
      ASSIGN_OR_RETURN(auto function, module->function_table().LookupFunction(
                                          function_ordinal));
      RETURN_IF_ERROR(
          EvaluateFunction(instance, &context, device->allocator(), function));
    }
  }

  RETURN_IF_ERROR(instance->device_manager()->UnregisterDevice(device.get()));
  device.reset();
  driver.reset();

  return OkStatus();
}

// Translates and runs a single LLVM file buffer.
Status EvaluateFile(std::unique_ptr<llvm::MemoryBuffer> file_buffer) {
  std::vector<std::string> target_backends;
  if (absl::GetFlag(FLAGS_target_backends).empty()) {
    target_backends =
        hal::DriverRegistry::shared_registry()->EnumerateAvailableDrivers();
  } else {
    // We need to map specific backends names to drivers (like 'vulkan-spirv' to
    // the driver 'vulkan').
    target_backends = absl::StrSplit(absl::GetFlag(FLAGS_target_backends), ',');
  }

  for (auto target_backend : target_backends) {
    // Prepare the module for execution and evaluate it.
    auto cloned_file_buffer = llvm::MemoryBuffer::getMemBufferCopy(
        file_buffer->getBuffer(), file_buffer->getBufferIdentifier());
    ASSIGN_OR_RETURN(auto module, PrepareModule(target_backend + '*',
                                                std::move(cloned_file_buffer)));
    if (!absl::GetFlag(FLAGS_run)) {
      continue;
    }
    RETURN_IF_ERROR(EvaluateFunctions(BackendToDriverName(target_backend),
                                      std::move(module)));
  }

  return OkStatus();
}

// Runs the given .mlir file based on the current flags.
Status RunFile(std::string mlir_filename) {
  // Load input file/from stdin.
  std::string error_message;
  auto file = mlir::openInputFile(mlir_filename, &error_message);
  if (!file) {
    return NotFoundErrorBuilder(IREE_LOC)
           << "Unable to open input file " << mlir_filename << ": "
           << error_message;
  }

  if (!absl::GetFlag(FLAGS_split_input_file)) {
    // Use entire buffer as a single module.
    return EvaluateFile(std::move(file));
  }

  // Split the buffer into separate modules and evaluate independently.
  // This matches the -split-input-file arg to mlir-opt.
  const char kSplitMarker[] = "// -----\n";
  auto* full_buffer = file.get();
  llvm::SmallVector<llvm::StringRef, 8> source_buffers;
  full_buffer->getBuffer().split(source_buffers, kSplitMarker);

  // Add the original buffer to the source manager.
  llvm::SourceMgr fileSourceMgr;
  fileSourceMgr.AddNewSourceBuffer(std::move(file), llvm::SMLoc());

  // Process each chunk in turn. Only return the first error (but log all).
  Status any_failure;
  for (auto& sub_source_buffer : source_buffers) {
    auto split_loc = llvm::SMLoc::getFromPointer(sub_source_buffer.data());
    unsigned split_line = fileSourceMgr.getLineAndColumn(split_loc).first;
    auto sub_buffer = llvm::MemoryBuffer::getMemBufferCopy(
        sub_source_buffer, full_buffer->getBufferIdentifier() +
                               llvm::Twine(" split at line #") +
                               llvm::Twine(split_line));
    auto sub_failure = EvaluateFile(std::move(sub_buffer));
    if (!sub_failure.ok()) {
      LOG(ERROR) << sub_failure;
      if (any_failure.ok()) {
        any_failure = std::move(sub_failure);
      }
    }
  }

  return any_failure;
}

}  // namespace

extern "C" int main(int argc, char** argv) {
  InitializeEnvironment(&argc, &argv);
  if (argc < 2) {
    LOG(ERROR) << "Must supply an input .mlir file.";
    return 1;
  }
  QCHECK_OK(RunFile(argv[1]));
  return 0;
}

}  // namespace iree
<commit_msg>Add missing header and replace use of old ABSL alias.<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// IREE source.mlir -> execution output test runner.
// This is meant to be called from LIT for FileCheck tests, and tries to match
// the interface of mlir-opt (featuring -split-input-file, etc) so it's easier
// to work with there. If you want a more generalized runner for standalone
// precompiled IREE modules use //third_party/iree/tools:run_module.
//
// By default all exported functions in the module will be run in order.
// All input values, provided via -input-values, will be passed to the
// functions (this means all input signatures must match). Results from the
// executed functions will be printed to stdout for checking.
// Use -output_types to set the function output data types, which like args will
// be used for all functions executed.
//
// Example input:
// // RUN: iree-run %s | FileCheck %s
// // CHECK-LABEL: @foo
// // CHECK: 1xf32: 2
// func @foo() -> memref<f32> attributes {iree.module.export} {
//   %0 = "iree.constant"() {value: dense<tensor<f32>, 2.0>} : () -> memref<f32>
//   return %0 : memref<f32>
// }

#include <iostream>

#include "absl/flags/flag.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "iree/base/init.h"
#include "iree/base/source_location.h"
#include "iree/base/status.h"
#include "iree/compiler/Translation/Sequencer/SequencerModuleTranslation.h"
#include "iree/hal/buffer_view_string_util.h"
#include "iree/hal/driver_registry.h"
#include "iree/schemas/module_def_generated.h"
#include "iree/vm/bytecode_tables_sequencer.h"
#include "iree/vm/debug/debug_server_flags.h"
#include "iree/vm/fiber_state.h"
#include "iree/vm/instance.h"
#include "iree/vm/module.h"
#include "iree/vm/module_printer.h"
#include "iree/vm/sequencer_context.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/SourceMgr.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Function.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/Module.h"
#include "mlir/Parser.h"
#include "mlir/Support/FileUtilities.h"

ABSL_FLAG(bool, split_input_file, true,
          "Split the input file into multiple modules.");

ABSL_FLAG(std::string, target_backends, "",
          "Comma-separated list of target backends to translate executables "
          "into. Omit to translate using all linked-in backend translators.");
ABSL_FLAG(
    bool, export_all, true,
    "Automatically add the iree.module.export attribute to all functions.");

ABSL_FLAG(std::string, input_values, "", "Input shapes and optional values.");
ABSL_FLAG(std::string, output_types, "",
          "Output data types (comma delimited list of b/i/u/f for "
          "binary/signed int/unsigned int/float).");

// TODO(benvanik): is there a more canonical flag we can use?
ABSL_FLAG(bool, print_mlir, true, "Prints MLIR IR during translation.");

ABSL_FLAG(bool, print_bytecode, false,
          "Prints IREE bytecode after translation.");

ABSL_FLAG(bool, run, true,
          "Option to run the file. Setting it to false just compiles it.");

namespace iree {
namespace {

using ::iree::hal::BufferView;
using ::iree::vm::Function;
using ::iree::vm::Module;
using ::iree::vm::ModuleFile;

// Returns a driver name capable of handling input from the given backend.
std::string BackendToDriverName(std::string backend) {
  size_t dash = backend.find('-');
  if (dash == std::string::npos) {
    return backend;
  } else {
    return backend.substr(0, dash);
  }
}

// Prepares a module for evaluation by running MLIR import and IREE translation.
StatusOr<std::unique_ptr<Module>> PrepareModule(
    std::string target_backend,
    std::unique_ptr<llvm::MemoryBuffer> file_buffer) {
  mlir::MLIRContext context;

  // Parse input MLIR module.
  llvm::SourceMgr source_mgr;
  source_mgr.AddNewSourceBuffer(std::move(file_buffer), llvm::SMLoc());
  mlir::OwningModuleRef mlir_module =
      mlir::parseSourceFile(source_mgr, &context);

  if (absl::GetFlag(FLAGS_export_all)) {
    for (auto function : mlir_module->getOps<mlir::FuncOp>()) {
      function.setAttr("iree.module.export", mlir::UnitAttr::get(&context));
    }
  }

  // Translate from MLIR to IREE bytecode.
  mlir::iree_compiler::ModuleTranslationOptions options;
  options.print_mlir = absl::GetFlag(FLAGS_print_mlir);
  options.target_backends = {target_backend};
  auto iree_module_bytes =
      mlir::iree_compiler::translateMlirToIreeSequencerModule(mlir_module.get(),
                                                              options);
  if (iree_module_bytes.empty()) {
    return iree::InternalErrorBuilder(IREE_LOC)
           << "Error translating MLIR to an IREE sequencer module";
  }

  if (absl::GetFlag(FLAGS_print_mlir)) {
    mlir_module->dump();
  }

  // Wrap module in a file handle.
  ASSIGN_OR_RETURN(auto iree_module_file,
                   ModuleFile::FromBuffer(ModuleDefIdentifier(),
                                          std::move(iree_module_bytes)));
  return Module::FromFile(std::move(iree_module_file));
}

// Parses a list of input shapes and values from a string of newline-separated
// inputs. Expects the contents to have one value per line with each value
// listed as
//   [shape]xtype=[value]
// Example:
//   4x4xi8=0,1,2,3
StatusOr<std::vector<BufferView>> ParseInputsFromFlags(
    hal::Allocator* allocator) {
  std::string file_contents =
      absl::StrReplaceAll(absl::GetFlag(FLAGS_input_values), {{"\\n", "\n"}});
  std::vector<BufferView> inputs;
  for (const auto& line :
       absl::StrSplit(file_contents, '\n', absl::SkipWhitespace())) {
    ASSIGN_OR_RETURN(auto input,
                     hal::ParseBufferViewFromString(line, allocator));
    inputs.push_back(input);
  }
  return inputs;
}

// Outputs all results from the function to stdout in IREE BufferView format.
Status OutputFunctionResults(const Function& function,
                             absl::Span<BufferView> results) {
  std::vector<std::string> output_types =
      absl::StrSplit(absl::GetFlag(FLAGS_output_types), absl::ByAnyChar(", "),
                     absl::SkipWhitespace());
  if (!output_types.empty() && output_types.size() != results.size()) {
    return InvalidArgumentErrorBuilder(IREE_LOC)
           << "--output_types= specified but has " << output_types.size()
           << " types when the function returns " << results.size();
  }

  for (int i = 0; i < results.size(); ++i) {
    const auto& result = results[i];
    auto print_mode = hal::BufferViewPrintMode::kFloatingPoint;
    if (!output_types.empty()) {
      ASSIGN_OR_RETURN(print_mode,
                       hal::ParseBufferViewPrintMode(output_types[i]));
    }
    ASSIGN_OR_RETURN(auto result_str,
                     hal::PrintBufferViewToString(result, print_mode, 1024));
    LOG(INFO) << "result[" << i << "]: " << result.buffer->DebugString();
    std::cout << result_str << "\n";
  }

  return OkStatus();
}

// Evaluates a single function in its own fiber, printing the results to stdout.
Status EvaluateFunction(std::shared_ptr<vm::Instance> instance,
                        vm::SequencerContext* context,
                        hal::Allocator* allocator, const Function& function) {
  // Setup our dummy fiber we will run with.
  vm::FiberState fiber_state(instance);

  std::cout << "EXEC @" << function.name() << std::endl;

  // Marshal inputs.
  ASSIGN_OR_RETURN(std::vector<BufferView> args,
                   ParseInputsFromFlags(allocator));
  std::vector<BufferView> results;
  results.resize(function.result_count());

  // Call into the main function.
  RETURN_IF_ERROR(context->Invoke(&fiber_state, function, absl::MakeSpan(args),
                                  absl::MakeSpan(results)));

  // Print outputs.
  RETURN_IF_ERROR(OutputFunctionResults(function, absl::MakeSpan(results)));

  return OkStatus();
}

// Evaluates all exported functions within given module.
Status EvaluateFunctions(absl::string_view target_backend,
                         std::unique_ptr<Module> module) {
  // Create the context we'll use for this (ensuring that we can't interfere
  // with other running evaluations, such as when in a multithreaded test
  // runner).
  ASSIGN_OR_RETURN(auto debug_server, vm::debug::CreateDebugServerFromFlags());
  auto instance = std::make_shared<vm::Instance>(std::move(debug_server));
  ASSIGN_OR_RETURN(auto driver, hal::DriverRegistry::shared_registry()->Create(
                                    target_backend));
  ASSIGN_OR_RETURN(auto device, driver->CreateDefaultDevice());
  RETURN_IF_ERROR(instance->device_manager()->RegisterDevice(device));
  vm::SequencerContext context(instance);

  if (absl::GetFlag(FLAGS_print_bytecode)) {
    vm::PrintModuleFlagBitfield print_flags = vm::PrintModuleFlag::kNone;
    RETURN_IF_ERROR(vm::PrintModuleToStream(vm::sequencer_opcode_table(),
                                            *module, print_flags, &std::cout));
  }

  // Register module with the context.
  RETURN_IF_ERROR(context.RegisterModule(std::move(module)));

  // Evaluate all exported functions.
  for (auto& module : context.modules()) {
    for (int function_ordinal : *module->def().function_table()->exports()) {
      ASSIGN_OR_RETURN(auto function, module->function_table().LookupFunction(
                                          function_ordinal));
      RETURN_IF_ERROR(
          EvaluateFunction(instance, &context, device->allocator(), function));
    }
  }

  RETURN_IF_ERROR(instance->device_manager()->UnregisterDevice(device.get()));
  device.reset();
  driver.reset();

  return OkStatus();
}

// Translates and runs a single LLVM file buffer.
Status EvaluateFile(std::unique_ptr<llvm::MemoryBuffer> file_buffer) {
  std::vector<std::string> target_backends;
  if (absl::GetFlag(FLAGS_target_backends).empty()) {
    target_backends =
        hal::DriverRegistry::shared_registry()->EnumerateAvailableDrivers();
  } else {
    // We need to map specific backends names to drivers (like 'vulkan-spirv' to
    // the driver 'vulkan').
    target_backends = absl::StrSplit(absl::GetFlag(FLAGS_target_backends), ',');
  }

  for (auto target_backend : target_backends) {
    // Prepare the module for execution and evaluate it.
    auto cloned_file_buffer = llvm::MemoryBuffer::getMemBufferCopy(
        file_buffer->getBuffer(), file_buffer->getBufferIdentifier());
    ASSIGN_OR_RETURN(auto module, PrepareModule(target_backend + '*',
                                                std::move(cloned_file_buffer)));
    if (!absl::GetFlag(FLAGS_run)) {
      continue;
    }
    RETURN_IF_ERROR(EvaluateFunctions(BackendToDriverName(target_backend),
                                      std::move(module)));
  }

  return OkStatus();
}

// Runs the given .mlir file based on the current flags.
Status RunFile(std::string mlir_filename) {
  // Load input file/from stdin.
  std::string error_message;
  auto file = mlir::openInputFile(mlir_filename, &error_message);
  if (!file) {
    return NotFoundErrorBuilder(IREE_LOC)
           << "Unable to open input file " << mlir_filename << ": "
           << error_message;
  }

  if (!absl::GetFlag(FLAGS_split_input_file)) {
    // Use entire buffer as a single module.
    return EvaluateFile(std::move(file));
  }

  // Split the buffer into separate modules and evaluate independently.
  // This matches the -split-input-file arg to mlir-opt.
  const char kSplitMarker[] = "// -----\n";
  auto* full_buffer = file.get();
  llvm::SmallVector<llvm::StringRef, 8> source_buffers;
  full_buffer->getBuffer().split(source_buffers, kSplitMarker);

  // Add the original buffer to the source manager.
  llvm::SourceMgr fileSourceMgr;
  fileSourceMgr.AddNewSourceBuffer(std::move(file), llvm::SMLoc());

  // Process each chunk in turn. Only return the first error (but log all).
  Status any_failure;
  for (auto& sub_source_buffer : source_buffers) {
    auto split_loc = llvm::SMLoc::getFromPointer(sub_source_buffer.data());
    unsigned split_line = fileSourceMgr.getLineAndColumn(split_loc).first;
    auto sub_buffer = llvm::MemoryBuffer::getMemBufferCopy(
        sub_source_buffer, full_buffer->getBufferIdentifier() +
                               llvm::Twine(" split at line #") +
                               llvm::Twine(split_line));
    auto sub_failure = EvaluateFile(std::move(sub_buffer));
    if (!sub_failure.ok()) {
      LOG(ERROR) << sub_failure;
      if (any_failure.ok()) {
        any_failure = std::move(sub_failure);
      }
    }
  }

  return any_failure;
}

}  // namespace

extern "C" int main(int argc, char** argv) {
  InitializeEnvironment(&argc, &argv);
  if (argc < 2) {
    LOG(ERROR) << "Must supply an input .mlir file.";
    return 1;
  }
  QCHECK_OK(RunFile(argv[1]));
  return 0;
}

}  // namespace iree
<|endoftext|>