tdf#126960, tdf#131330: FB make views editable+refresh auto after creation

Change-Id: I78783056659a26cc8139d74eefc225de1a11ca7a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129011
Reviewed-by: Julien Nabet <serval2412@yahoo.fr>
(cherry picked from commit 0adff3f2476f797843fb62d6810de90bfb333e10)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129067
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
diff --git a/connectivity/Library_firebird_sdbc.mk b/connectivity/Library_firebird_sdbc.mk
index 5fb596e..6b1045b 100644
--- a/connectivity/Library_firebird_sdbc.mk
+++ b/connectivity/Library_firebird_sdbc.mk
@@ -61,6 +61,8 @@ $(eval $(call gb_Library_add_exception_objects,firebird_sdbc,\
    connectivity/source/drivers/firebird/User \
    connectivity/source/drivers/firebird/Users \
    connectivity/source/drivers/firebird/Util \
    connectivity/source/drivers/firebird/View \
    connectivity/source/drivers/firebird/Views \
))

# vim: set noet sw=4 ts=4:
diff --git a/connectivity/source/drivers/firebird/Catalog.cxx b/connectivity/source/drivers/firebird/Catalog.cxx
index c743b42c..2ef4f51 100644
--- a/connectivity/source/drivers/firebird/Catalog.cxx
+++ b/connectivity/source/drivers/firebird/Catalog.cxx
@@ -10,6 +10,7 @@
#include "Catalog.hxx"
#include "Tables.hxx"
#include "Users.hxx"
#include "Views.hxx"

#include <com/sun/star/sdbc/XRow.hpp>

@@ -53,8 +54,20 @@ void Catalog::refreshTables()

void Catalog::refreshViews()
{
    // TODO: implement me.
    // Sets m_pViews (OCatalog)
    css::uno::Reference<css::sdbc::XResultSet> xViews
        = m_xMetaData->getTables(css::uno::Any(), "%", "%", { "VIEW" });

    if (!xViews.is())
        return;

    ::std::vector<OUString> aViewNames;

    fillNames(xViews, aViewNames);

    if (!m_pViews)
        m_pViews.reset(new Views(m_xConnection, *this, m_aMutex, aViewNames));
    else
        m_pViews->reFill(aViewNames);
}

//----- IRefreshableGroups ---------------------------------------------------
diff --git a/connectivity/source/drivers/firebird/Catalog.hxx b/connectivity/source/drivers/firebird/Catalog.hxx
index 4a562e2..b6bf02f 100644
--- a/connectivity/source/drivers/firebird/Catalog.hxx
+++ b/connectivity/source/drivers/firebird/Catalog.hxx
@@ -30,6 +30,8 @@ namespace connectivity::firebird

            // IRefreshableUsers
            virtual void refreshUsers() override;

            sdbcx::OCollection* getPrivateTables() const { return m_pTables.get(); }
        };

} // namespace connectivity::firebird
diff --git a/connectivity/source/drivers/firebird/Tables.cxx b/connectivity/source/drivers/firebird/Tables.cxx
index ebd6f23..06e6806 100644
--- a/connectivity/source/drivers/firebird/Tables.cxx
+++ b/connectivity/source/drivers/firebird/Tables.cxx
@@ -205,4 +205,18 @@ void Tables::dropObject(sal_Int32 nPosition, const OUString& sName)
        "DROP " + sType + ::dbtools::quoteName(sQuoteString,sName));
}

void connectivity::firebird::Tables::appendNew(const OUString& _rsNewTable)
{
    insertElement(_rsNewTable, nullptr);

    // notify our container listeners
    css::container::ContainerEvent aEvent(static_cast<XContainer*>(this),
                                          css::uno::makeAny(_rsNewTable), css::uno::Any(),
                                          css::uno::Any());
    ::comphelper::OInterfaceIteratorHelper2 aListenerLoop(m_aContainerListeners);
    while (aListenerLoop.hasMoreElements())
        static_cast<XContainerListener*>(aListenerLoop.next())->elementInserted(aEvent);
}


/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Tables.hxx b/connectivity/source/drivers/firebird/Tables.hxx
index d7fe019..7d84edb 100644
--- a/connectivity/source/drivers/firebird/Tables.hxx
+++ b/connectivity/source/drivers/firebird/Tables.hxx
@@ -51,6 +51,8 @@ namespace connectivity::firebird
            // XDrop
            virtual void dropObject(sal_Int32 nPosition, const OUString& rName) override;

            void appendNew(const OUString& _rsNewTable);

        };

} // namespace connectivity::firebird
diff --git a/connectivity/source/drivers/firebird/View.cxx b/connectivity/source/drivers/firebird/View.cxx
new file mode 100644
index 0000000..506cafb
--- /dev/null
+++ b/connectivity/source/drivers/firebird/View.cxx
@@ -0,0 +1,90 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#include "View.hxx"
#include <iostream>

#include <propertyids.hxx>

#include <com/sun/star/sdbc/XRow.hpp>

namespace connectivity::firebird
{
View::View(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection, bool _bCaseSensitive,
           const OUString& _rSchemaName, const OUString& _rName)
    : View_Base(_bCaseSensitive, _rName, _rxConnection->getMetaData(), OUString(), _rSchemaName,
                OUString())
    , m_xConnection(_rxConnection)
{
}

View::~View() {}

void SAL_CALL View::acquire() noexcept { View_Base::acquire(); };
void SAL_CALL View::release() noexcept { View_Base::release(); };
css::uno::Any SAL_CALL View::queryInterface(const css::uno::Type& _rType)
{
    css::uno::Any aReturn = View_Base::queryInterface(_rType);
    if (!aReturn.hasValue())
        aReturn = View_IBASE::queryInterface(_rType);
    return aReturn;
}

css::uno::Sequence<css::uno::Type> SAL_CALL View::getTypes()
{
    return ::comphelper::concatSequences(View_Base::getTypes(), View_IBASE::getTypes());
}

css::uno::Sequence<sal_Int8> SAL_CALL View::getImplementationId()
{
    return css::uno::Sequence<sal_Int8>();
}

void SAL_CALL View::alterCommand(const OUString& _rNewCommand)
{
    OUString aCommand = "ALTER VIEW \"" + m_Name + "\" AS " + _rNewCommand;
    m_xMetaData->getConnection()->createStatement()->execute(aCommand);
}

void SAL_CALL View::getFastPropertyValue(css::uno::Any& _rValue, sal_Int32 _nHandle) const
{
    if (_nHandle == PROPERTY_ID_COMMAND)
    {
        // retrieve the very current command, don't rely on the base classes cached value
        // (which we initialized empty, anyway)
        _rValue <<= impl_getCommand();
        return;
    }

    View_Base::getFastPropertyValue(_rValue, _nHandle);
}

OUString View::impl_getCommand() const
{
    OUString aCommand("SELECT RDB$VIEW_SOURCE FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = '"
                      + m_Name + "'");
    std::cerr << "TODO aCommand=" << aCommand << "\n";
    // OUString aCommand("SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = '"
    //                  + m_SchemaName + "' AND TABLE_NAME = '" + m_Name + "'");
    //::utl::SharedUNOComponent< XStatement > xStatement; xStatement.set( m_xConnection->createStatement(), UNO_QUERY_THROW );
    css::uno::Reference<css::sdbc::XStatement> statement = m_xConnection->createStatement();
    css::uno::Reference<css::sdbc::XResultSet> xResult = statement->executeQuery(aCommand);

    css::uno::Reference<css::sdbc::XRow> xRow(xResult, css::uno::UNO_QUERY_THROW);
    if (!xResult->next())
    {
        // hmm. There is no view the name as we know it. Can only mean some other instance
        // dropped this view meanwhile...
        std::abort();
    }

    return xRow->getString(1);
}

} // namespace connectivity::firebird
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/View.hxx b/connectivity/source/drivers/firebird/View.hxx
new file mode 100644
index 0000000..2b300a8
--- /dev/null
+++ b/connectivity/source/drivers/firebird/View.hxx
@@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#pragma once

#include <connectivity/sdbcx/VView.hxx>

#include <com/sun/star/sdbcx/XAlterView.hpp>
#include <com/sun/star/sdbc/XConnection.hpp>

#include <comphelper/sequence.hxx>
#include <cppuhelper/implbase1.hxx>

namespace connectivity::firebird
{
typedef ::connectivity::sdbcx::OView View_Base;
typedef ::cppu::ImplHelper1<css::sdbcx::XAlterView> View_IBASE;

class View : public View_Base, public View_IBASE
{
public:
    View(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection, bool _bCaseSensitive,
         const OUString& _rSchemaName, const OUString& _rName);

    // UNO
    virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& aType) override;
    virtual void SAL_CALL acquire() noexcept override;
    virtual void SAL_CALL release() noexcept override;

    virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
    virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;

    // XAlterView
    virtual void SAL_CALL alterCommand(const OUString& NewCommand) override;

protected:
    virtual ~View() override;

protected:
    // OPropertyContainer
    virtual void SAL_CALL getFastPropertyValue(css::uno::Any& _rValue,
                                               sal_Int32 _nHandle) const override;

private:
    /** retrieves the current command of the View */
    OUString impl_getCommand() const;

private:
    css::uno::Reference<css::sdbc::XConnection> m_xConnection;

    using View_Base::getFastPropertyValue;
};

} // namespace connectivity::firebird
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Views.cxx b/connectivity/source/drivers/firebird/Views.cxx
new file mode 100644
index 0000000..2e5bec4
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Views.cxx
@@ -0,0 +1,112 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#include "Tables.hxx"
#include "Views.hxx"
#include "View.hxx"
#include "Catalog.hxx"
#include <connectivity/dbtools.hxx>
#include <comphelper/types.hxx>
#include <TConnection.hxx>

connectivity::firebird::Views::Views(
    const css::uno::Reference<css::sdbc::XConnection>& _rxConnection, ::cppu::OWeakObject& _rParent,
    ::osl::Mutex& _rMutex, const ::std::vector<OUString>& _rVector)
    : sdbcx::OCollection(_rParent, true, _rMutex, _rVector)
    , m_xConnection(_rxConnection)
    , m_xMetaData(_rxConnection->getMetaData())
    , m_bInDrop(false)
{
}

connectivity::sdbcx::ObjectType connectivity::firebird::Views::createObject(const OUString& _rName)
{
    OUString sCatalog, sSchema, sTable;
    ::dbtools::qualifiedNameComponents(m_xMetaData, _rName, sCatalog, sSchema, sTable,
                                       ::dbtools::EComposeRule::InDataManipulation);
    return new View(m_xConnection, isCaseSensitive(), sSchema, sTable);
}

void connectivity::firebird::Views::impl_refresh()
{
    static_cast<Catalog&>(m_rParent).refreshViews();
}

css::uno::Reference<css::beans::XPropertySet> connectivity::firebird::Views::createDescriptor()
{
    return new connectivity::sdbcx::OView(true, m_xMetaData);
}

// XAppend
connectivity::sdbcx::ObjectType connectivity::firebird::Views::appendObject(
    const OUString& _rForName, const css::uno::Reference<css::beans::XPropertySet>& descriptor)
{
    createView(descriptor);
    return createObject(_rForName);
}

// XDrop
void connectivity::firebird::Views::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/)
{
    if (m_bInDrop)
        return;

    css::uno::Reference<XInterface> xObject(getObject(_nPos));
    bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject);
    if (!bIsNew)
    {
        OUString aSql("DROP VIEW");

        css::uno::Reference<css::beans::XPropertySet> xProp(xObject, css::uno::UNO_QUERY);
        aSql += ::dbtools::composeTableName(m_xMetaData, xProp,
                                            ::dbtools::EComposeRule::InTableDefinitions, true);

        css::uno::Reference<css::sdbc::XConnection> xConnection = m_xMetaData->getConnection();
        css::uno::Reference<css::sdbc::XStatement> xStmt = xConnection->createStatement();
        xStmt->execute(aSql);
        ::comphelper::disposeComponent(xStmt);
    }
}

void connectivity::firebird::Views::dropByNameImpl(const OUString& elementName)
{
    m_bInDrop = true;
    connectivity::sdbcx::OCollection::dropByName(elementName);
    m_bInDrop = false;
}

void connectivity::firebird::Views::createView(
    const css::uno::Reference<css::beans::XPropertySet>& descriptor)
{
    css::uno::Reference<css::sdbc::XConnection> xConnection = m_xMetaData->getConnection();

    OUString sCommand;
    descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND))
        >>= sCommand;

    OUString aSql = "CREATE VIEW "
                    + ::dbtools::composeTableName(m_xMetaData, descriptor,
                                                  ::dbtools::EComposeRule::InTableDefinitions, true)
                    + " AS " + sCommand;

    css::uno::Reference<css::sdbc::XStatement> xStmt = xConnection->createStatement();
    if (xStmt.is())
    {
        xStmt->execute(aSql);
        ::comphelper::disposeComponent(xStmt);
    }
    connectivity::firebird::Tables* pTables = static_cast<connectivity::firebird::Tables*>(
        static_cast<connectivity::firebird::Catalog&>(m_rParent).getPrivateTables());
    if (pTables)
    {
        OUString sName = ::dbtools::composeTableName(
            m_xMetaData, descriptor, ::dbtools::EComposeRule::InDataManipulation, false);
        pTables->appendNew(sName);
    }
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/drivers/firebird/Views.hxx b/connectivity/source/drivers/firebird/Views.hxx
new file mode 100644
index 0000000..6887bdc
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Views.hxx
@@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#pragma once

#include <connectivity/sdbcx/VCollection.hxx>
#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
namespace connectivity::firebird
{
class Views final : public connectivity::sdbcx::OCollection
{
    css::uno::Reference<css::sdbc::XConnection> m_xConnection;
    css::uno::Reference<css::sdbc::XDatabaseMetaData> m_xMetaData;
    bool m_bInDrop;

    // OCollection
    virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
    virtual void impl_refresh() override;
    virtual css::uno::Reference<css::beans::XPropertySet> createDescriptor() override;
    virtual sdbcx::ObjectType
    appendObject(const OUString& _rForName,
                 const css::uno::Reference<css::beans::XPropertySet>& descriptor) override;

    void createView(const css::uno::Reference<css::beans::XPropertySet>& descriptor);

public:
    Views(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection,
          ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
          const ::std::vector<OUString>& _rVector);

    // XDrop
    virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;

    void dropByNameImpl(const OUString& elementName);
};
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */