view Framework/Common/DatabaseManager.h @ 33:860542a0a64b OrthancPostgreSQL-2.2

set version
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 16 Jul 2018 17:16:27 +0200
parents 2fb9cd42af14
children 714c5d2bee76
line wrap: on
line source

/**
 * Orthanc - A Lightweight, RESTful DICOM Store
 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
 * Department, University Hospital of Liege, Belgium
 * Copyright (C) 2017-2018 Osimis S.A., Belgium
 *
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program 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
 * Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 **/


#pragma once

#include "IDatabaseFactory.h"
#include "StatementLocation.h"

#include <Core/Enumerations.h>

#include <boost/thread/recursive_mutex.hpp>
#include <memory>

namespace OrthancDatabases
{
  class DatabaseManager : public boost::noncopyable
  {
  private:
    typedef std::map<StatementLocation, IPrecompiledStatement*>  CachedStatements;

    boost::recursive_mutex           mutex_;
    std::auto_ptr<IDatabaseFactory>  factory_;
    std::auto_ptr<IDatabase>         database_;
    std::auto_ptr<ITransaction>      transaction_;
    CachedStatements                 cachedStatements_;
    Dialect                          dialect_;

    IDatabase& GetDatabase();

    void CloseIfUnavailable(Orthanc::ErrorCode e);

    IPrecompiledStatement* LookupCachedStatement(const StatementLocation& location) const;

    IPrecompiledStatement& CacheStatement(const StatementLocation& location,
                                          const Query& query);

    ITransaction& GetTransaction();

    void ReleaseImplicitTransaction();

  public:
    explicit DatabaseManager(IDatabaseFactory* factory);  // Takes ownership
    
    ~DatabaseManager()
    {
      Close();
    }

    Dialect GetDialect() const
    {
      return dialect_;
    }

    void Open()
    {
      GetDatabase();
    }

    void Close();
    
    void StartTransaction();

    void CommitTransaction();
    
    void RollbackTransaction();


    // This class is only used in the "StorageBackend"
    class Transaction : public boost::noncopyable
    {
    private:
      boost::recursive_mutex::scoped_lock  lock_;
      DatabaseManager&                     manager_;
      IDatabase&                           database_;
      bool                                 committed_;

    public:
      explicit Transaction(DatabaseManager& manager);

      ~Transaction();

      void Commit();

      DatabaseManager& GetManager()
      {
        return manager_;
      }

      IDatabase& GetDatabase()
      {
        return database_;
      }
    };


    class CachedStatement : public boost::noncopyable
    {
    private:
      DatabaseManager&                     manager_;
      boost::recursive_mutex::scoped_lock  lock_;
      IDatabase&                           database_;
      StatementLocation                    location_;
      ITransaction&                        transaction_;
      IPrecompiledStatement*               statement_;
      std::auto_ptr<Query>                 query_;
      std::auto_ptr<IResult>               result_;

      void Setup(const char* sql);

      IResult& GetResult() const;

    public:
      CachedStatement(const StatementLocation& location,
                      DatabaseManager& manager,
                      const char* sql);

      CachedStatement(const StatementLocation& location,
                      Transaction& transaction,
                      const char* sql);

      ~CachedStatement();

      IDatabase& GetDatabase()
      {
        return database_;
      }

      void SetReadOnly(bool readOnly);

      void SetParameterType(const std::string& parameter,
                            ValueType type);
      
      void Execute();

      void Execute(const Dictionary& parameters);

      bool IsDone() const;
      
      void Next();

      size_t GetResultFieldsCount() const;

      void SetResultFieldType(size_t field,
                              ValueType type);
      
      const IValue& GetResultField(size_t index) const;
    };
  };
}