changeset 0:1d7c4b961831

initial release
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 12 Feb 2015 16:05:39 +0100
parents
children 5acd659b3465
files AUTHORS CMakeLists.txt COPYING Core/Configuration.cpp Core/Configuration.h Core/GlobalProperties.cpp Core/GlobalProperties.h Core/GlobalProperties.sql Core/PostgreSQLConnection.cpp Core/PostgreSQLConnection.h Core/PostgreSQLException.h Core/PostgreSQLLargeObject.cpp Core/PostgreSQLLargeObject.h Core/PostgreSQLResult.cpp Core/PostgreSQLResult.h Core/PostgreSQLStatement.cpp Core/PostgreSQLStatement.h Core/PostgreSQLTransaction.cpp Core/PostgreSQLTransaction.h IndexPlugin/Plugin.cpp IndexPlugin/PostgreSQLPrepare.sql IndexPlugin/PostgreSQLUpserts.sql IndexPlugin/PostgreSQLWrapper.cpp IndexPlugin/PostgreSQLWrapper.h NEWS README Resources/CMake/AutoGeneratedCode.cmake Resources/CMake/BoostConfiguration.cmake Resources/CMake/DownloadPackage.cmake Resources/CMake/FindPostgreSQL.cmake Resources/CMake/GoogleTestConfiguration.cmake Resources/CMake/JsonCppConfiguration.cmake Resources/CMake/PostgreSQLConfiguration.cmake Resources/EmbedResources.py Resources/Platforms/pg_config-linux32.h Resources/Platforms/pg_config-linux64.h Resources/Platforms/pg_config-windows32.h Resources/Platforms/pg_config-windows64.h Resources/Platforms/pg_config_ext.h Resources/VersionScript.map StoragePlugin/Plugin.cpp StoragePlugin/PostgreSQLStorageArea.cpp StoragePlugin/PostgreSQLStorageArea.h UnitTestsSources/PostgreSQLTests.cpp UnitTestsSources/PostgreSQLWrapperTests.cpp UnitTestsSources/UnitTestsMain.cpp
diffstat 46 files changed, 10419 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AUTHORS	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,13 @@
+PostgreSQL plugin for Orthanc
+=============================
+
+
+Authors
+-------
+
+* Sebastien Jodogne <s.jodogne@gmail.com>
+  Department of Medical Physics
+  University Hospital of Liege
+  Belgium
+
+  Overall design and lead developer.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CMakeLists.txt	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,136 @@
+# Orthanc - A Lightweight, RESTful DICOM Store
+# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+# Department, University Hospital of Liege, 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/>.
+
+
+cmake_minimum_required(VERSION 2.8)
+
+project(OrthancPostgreSQL)
+
+# Parameters of the build
+set(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)")
+set(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages")
+
+# Advanced parameters to fine-tune linking against system libraries
+set(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp")
+set(USE_SYSTEM_BOOST ON CACHE BOOL "Use the system version of Boost")
+set(USE_SYSTEM_GOOGLE_TEST ON CACHE BOOL "Use the system version of Google Test")
+set(USE_SYSTEM_LIBPQ ON CACHE BOOL "Use the system version of the PostgreSQL client library")
+
+# Distribution-specific settings
+set(USE_GTEST_DEBIAN_SOURCE_PACKAGE OFF CACHE BOOL "Use the sources of Google Test shipped with libgtest-dev (Debian only)")
+mark_as_advanced(USE_GTEST_DEBIAN_SOURCE_PACKAGE)
+
+# Force static build when cross-compiling
+if (CMAKE_CROSSCOMPILING)
+  set(STATIC_BUILD ON)
+endif()
+
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+  link_libraries(uuid)
+  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pthread")
+elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+  link_libraries(rpcrt4 ws2_32 secur32)
+  if (CMAKE_COMPILER_IS_GNUCXX)
+    SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc -static-libstdc++")
+  endif()
+endif ()
+
+if (CMAKE_COMPILER_IS_GNUCXX)
+  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/Resources/VersionScript.map -Wl,--no-undefined")
+endif()
+
+
+include(CheckIncludeFiles)
+include(CheckIncludeFileCXX)
+include(CheckLibraryExists)
+include(${CMAKE_SOURCE_DIR}/Resources/CMake/AutoGeneratedCode.cmake)
+include(${CMAKE_SOURCE_DIR}/Resources/CMake/DownloadPackage.cmake)
+include(${CMAKE_SOURCE_DIR}/Resources/CMake/BoostConfiguration.cmake)
+include(${CMAKE_SOURCE_DIR}/Resources/CMake/PostgreSQLConfiguration.cmake)
+include(${CMAKE_SOURCE_DIR}/Resources/CMake/JsonCppConfiguration.cmake)
+include(${CMAKE_SOURCE_DIR}/Resources/CMake/GoogleTestConfiguration.cmake)
+
+
+# Check that the Orthanc SDK headers are available or download them
+if (STATIC_BUILD)
+  set(ORTHANC_SDK_URL "http://orthanc.googlecode.com/hg") # TODO use 0.8.6 release
+  file(MAKE_DIRECTORY ${AUTOGENERATED_DIR}/orthanc)
+  file(DOWNLOAD "${ORTHANC_SDK_URL}/Plugins/Include/OrthancCPlugin.h"
+    "${AUTOGENERATED_DIR}/orthanc/OrthancCPlugin.h" SHOW_PROGRESS)
+  file(DOWNLOAD "${ORTHANC_SDK_URL}/Plugins/Include/OrthancCDatabasePlugin.h"
+    "${AUTOGENERATED_DIR}/orthanc/OrthancCDatabasePlugin.h" SHOW_PROGRESS)
+  file(DOWNLOAD "${ORTHANC_SDK_URL}/Plugins/Include/OrthancCppDatabasePlugin.h" 
+    "${AUTOGENERATED_DIR}/orthanc/OrthancCppDatabasePlugin.h" SHOW_PROGRESS)
+  if (${MSVC})
+    add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
+    file(DOWNLOAD "${ORTHANC_SDK_URL}/Resources/ThirdParty/VisualStudio/stdint.h" 
+      "${AUTOGENERATED_DIR}/stdint.h" SHOW_PROGRESS)
+  endif()
+else ()
+  CHECK_INCLUDE_FILE_CXX(orthanc/OrthancCppDatabasePlugin.h HAVE_ORTHANC_H)
+  if (NOT HAVE_ORTHANC_H)
+    message(FATAL_ERROR "Please install the headers of the Orthanc plugins SDK")
+  endif()
+endif()
+
+
+# Embed the SQL files into the binaries
+EmbedResources(
+  GLOBAL_PROPERTIES  ${CMAKE_CURRENT_SOURCE_DIR}/Core/GlobalProperties.sql
+  POSTGRESQL_PREPARE ${CMAKE_CURRENT_SOURCE_DIR}/IndexPlugin/PostgreSQLPrepare.sql
+  POSTGRESQL_UPSERTS ${CMAKE_CURRENT_SOURCE_DIR}/IndexPlugin/PostgreSQLUpserts.sql
+  )
+
+set(CORE_SOURCES
+  ${CMAKE_SOURCE_DIR}/Core/PostgreSQLConnection.cpp
+  ${CMAKE_SOURCE_DIR}/Core/PostgreSQLLargeObject.cpp
+  ${CMAKE_SOURCE_DIR}/Core/PostgreSQLResult.cpp
+  ${CMAKE_SOURCE_DIR}/Core/PostgreSQLStatement.cpp
+  ${CMAKE_SOURCE_DIR}/Core/PostgreSQLTransaction.cpp
+  ${CMAKE_SOURCE_DIR}/Core/Configuration.cpp
+  ${CMAKE_SOURCE_DIR}/Core/GlobalProperties.cpp
+
+  ${LIBPQ_SOURCES}
+  ${BOOST_SOURCES}
+  ${JSONCPP_SOURCES}
+  ${AUTOGENERATED_SOURCES}
+  )
+
+add_library(OrthancPostgreSQLStorage
+  SHARED
+  ${CORE_SOURCES}
+  ${CMAKE_SOURCE_DIR}/StoragePlugin/PostgreSQLStorageArea.cpp
+  ${CMAKE_SOURCE_DIR}/StoragePlugin/Plugin.cpp
+  )
+
+add_library(OrthancPostgreSQLIndex
+  SHARED
+  ${CORE_SOURCES}
+  ${AUTOGENERATED_SOURCES}
+  ${CMAKE_SOURCE_DIR}/IndexPlugin/PostgreSQLWrapper.cpp
+  ${CMAKE_SOURCE_DIR}/IndexPlugin/Plugin.cpp
+  )
+
+add_executable(UnitTests
+  ${CORE_SOURCES}
+  ${GTEST_SOURCES}
+  ${CMAKE_SOURCE_DIR}/IndexPlugin/PostgreSQLWrapper.cpp
+  ${CMAKE_SOURCE_DIR}/StoragePlugin/PostgreSQLStorageArea.cpp
+  ${CMAKE_SOURCE_DIR}/UnitTestsSources/UnitTestsMain.cpp
+  ${CMAKE_SOURCE_DIR}/UnitTestsSources/PostgreSQLTests.cpp
+  ${CMAKE_SOURCE_DIR}/UnitTestsSources/PostgreSQLWrapperTests.cpp
+  )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/COPYING	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,661 @@
+                    GNU AFFERO GENERAL PUBLIC LICENSE
+                       Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+  A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate.  Many developers of free software are heartened and
+encouraged by the resulting cooperation.  However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+  The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community.  It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server.  Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+  An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals.  This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU Affero General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Remote Network Interaction; Use with the GNU General Public License.
+
+  Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software.  This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time.  Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source.  For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code.  There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Configuration.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,178 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "Configuration.h"
+
+#include "PostgreSQLException.h"
+
+#include <fstream>
+#include <json/reader.h>
+#include <memory>
+
+
+// For UUID generation
+extern "C"
+{
+#ifdef WIN32
+#include <rpc.h>
+#else
+#include <uuid/uuid.h>
+#endif
+}
+
+
+namespace OrthancPlugins
+{
+  bool ReadConfiguration(Json::Value& configuration,
+                         OrthancPluginContext* context)
+  {
+    std::string path;
+
+    {
+      char* pathTmp = OrthancPluginGetConfigurationPath(context);
+      if (pathTmp == NULL)
+      {
+        OrthancPluginLogError(context, "No configuration file is provided");
+        return false;
+      }
+
+      path = std::string(pathTmp);
+
+      OrthancPluginFreeString(context, pathTmp);
+    }
+
+    std::ifstream f(path.c_str());
+
+    Json::Reader reader;
+    if (!reader.parse(f, configuration) ||
+        configuration.type() != Json::objectValue)
+    {
+      std::string s = "Unable to parse the configuration file: " + std::string(path);
+      OrthancPluginLogError(context, s.c_str());
+      return false;
+    }
+
+    return true;
+  }
+
+
+  std::string GetStringValue(const Json::Value& configuration,
+                             const std::string& key,
+                             const std::string& defaultValue)
+  {
+    if (configuration.type() != Json::objectValue ||
+        !configuration.isMember(key) ||
+        configuration[key].type() != Json::stringValue)
+    {
+      return defaultValue;
+    }
+    else
+    {
+      return configuration[key].asString();
+    }
+  }
+
+
+  int GetIntegerValue(const Json::Value& configuration,
+                      const std::string& key,
+                      int defaultValue)
+  {
+    if (configuration.type() != Json::objectValue ||
+        !configuration.isMember(key) ||
+        configuration[key].type() != Json::intValue)
+    {
+      return defaultValue;
+    }
+    else
+    {
+      return configuration[key].asInt();
+    }
+  }
+
+
+  PostgreSQLConnection* CreateConnection(OrthancPluginContext* context)
+  {
+    Json::Value configuration;
+    if (!ReadConfiguration(configuration, context))
+    {
+      return NULL;
+    }
+
+    std::auto_ptr<PostgreSQLConnection> connection(new PostgreSQLConnection);
+
+    if (configuration.isMember("PostgreSQL"))
+    {
+      Json::Value c = configuration["PostgreSQL"];  
+      connection->SetHost(GetStringValue(c, "Host", "localhost"));
+      connection->SetPortNumber(GetIntegerValue(c, "Port", 5432));
+      connection->SetDatabase(GetStringValue(c, "Database", "orthanc"));
+      connection->SetUsername(GetStringValue(c, "Username", "orthanc"));
+      connection->SetPassword(GetStringValue(c, "Password", "orthanc"));
+    }
+
+    connection->Open();
+
+    return connection.release();
+  }
+
+
+  std::string GenerateUuid()
+  {
+#ifdef WIN32
+    UUID uuid;
+    UuidCreate ( &uuid );
+
+    unsigned char * str;
+    UuidToStringA ( &uuid, &str );
+
+    std::string s( ( char* ) str );
+
+    RpcStringFreeA ( &str );
+#else
+    uuid_t uuid;
+    uuid_generate_random ( uuid );
+    char s[37];
+    uuid_unparse ( uuid, s );
+#endif
+    return s;
+  }
+
+
+  bool IsFlagInCommandLineArguments(OrthancPluginContext* context,
+                                    const std::string& flag)
+  {
+    uint32_t count = OrthancPluginGetCommandLineArgumentsCount(context);
+
+    for (uint32_t i = 0; i < count; i++)
+    {
+      char* tmp = OrthancPluginGetCommandLineArgument(context, i);
+      std::string arg(tmp);
+      OrthancPluginFreeString(context, tmp);
+
+      if (arg == flag)
+      {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/Configuration.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,56 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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 "PostgreSQLConnection.h"
+
+#include <json/value.h>
+#include <orthanc/OrthancCPlugin.h>
+
+
+// This comes from the Orthanc source code
+static const int32_t GlobalProperty_DatabaseSchemaVersion = 1;
+
+static const int32_t GlobalProperty_IndexLock = 1024;
+static const int32_t GlobalProperty_StorageLock = 1025;
+
+static const std::string FLAG_UNLOCK = "--unlock";
+
+namespace OrthancPlugins
+{
+  bool ReadConfiguration(Json::Value& configuration,
+                         OrthancPluginContext* context);
+
+  std::string GetStringValue(const Json::Value& configuration,
+                             const std::string& key,
+                             const std::string& defaultValue);
+
+  int GetIntegerValue(const Json::Value& configuration,
+                      const std::string& key,
+                      int defaultValue);
+
+  PostgreSQLConnection* CreateConnection(OrthancPluginContext* context);
+
+  std::string GenerateUuid();
+
+  bool IsFlagInCommandLineArguments(OrthancPluginContext* context,
+                                    const std::string& flag);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/GlobalProperties.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,126 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "GlobalProperties.h"
+
+#include "Configuration.h"
+#include "PostgreSQLException.h"
+#include "PostgreSQLResult.h"
+#include "PostgreSQLTransaction.h"
+
+#include "EmbeddedResources.h"
+
+namespace OrthancPlugins
+{
+  GlobalProperties::GlobalProperties(PostgreSQLConnection& connection,
+                                     int32_t lockKey) :
+    connection_(connection),
+    lockKey_(lockKey)
+  {
+    PostgreSQLTransaction transaction(connection_);
+
+    if (!connection_.DoesTableExist("GlobalProperties"))
+    {
+      std::string query;
+
+      EmbeddedResources::GetFileResource(query, EmbeddedResources::GLOBAL_PROPERTIES);
+      connection_.Execute(query);
+    }
+
+    transaction.Commit();
+  }
+
+
+  void GlobalProperties::Lock(bool allowUnlock)
+  {
+    PostgreSQLTransaction transaction(connection_);
+
+    // Check the lock
+    if (!allowUnlock)
+    {
+      std::string lock = "0";
+      if (LookupGlobalProperty(lock, lockKey_) &&
+          lock != "0")
+      {
+        throw PostgreSQLException("The database is locked by another instance of Orthanc. "
+                                  "Use \"" + FLAG_UNLOCK + "\" to manually remove the lock.");
+      }
+    }
+
+    // Lock the database
+    SetGlobalProperty(lockKey_, "1");             
+
+    transaction.Commit();
+  }
+
+
+  bool GlobalProperties::LookupGlobalProperty(std::string& target,
+                                              int32_t property)
+  {
+    if (lookupGlobalProperty_.get() == NULL)
+    {
+      lookupGlobalProperty_.reset
+        (new PostgreSQLStatement
+         (connection_, "SELECT value FROM GlobalProperties WHERE property=$1"));
+      lookupGlobalProperty_->DeclareInputInteger(0);
+    }
+
+    lookupGlobalProperty_->BindInteger(0, static_cast<int>(property));
+
+    PostgreSQLResult result(*lookupGlobalProperty_);
+    if (result.IsDone())
+    {
+      return false;
+    }
+    else
+    {
+      target = result.GetString(0);
+      return true;
+    }
+  }
+
+
+  void GlobalProperties::SetGlobalProperty(int32_t property,
+                                           const char* value)
+  {
+    if (setGlobalProperty_.get() == NULL)
+    {
+      // http://stackoverflow.com/a/1109198/881731
+      setGlobalProperty_.reset
+        (new PostgreSQLStatement
+         (connection_, "SELECT ChangeGlobalProperty($1, $2)"));
+      setGlobalProperty_->DeclareInputInteger(0);
+      setGlobalProperty_->DeclareInputString(1);
+    }
+
+    setGlobalProperty_->BindInteger(0, property);
+    setGlobalProperty_->BindString(1, value);
+    setGlobalProperty_->Run();
+  }
+
+
+  void GlobalProperties::Unlock()
+  {
+    // Remove the lock
+    PostgreSQLTransaction transaction(connection_);
+    SetGlobalProperty(lockKey_, "0");
+    transaction.Commit();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/GlobalProperties.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,55 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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 "PostgreSQLConnection.h"
+#include "PostgreSQLStatement.h"
+
+#include <stdint.h>
+#include <memory>
+
+namespace OrthancPlugins
+{
+  class GlobalProperties
+  {
+  private:
+    PostgreSQLConnection& connection_;
+    int32_t lockKey_;
+
+    std::auto_ptr<PostgreSQLStatement> lookupGlobalProperty_;
+    std::auto_ptr<PostgreSQLStatement> setGlobalProperty_;
+
+  public:
+    GlobalProperties(PostgreSQLConnection& connection,
+                     int32_t lockKey);
+
+    void Lock(bool allowUnlock);
+
+    void Unlock();
+
+    bool LookupGlobalProperty(std::string& target,
+                              int32_t property);
+
+    void SetGlobalProperty(int32_t property,
+                         const char* value);
+
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/GlobalProperties.sql	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,30 @@
+CREATE TABLE GlobalProperties(
+       property INTEGER PRIMARY KEY,
+       value TEXT
+       );
+
+
+-- Upsert functions ("insert or replace")
+-- http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-UPSERT-EXAMPLE
+CREATE FUNCTION ChangeGlobalProperty(property_ INT, value_ TEXT) RETURNS VOID AS
+$$
+BEGIN
+    LOOP
+        -- first try to update the property
+        UPDATE GlobalProperties SET value = value_ WHERE property = property_;
+        IF found THEN
+            RETURN;
+        END IF;
+        -- not there, so try to insert the property
+        -- if someone else inserts the same property concurrently,
+        -- we could get a unique-key failure
+        BEGIN
+            INSERT INTO GlobalProperties VALUES (property_, value_);
+            RETURN;
+        EXCEPTION WHEN unique_violation THEN
+            -- Do nothing, and loop to try the UPDATE again.
+        END;
+    END LOOP;
+END;
+$$
+LANGUAGE plpgsql;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/PostgreSQLConnection.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,204 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "PostgreSQLConnection.h"
+
+#include "PostgreSQLException.h"
+#include "PostgreSQLResult.h"
+#include "PostgreSQLStatement.h"
+#include "PostgreSQLTransaction.h"
+
+#include <boost/lexical_cast.hpp>
+
+// PostgreSQL includes
+#include <libpq-fe.h>
+#include <c.h>
+#include <catalog/pg_type.h>
+
+
+namespace OrthancPlugins
+{
+  void PostgreSQLConnection::Close()
+  {
+    if (pg_ != NULL)
+    {
+      PQfinish(reinterpret_cast<PGconn*>(pg_));
+      pg_ = NULL;
+    }
+  }
+
+
+  PostgreSQLConnection::PostgreSQLConnection()
+  {
+    pg_ = NULL;
+    host_ = "localhost";
+    port_ = 5432;
+    username_ = "postgres";
+    password_ = "postgres";
+    database_ = "";
+  }
+
+  
+  PostgreSQLConnection::PostgreSQLConnection(const PostgreSQLConnection& other) : 
+    host_(other.host_),
+    port_(other.port_),
+    username_(other.username_),
+    password_(other.password_),
+    database_(other.database_),
+    pg_(NULL)
+  {
+  }
+
+
+  void PostgreSQLConnection::SetHost(const std::string& host)
+  {
+    Close();
+    host_ = host;
+  }
+
+  void PostgreSQLConnection::SetPortNumber(uint16_t port)
+  {
+    Close();
+    port_ = port;
+  }
+
+  void PostgreSQLConnection::SetUsername(const std::string& username)
+  {
+    Close();
+    username_ = username;
+  }
+
+  void PostgreSQLConnection::SetPassword(const std::string& password)
+  {
+    Close();
+    password_ = password;
+  }
+
+  void PostgreSQLConnection::SetDatabase(const std::string& database)
+  {
+    Close();
+    database_ = database;
+  }
+
+  void PostgreSQLConnection::Open()
+  {
+    if (pg_ != NULL)
+    {
+      // Already connected
+      return;
+    }
+
+    std::string s =
+      std::string(" sslmode=disable") +   // TODO WHY SSL DOES NOT WORK? ("SSL error: wrong version number")
+      " user=" + username_ + 
+      " password=" + password_ + 
+      " host=" + host_ + 
+      " port=" + boost::lexical_cast<std::string>(port_);
+
+    if (database_.size() > 0)
+    {
+      s += " dbname=" + database_;
+    }
+
+    pg_ = PQconnectdb(s.c_str());
+
+    if (pg_ == NULL ||
+        PQstatus(reinterpret_cast<PGconn*>(pg_)) != CONNECTION_OK)
+    {
+      std::string message;
+
+      if (pg_)
+      {
+        message = PQerrorMessage(reinterpret_cast<PGconn*>(pg_));
+        PQfinish(reinterpret_cast<PGconn*>(pg_));
+        pg_ = NULL;
+      }
+
+      throw PostgreSQLException(message);
+    }
+  }
+
+
+  void PostgreSQLConnection::Execute(const std::string& sql)
+  {
+    Open();
+
+    PGresult* result = PQexec(reinterpret_cast<PGconn*>(pg_), sql.c_str());
+    if (result == NULL)
+    {
+      throw PostgreSQLException(PQerrorMessage(reinterpret_cast<PGconn*>(pg_)));
+    }
+
+    bool ok = (PQresultStatus(result) == PGRES_COMMAND_OK ||
+               PQresultStatus(result) == PGRES_TUPLES_OK);
+
+    if (ok)
+    {
+      PQclear(result);
+    }
+    else
+    {
+      std::string message = PQresultErrorMessage(result);
+      PQclear(result);
+      throw PostgreSQLException(message);
+    }
+  }
+
+
+  bool PostgreSQLConnection::DoesTableExist(const char* name)
+  {
+    std::string lower(name);
+    std::transform(lower.begin(), lower.end(), lower.begin(), tolower);
+
+    // http://stackoverflow.com/a/24089729/881731
+
+    PostgreSQLStatement statement(*this, 
+                                  "SELECT 1 FROM pg_catalog.pg_class c "
+                                  "JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace "
+                                  "WHERE n.nspname = 'public' AND c.relkind='r' "
+                                  "AND c.relname=$1");
+
+    statement.DeclareInputString(0);
+    statement.BindString(0, lower);
+
+    PostgreSQLResult result(statement);
+    return !result.IsDone();
+  }
+
+
+
+  void PostgreSQLConnection::ClearAll()
+  {
+    PostgreSQLTransaction transaction(*this);
+    
+    // Remove all the large objects
+    Execute("SELECT lo_unlink(loid) FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) as loids;");
+
+    // http://stackoverflow.com/a/21247009/881731
+    Execute("DROP SCHEMA public CASCADE;");
+    Execute("CREATE SCHEMA public;");
+    Execute("GRANT ALL ON SCHEMA public TO postgres;");
+    Execute("GRANT ALL ON SCHEMA public TO public;");
+    Execute("COMMENT ON SCHEMA public IS 'standard public schema';");
+
+    transaction.Commit();
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/PostgreSQLConnection.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,114 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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
+
+#if defined(_WIN32)
+#include <winsock2.h>
+#  if defined(_MSC_VER)
+//   http://msdn.microsoft.com/en-us/library/a3140177.aspx
+#    define htobe32(x) _byteswap_ulong(x)
+#    define htobe64(x) _byteswap_uint64(x)
+#  else   // MinGW
+#    define htobe32(x) __builtin_bswap32(x)
+#    define htobe64(x) __builtin_bswap64(x)
+#  endif
+#endif
+
+#include <string>
+#include <boost/noncopyable.hpp>
+#include <stdint.h>
+
+namespace OrthancPlugins
+{
+  class PostgreSQLConnection : public boost::noncopyable
+  {
+  private:
+    friend class PostgreSQLStatement;
+    friend class PostgreSQLLargeObject;
+
+    std::string host_;
+    uint16_t port_;
+    std::string username_;
+    std::string password_;
+    std::string database_;
+    void* pg_;   /* Object of type "PGconn*" */
+
+    void Close();
+
+  public:
+    PostgreSQLConnection();
+
+    PostgreSQLConnection(const PostgreSQLConnection& other);
+
+    ~PostgreSQLConnection()
+    {
+      Close();
+    }
+
+    void SetHost(const std::string& host);
+
+    const std::string& GetHost() const
+    {
+      return host_;
+    }
+
+    void SetPortNumber(uint16_t port);
+
+    uint16_t GetPortNumber() const
+    {
+      return port_;
+    }
+
+    void SetUsername(const std::string& username);
+
+    const std::string& GetUsername() const
+    {
+      return username_;
+    }
+
+    void SetPassword(const std::string& password);
+
+    const std::string& GetPassword() const
+    {
+      return password_;
+    }
+
+    void SetDatabase(const std::string& database);
+
+    void ResetDatabase()
+    {
+      SetDatabase("");
+    }
+
+    const std::string& GetDatabase() const
+    {
+      return database_;
+    }
+
+    void Open();
+
+    void Execute(const std::string& sql);
+
+    bool DoesTableExist(const char* name);
+
+    void ClearAll();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/PostgreSQLException.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,41 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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 <stdexcept>
+#include <string>
+
+namespace OrthancPlugins
+{
+  class PostgreSQLException : public std::runtime_error
+  {
+  public:
+    PostgreSQLException() : 
+      std::runtime_error("Error in PostgreSQL")
+    {
+    }
+
+    PostgreSQLException(const std::string& message) : 
+      std::runtime_error("Error in PostgreSQL: " + message)
+    {
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/PostgreSQLLargeObject.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,217 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+// http://www.postgresql.org/docs/9.1/static/lo-interfaces.html#AEN33102
+
+#include "PostgreSQLLargeObject.h"
+
+#include "PostgreSQLException.h"
+
+#include <boost/lexical_cast.hpp>
+#include <libpq/libpq-fs.h>
+
+
+namespace OrthancPlugins
+{  
+  void PostgreSQLLargeObject::Create()
+  {
+    PGconn* pg = reinterpret_cast<PGconn*>(connection_.pg_);
+
+    oid_ = lo_creat(pg, INV_WRITE);
+    if (oid_ == 0)
+    {
+      throw PostgreSQLException("Cannot create a large object");
+    }
+  }
+
+
+  void PostgreSQLLargeObject::Write(const void* data, 
+                                    size_t size)
+  {
+    static int MAX_CHUNK_SIZE = 16 * 1024 * 1024;
+
+    PGconn* pg = reinterpret_cast<PGconn*>(connection_.pg_);
+
+    int fd = lo_open(pg, oid_, INV_WRITE);
+    if (fd < 0)
+    {
+      throw PostgreSQLException();
+    }
+
+    const char* position = reinterpret_cast<const char*>(data);
+    while (size > 0)
+    {
+      int chunk = (size > static_cast<size_t>(MAX_CHUNK_SIZE) ? MAX_CHUNK_SIZE : static_cast<int>(size));
+      int nbytes = lo_write(pg, fd, position, chunk);
+      if (nbytes <= 0)
+      {
+        lo_close(pg, fd);
+        throw PostgreSQLException();
+      }
+
+      size -= nbytes;
+      position += nbytes;
+    }
+
+    lo_close(pg, fd);
+  }
+
+
+  PostgreSQLLargeObject::PostgreSQLLargeObject(PostgreSQLConnection& connection,
+                                               const void* data,
+                                               size_t size) : 
+    connection_(connection)
+  {
+    Create();
+    Write(data, size);
+  }
+
+
+  PostgreSQLLargeObject::PostgreSQLLargeObject(PostgreSQLConnection& connection,
+                                               const std::string& s) : 
+    connection_(connection)
+  {
+    Create();
+
+    if (s.size() != 0)
+    {
+      Write(s.c_str(), s.size());
+    }
+    else
+    {
+      Write(NULL, 0);
+    }
+  }
+
+
+  class PostgreSQLLargeObject::Reader
+  {
+  private: 
+    PGconn* pg_;
+    int fd_;
+    size_t size_;
+
+  public:
+    Reader(PostgreSQLConnection& connection,
+           const std::string& oid)
+    {
+      pg_ = reinterpret_cast<PGconn*>(connection.pg_);
+      Oid id = boost::lexical_cast<Oid>(oid);
+
+      fd_ = lo_open(pg_, id, INV_READ);
+
+      if (fd_ < 0 ||
+          lo_lseek(pg_, fd_, 0, SEEK_END) < 0)
+      {
+        throw PostgreSQLException("No such large object in the connection; Make sure you use a transaction");
+      }
+
+      // Get the size of the large object
+      int size = lo_tell(pg_, fd_);
+      if (size < 0)
+      {
+        throw PostgreSQLException("Internal error");
+      }
+      size_ = static_cast<size_t>(size);
+
+      // Go to the first byte of the object
+      lo_lseek(pg_, fd_, 0, SEEK_SET);
+    }
+
+    ~Reader()
+    {
+      lo_close(pg_, fd_);
+    }
+
+    size_t GetSize() const
+    {
+      return size_;
+    }
+
+    void Read(char* target)
+    {
+      for (size_t position = 0; position < size_; )
+      {
+        size_t remaining = size_ - position;
+        size_t nbytes = lo_read(pg_, fd_, target + position, remaining);
+
+        if (nbytes < 0)
+        {
+          throw PostgreSQLException("Unable to read the large object in the database");
+        }
+
+        position += nbytes;
+      }
+    }
+  };
+  
+
+  void PostgreSQLLargeObject::Read(std::string& target,
+                                   PostgreSQLConnection& connection,
+                                   const std::string& oid)
+  {
+    Reader reader(connection, oid);
+    target.resize(reader.GetSize());    
+
+    if (target.size() > 0)
+    {
+      reader.Read(&target[0]);
+    }
+  }
+
+
+  void PostgreSQLLargeObject::Read(void*& target,
+                                   size_t& size,
+                                   PostgreSQLConnection& connection,
+                                   const std::string& oid)
+  {
+    Reader reader(connection, oid);
+    size = reader.GetSize();
+
+    if (size == 0)
+    {
+      target = NULL;
+    }
+    else
+    {
+      target = malloc(size);
+      reader.Read(reinterpret_cast<char*>(target));
+    }
+  }
+
+
+  std::string PostgreSQLLargeObject::GetOid() const
+  {
+    return boost::lexical_cast<std::string>(oid_);
+  }
+
+
+  void PostgreSQLLargeObject::Delete(PostgreSQLConnection& connection,
+                                     const std::string& oid)
+  {
+    PGconn* pg = reinterpret_cast<PGconn*>(connection.pg_);
+    Oid id = boost::lexical_cast<Oid>(oid);
+
+    if (lo_unlink(pg, id) < 0)
+    {
+      throw PostgreSQLException("Unable to delete the large object from the database");
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/PostgreSQLLargeObject.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,65 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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 "PostgreSQLConnection.h"
+
+#include <libpq-fe.h>
+
+namespace OrthancPlugins
+{  
+  class PostgreSQLLargeObject : public boost::noncopyable
+  {
+  private:
+    class Reader;
+
+    PostgreSQLConnection& connection_;
+    Oid oid_;
+
+    void Create();
+
+    void Write(const void* data, 
+               size_t size);
+
+  public:
+    PostgreSQLLargeObject(PostgreSQLConnection& connection,
+                          const void* data,
+                          size_t size);
+
+    PostgreSQLLargeObject(PostgreSQLConnection& connection,
+                          const std::string& s);
+
+    std::string GetOid() const;
+
+    static void Read(std::string& target,
+                     PostgreSQLConnection& connection,
+                     const std::string& oid);
+
+    static void Read(void*& target,
+                     size_t& size,
+                     PostgreSQLConnection& connection,
+                     const std::string& oid);
+
+    static void Delete(PostgreSQLConnection& connection,
+                       const std::string& oid);
+  };
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/PostgreSQLResult.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,160 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "PostgreSQLResult.h"
+
+#include "PostgreSQLException.h"
+
+#include <cassert>
+#include <boost/lexical_cast.hpp>
+
+// PostgreSQL includes
+#include <libpq-fe.h>
+#include <c.h>
+#include <catalog/pg_type.h>
+
+
+namespace OrthancPlugins
+{
+  void PostgreSQLResult::Clear()
+  {
+    if (result_ != NULL)
+    {
+      PQclear(reinterpret_cast<PGresult*>(result_));
+      result_ = NULL;
+    }
+  }
+
+  void PostgreSQLResult::CheckDone()
+  {
+    if (position_ >= PQntuples(reinterpret_cast<PGresult*>(result_)))
+    {
+      // We are at the end of the result set
+      Clear();
+    }
+  }
+
+  void PostgreSQLResult::CheckColumn(unsigned int column, unsigned int /*Oid*/ expectedType) const
+  {
+    if (IsDone())
+    {
+      throw PostgreSQLException("Bad sequence of calls");
+    }
+
+    if (column >= static_cast<unsigned int>(PQnfields(reinterpret_cast<PGresult*>(result_))))
+    {
+      throw PostgreSQLException("Parameter out of range");
+    }
+
+    if (expectedType != 0 &&
+        expectedType != PQftype(reinterpret_cast<PGresult*>(result_), column))
+    {
+      throw PostgreSQLException("Bad type of parameter");
+    }
+  }
+
+  PostgreSQLResult::PostgreSQLResult(PostgreSQLStatement& statement) : 
+    position_(0), 
+    connection_(statement.GetConnection())
+  {
+    result_ = statement.Execute();
+    assert(result_ != NULL);   // An exception would have been thrown otherwise
+
+    // This is the first call to "Step()"
+    if (PQresultStatus(reinterpret_cast<PGresult*>(result_)) != PGRES_TUPLES_OK)
+    {
+      throw PostgreSQLException("PostgreSQL: Step() applied to non-SELECT request");
+    }
+
+    CheckDone();
+  }
+
+  void PostgreSQLResult::Step()
+  {
+    position_++;
+    CheckDone();
+  }
+
+  bool PostgreSQLResult::IsNull(unsigned int column) const
+  {
+    CheckColumn(column, 0);
+    return PQgetisnull(reinterpret_cast<PGresult*>(result_), position_, column) != 0;
+  }
+
+  int PostgreSQLResult::GetInteger(unsigned int column) const
+  {
+    CheckColumn(column, INT4OID);
+    assert(PQfsize(reinterpret_cast<PGresult*>(result_), column) == 4);
+    char *v = PQgetvalue(reinterpret_cast<PGresult*>(result_), position_, column);
+    return htobe32(*reinterpret_cast<int32_t*>(v));
+  }
+
+  int64_t PostgreSQLResult::GetInteger64(unsigned int column) const
+  {
+    CheckColumn(column, INT8OID);
+    assert(PQfsize(reinterpret_cast<PGresult*>(result_), column) == 8);
+    char *v = PQgetvalue(reinterpret_cast<PGresult*>(result_), position_, column);
+    return htobe64(*reinterpret_cast<int64_t*>(v));
+  }
+
+  std::string PostgreSQLResult::GetString(unsigned int column) const
+  {
+    CheckColumn(column, 0);
+
+    Oid oid = PQftype(reinterpret_cast<PGresult*>(result_), column);
+    if (oid != TEXTOID && oid != VARCHAROID && oid != BYTEAOID)
+    {
+      throw PostgreSQLException("Bad type of parameter");
+    }
+
+    return std::string(PQgetvalue(reinterpret_cast<PGresult*>(result_), position_, column));
+  }
+
+
+  void PostgreSQLResult::GetLargeObject(std::string& result,
+                                        unsigned int column) const
+  {
+    CheckColumn(column, OIDOID);
+
+    Oid oid;
+    assert(PQfsize(reinterpret_cast<PGresult*>(result_), column) == sizeof(oid));
+
+    oid = *(const Oid*) PQgetvalue(reinterpret_cast<PGresult*>(result_), position_, column);
+    oid = ntohl(oid);
+
+    PostgreSQLLargeObject::Read(result, connection_, boost::lexical_cast<std::string>(oid));
+  }
+
+
+  void PostgreSQLResult::GetLargeObject(void*& result,
+                                        size_t& size,
+                                        unsigned int column) const
+  {
+    CheckColumn(column, OIDOID);
+
+    Oid oid;
+    assert(PQfsize(reinterpret_cast<PGresult*>(result_), column) == sizeof(oid));
+
+    oid = *(const Oid*) PQgetvalue(reinterpret_cast<PGresult*>(result_), position_, column);
+    oid = ntohl(oid);
+
+    PostgreSQLLargeObject::Read(result, size, connection_, boost::lexical_cast<std::string>(oid));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/PostgreSQLResult.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,70 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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 "PostgreSQLStatement.h"
+
+namespace OrthancPlugins
+{
+  class PostgreSQLResult : public boost::noncopyable
+  {
+  private:
+    void *result_;  /* Object of type "PGresult*" */
+    int position_;
+    PostgreSQLConnection& connection_;
+
+    void Clear();
+
+    void CheckDone();
+
+    void CheckColumn(unsigned int column, /*Oid*/ unsigned int expectedType) const;
+
+  public:
+    PostgreSQLResult(PostgreSQLStatement& statement);
+
+    ~PostgreSQLResult()
+    {
+      Clear();
+    }
+
+    void Step();
+
+    bool IsDone() const
+    {
+      return result_ == NULL;
+    }
+
+    bool IsNull(unsigned int column) const;
+
+    int GetInteger(unsigned int column) const;
+
+    int64_t GetInteger64(unsigned int column) const;
+
+    std::string GetString(unsigned int column) const;
+
+    void GetLargeObject(std::string& result,
+                        unsigned int column) const;
+
+    void GetLargeObject(void*& result,
+                        size_t& size,
+                        unsigned int column) const;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/PostgreSQLStatement.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,397 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "PostgreSQLStatement.h"
+
+#include "PostgreSQLException.h"
+#include "Configuration.h"
+
+#include <cassert>
+
+// PostgreSQL includes
+#include <libpq-fe.h>
+#include <c.h>
+#include <catalog/pg_type.h>
+
+
+namespace OrthancPlugins
+{
+  class PostgreSQLStatement::Inputs : public boost::noncopyable
+  {
+  private:
+    std::vector<char*> values_;
+    std::vector<int> sizes_;
+
+    static char* Allocate(const void* source, int size)
+    {
+      if (size == 0)
+      {
+        return NULL;
+      }
+      else
+      {
+        char* ptr = reinterpret_cast<char*>(malloc(size));
+
+        if (source != NULL)
+        {
+          memcpy(ptr, source, size);
+        }
+
+        return ptr;
+      }
+    }
+
+    void Resize(size_t size)
+    {
+      // Shrinking of the vector
+      for (size_t i = size; i < values_.size(); i++)
+      {
+        if (values_[i] != NULL)
+          free(values_[i]);
+      }
+
+      values_.resize(size, NULL);
+      sizes_.resize(size, 0);
+    }
+
+    void EnlargeForIndex(size_t index)
+    {
+      if (index >= values_.size())
+      {
+        // The vector is too small
+        Resize(index + 1);
+      }
+    }
+
+  public:
+    Inputs()
+    {
+    }
+
+    ~Inputs()
+    {
+      Resize(0);
+    }
+
+    void SetItem(size_t pos, const void* source, int size)
+    {
+      EnlargeForIndex(pos);
+
+      if (sizes_[pos] == size)
+      {
+        if (source && size != 0)
+        {
+          memcpy(values_[pos], source, size);
+        }
+      }
+      else
+      {
+        if (values_[pos] != NULL)
+        {
+          free(values_[pos]);
+        }
+
+        values_[pos] = Allocate(source, size);
+        sizes_[pos] = size;
+      }
+    }
+
+    void SetItem(size_t pos, int size)
+    {
+      SetItem(pos, NULL, size);
+    }
+
+    void* GetItem(size_t pos) const
+    {
+      if (pos >= values_.size())
+      {
+        throw PostgreSQLException("Parameter out of range");
+      }
+
+      return values_[pos];
+    }
+
+    const std::vector<char*>& GetValues() const
+    {
+      return values_;
+    }
+
+    const std::vector<int>& GetSizes() const
+    {
+      return sizes_;
+    }
+  };
+
+
+  void PostgreSQLStatement::Prepare()
+  {
+    if (id_.size() > 0)
+    {
+      // Already prepared
+      return;
+    }
+
+    for (size_t i = 0; i < oids_.size(); i++)
+    {
+      if (oids_[i] == 0)
+      {
+        // The type of an input parameter was not set
+        throw PostgreSQLException();
+      }
+    }
+
+    id_ = GenerateUuid();
+
+    const unsigned int* tmp = oids_.size() ? &oids_[0] : NULL;
+
+    PGresult* result = PQprepare(reinterpret_cast<PGconn*>(connection_.pg_),
+                                 id_.c_str(), sql_.c_str(), oids_.size(), tmp);
+
+    if (result == NULL)
+    {
+      id_.clear();
+      throw PostgreSQLException(PQerrorMessage(reinterpret_cast<PGconn*>(connection_.pg_)));
+    }
+
+    bool ok = (PQresultStatus(result) == PGRES_COMMAND_OK);
+    if (ok)
+    {
+      PQclear(result);
+    }
+    else
+    {
+      std::string message = PQresultErrorMessage(result);
+      PQclear(result);
+      id_.clear();
+      throw PostgreSQLException(message);
+    }
+  }
+
+
+  void PostgreSQLStatement::Unprepare()
+  {
+    if (id_.size() > 0)
+    {
+      // "Although there is no libpq function for deleting a
+      // prepared statement, the SQL DEALLOCATE statement can be
+      // used for that purpose."
+      //connection_.Execute("DEALLOCATE " + id_);
+    }
+
+    id_.clear();
+  }
+
+
+  void PostgreSQLStatement::DeclareInputInternal(unsigned int param,
+                                                 unsigned int /*Oid*/ type)
+  {
+    Unprepare();
+
+    if (oids_.size() <= param)
+    {
+      oids_.resize(param + 1, 0);
+      binary_.resize(param + 1);
+    }
+
+    oids_[param] = type;
+    binary_[param] = (type == TEXTOID || type == BYTEAOID || type == OIDOID) ? 0 : 1;
+  }
+
+
+  void PostgreSQLStatement::DeclareInputInteger(unsigned int param)
+  {
+    DeclareInputInternal(param, INT4OID);
+  }
+    
+
+  void PostgreSQLStatement::DeclareInputInteger64(unsigned int param)
+  {
+    DeclareInputInternal(param, INT8OID);
+  }
+
+
+  void PostgreSQLStatement::DeclareInputString(unsigned int param)
+  {
+    DeclareInputInternal(param, TEXTOID);
+  }
+
+
+  void PostgreSQLStatement::DeclareInputBinary(unsigned int param)
+  {
+    DeclareInputInternal(param, BYTEAOID);
+  }
+
+
+  void PostgreSQLStatement::DeclareInputLargeObject(unsigned int param)
+  {
+    DeclareInputInternal(param, OIDOID);
+  }
+
+
+  void* /* PGresult* */ PostgreSQLStatement::Execute()
+  {
+    Prepare();
+
+    PGresult* result;
+
+    if (oids_.size() == 0)
+    {
+      // No parameter
+      result = PQexecPrepared(reinterpret_cast<PGconn*>(connection_.pg_),
+                              id_.c_str(), 0, NULL, NULL, NULL, 1);
+    }
+    else
+    {
+      // At least 1 parameter
+      result = PQexecPrepared(reinterpret_cast<PGconn*>(connection_.pg_),
+                              id_.c_str(),
+                              oids_.size(),
+                              &inputs_->GetValues()[0],
+                              &inputs_->GetSizes()[0],
+                              &binary_[0],
+                              1);
+    }
+
+    if (result == NULL)
+    {
+      throw PostgreSQLException(PQerrorMessage(reinterpret_cast<PGconn*>(connection_.pg_)));
+    }
+
+    return result;
+  }
+
+
+  PostgreSQLStatement::PostgreSQLStatement(PostgreSQLConnection& connection,
+                                           const std::string& sql) :
+    connection_(connection),
+    sql_(sql),
+    inputs_(new Inputs)
+  {
+    connection_.Open();
+  }
+
+
+  void PostgreSQLStatement::Run()
+  {
+    PGresult* result = reinterpret_cast<PGresult*>(Execute());
+    assert(result != NULL);   // An exception would have been thrown otherwise
+
+    bool ok = (PQresultStatus(result) == PGRES_COMMAND_OK ||
+               PQresultStatus(result) == PGRES_TUPLES_OK);
+    if (ok)
+    {
+      PQclear(result);
+    }
+    else
+    {
+      std::string error = PQresultErrorMessage(result);
+      PQclear(result);
+      throw PostgreSQLException(error);
+    }
+  }
+
+
+  void PostgreSQLStatement::BindNull(unsigned int param)
+  {
+    if (param >= oids_.size())
+    {
+      throw PostgreSQLException("Parameter out of range");
+    }
+
+    inputs_->SetItem(param, 0);
+  }
+
+
+  void PostgreSQLStatement::BindInteger(unsigned int param, int value)
+  {
+    if (param >= oids_.size())
+    {
+      throw PostgreSQLException("Parameter out of range");
+    }
+
+    if (oids_[param] != INT4OID)
+    {
+      throw PostgreSQLException("Bad type of parameter");
+    }
+
+    assert(sizeof(int32_t) == 4);
+    int32_t v = htobe32(static_cast<int32_t>(value));
+    inputs_->SetItem(param, &v, sizeof(int32_t));
+  }
+
+
+  void PostgreSQLStatement::BindInteger64(unsigned int param, int64_t value)
+  {
+    if (param >= oids_.size())
+    {
+      throw PostgreSQLException("Parameter out of range");
+    }
+
+    if (oids_[param] != INT8OID)
+    {
+      throw PostgreSQLException("Bad type of parameter");
+    }
+
+    assert(sizeof(int64_t) == 8);
+    int64_t v = htobe64(value);
+    inputs_->SetItem(param, &v, sizeof(int64_t));
+  }
+
+
+  void PostgreSQLStatement::BindString(unsigned int param, const std::string& value)
+  {
+    if (param >= oids_.size())
+    {
+      throw PostgreSQLException("Parameter out of range");
+    }
+
+    if (oids_[param] != TEXTOID && oids_[param] != BYTEAOID)
+    {
+      throw PostgreSQLException("Bad type of parameter");
+    }
+
+    if (value.size() == 0)
+    {
+      inputs_->SetItem(param, "", 1 /* end-of-string character */);
+    }
+    else
+    {
+      inputs_->SetItem(param, value.c_str(), 
+                       value.size() + 1);  // "+1" for end-of-string character
+    }
+  }
+
+
+  void PostgreSQLStatement::BindLargeObject(unsigned int param, const PostgreSQLLargeObject& value)
+  {
+    if (param >= oids_.size())
+    {
+      throw PostgreSQLException("Parameter out of range");
+    }
+
+    if (oids_[param] != OIDOID)
+    {
+      throw PostgreSQLException("Bad type of parameter");
+    }
+
+    inputs_->SetItem(param, value.GetOid().c_str(), 
+                     value.GetOid().size() + 1);  // "+1" for end-of-string character
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/PostgreSQLStatement.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,90 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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 "PostgreSQLConnection.h"
+#include "PostgreSQLLargeObject.h"
+
+#include <vector>
+#include <memory>
+#include <boost/shared_ptr.hpp>
+
+namespace OrthancPlugins
+{
+  class PostgreSQLStatement : public boost::noncopyable
+  {
+  private:
+    class Inputs;
+    friend class PostgreSQLResult;
+
+    PostgreSQLConnection& connection_;
+    std::string id_;
+    std::string sql_;
+    std::vector<unsigned int /*Oid*/>  oids_;
+    std::vector<int>  binary_;
+    boost::shared_ptr<Inputs> inputs_;
+
+    void Prepare();
+
+    void Unprepare();
+
+    void DeclareInputInternal(unsigned int param,
+                              unsigned int /*Oid*/ type);
+
+    void* /* PGresult* */ Execute();
+
+  public:
+    PostgreSQLStatement(PostgreSQLConnection& connection,
+                        const std::string& sql);
+
+    ~PostgreSQLStatement()
+    {
+      Unprepare();
+    }
+    
+    void DeclareInputInteger(unsigned int param);
+    
+    void DeclareInputInteger64(unsigned int param);
+
+    void DeclareInputString(unsigned int param);
+
+    void DeclareInputBinary(unsigned int param);
+
+    void DeclareInputLargeObject(unsigned int param);
+
+    void Run();
+
+    void BindNull(unsigned int param);
+
+    void BindInteger(unsigned int param, int value);
+
+    void BindInteger64(unsigned int param, int64_t value);
+
+    void BindString(unsigned int param, const std::string& value);
+
+    void BindLargeObject(unsigned int param, const PostgreSQLLargeObject& value);
+
+    PostgreSQLConnection& GetConnection() const
+    {
+      return connection_;
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/PostgreSQLTransaction.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,80 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "PostgreSQLTransaction.h"
+
+#include "PostgreSQLException.h"
+
+namespace OrthancPlugins
+{
+  PostgreSQLTransaction::PostgreSQLTransaction(PostgreSQLConnection& connection,
+                                               bool open) :
+    connection_(connection),
+    isOpen_(false)
+  {
+    if (open)
+    {
+      Begin();
+    }
+  }
+
+  PostgreSQLTransaction::~PostgreSQLTransaction()
+  {
+    if (isOpen_)
+    {
+      connection_.Execute("ABORT");
+    }
+  }
+
+  void PostgreSQLTransaction::Begin()
+  {
+    if (isOpen_) 
+    {
+      throw PostgreSQLException("PostgreSQL: Beginning a transaction twice!");
+    }
+
+    connection_.Execute("BEGIN");
+    isOpen_ = true;
+  }
+
+  void PostgreSQLTransaction::Rollback() 
+  {
+    if (!isOpen_) 
+    {
+      throw PostgreSQLException("Attempting to rollback a nonexistent transaction. "
+                                "Did you remember to call Begin()?");
+    }
+
+    connection_.Execute("ABORT");
+    isOpen_ = false;
+  }
+
+  void PostgreSQLTransaction::Commit() 
+  {
+    if (!isOpen_) 
+    {
+      throw PostgreSQLException("Attempting to roll back a nonexistent transaction. "
+                                "Did you remember to call Begin()?");
+    }
+
+    connection_.Execute("COMMIT");
+    isOpen_ = false;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/PostgreSQLTransaction.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,45 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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 "PostgreSQLConnection.h"
+
+namespace OrthancPlugins
+{
+  class PostgreSQLTransaction
+  {
+  private:
+    PostgreSQLConnection& connection_;
+    bool isOpen_;
+
+  public:
+    explicit PostgreSQLTransaction(PostgreSQLConnection& connection,
+                                   bool open = true);
+
+    ~PostgreSQLTransaction();
+
+    void Begin();
+
+    void Rollback();
+
+    void Commit();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IndexPlugin/Plugin.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,100 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include <orthanc/OrthancCPlugin.h>
+
+#include "PostgreSQLWrapper.h"
+#include "../Core/PostgreSQLException.h"
+#include "../Core/Configuration.h"
+
+
+static OrthancPluginContext* context_ = NULL;
+static OrthancPlugins::PostgreSQLWrapper* backend_ = NULL;
+
+
+extern "C"
+{
+  ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)
+  {
+    context_ = context;
+    OrthancPluginLogWarning(context, "Using PostgreSQL index");
+
+    /* Check the version of the Orthanc core */
+    if (OrthancPluginCheckVersion(context_) == 0)
+    {
+      char info[1024];
+      sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin",
+              context_->orthancVersion,
+              ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER,
+              ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER,
+              ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER);
+      OrthancPluginLogError(context, info);
+      return -1;
+    }
+
+    bool allowUnlock = OrthancPlugins::IsFlagInCommandLineArguments(context_, FLAG_UNLOCK);
+
+    OrthancPluginSetDescription(context_, "Stores the Orthanc index into a PostgreSQL database.");
+
+    try
+    {
+      /* Create the connection to PostgreSQL */
+      std::auto_ptr<OrthancPlugins::PostgreSQLConnection> pg(OrthancPlugins::CreateConnection(context_));
+      pg->Open();
+ 
+      /* Create the database back-end */
+      backend_ = new OrthancPlugins::PostgreSQLWrapper(pg.release(), allowUnlock);
+
+      /* Register the PostgreSQL index into Orthanc */
+      OrthancPlugins::DatabaseBackendAdapter::Register(context, *backend_);
+    }
+    catch (std::runtime_error& e)
+    {
+      OrthancPluginLogError(context_, e.what());
+      return -1;
+    }
+
+    return 0;
+  }
+
+
+  ORTHANC_PLUGINS_API void OrthancPluginFinalize()
+  {
+    OrthancPluginLogWarning(context_, "PostgreSQL index is finalizing");
+
+    if (backend_ != NULL)
+    {
+      delete backend_;
+      backend_ = NULL;
+    }
+  }
+
+
+  ORTHANC_PLUGINS_API const char* OrthancPluginGetName()
+  {
+    return "postgresql-index";
+  }
+
+
+  ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion()
+  {
+    return "1.0";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IndexPlugin/PostgreSQLPrepare.sql	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,172 @@
+-- Table "GlobalProperties" is created by the
+-- "OrthancPlugins::GlobalProperties" class
+
+CREATE TABLE Resources(
+       internalId BIGSERIAL NOT NULL PRIMARY KEY,
+       resourceType INTEGER NOT NULL,
+       publicId VARCHAR(64) NOT NULL,
+       parentId BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE
+       );
+
+CREATE TABLE MainDicomTags(
+       id BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
+       tagGroup INTEGER,
+       tagElement INTEGER,
+       value BYTEA,
+       PRIMARY KEY(id, tagGroup, tagElement)
+       );
+
+CREATE TABLE DicomIdentifiers(
+       id BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
+       tagGroup INTEGER,
+       tagElement INTEGER,
+       value BYTEA,
+       PRIMARY KEY(id, tagGroup, tagElement)
+       );
+
+CREATE TABLE Metadata(
+       id BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
+       type INTEGER NOT NULL,
+       value TEXT,
+       PRIMARY KEY(id, type)
+       );
+
+CREATE TABLE AttachedFiles(
+       id BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
+       fileType INTEGER,
+       uuid VARCHAR(64) NOT NULL,
+       compressedSize BIGINT,
+       uncompressedSize BIGINT,
+       compressionType INTEGER,
+       uncompressedHash VARCHAR(40),
+       compressedHash VARCHAR(40),
+       PRIMARY KEY(id, fileType)
+       );              
+
+CREATE TABLE Changes(
+       seq BIGSERIAL NOT NULL PRIMARY KEY,
+       changeType INTEGER,
+       internalId BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
+       resourceType INTEGER,
+       date VARCHAR(64)
+       );
+
+CREATE TABLE ExportedResources(
+       seq BIGSERIAL NOT NULL PRIMARY KEY,
+       resourceType INTEGER,
+       publicId VARCHAR(64),
+       remoteModality TEXT,
+       patientId VARCHAR(64),
+       studyInstanceUid TEXT,
+       seriesInstanceUid TEXT,
+       sopInstanceUid TEXT,
+       date VARCHAR(64)
+       ); 
+
+CREATE TABLE PatientRecyclingOrder(
+       seq BIGSERIAL NOT NULL PRIMARY KEY,
+       patientId BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE
+       );
+
+CREATE INDEX ChildrenIndex ON Resources(parentId);
+CREATE INDEX PublicIndex ON Resources(publicId);
+CREATE INDEX ResourceTypeIndex ON Resources(resourceType);
+CREATE INDEX PatientRecyclingIndex ON PatientRecyclingOrder(patientId);
+
+CREATE INDEX MainDicomTagsIndex ON MainDicomTags(id);
+CREATE INDEX DicomIdentifiersIndex1 ON DicomIdentifiers(id);
+CREATE INDEX DicomIdentifiersIndex2 ON DicomIdentifiers(tagGroup, tagElement);
+CREATE INDEX DicomIdentifiersIndexValues ON DicomIdentifiers(value);
+
+CREATE INDEX ChangesIndex ON Changes(internalId);
+
+
+-- Differences with SQLite
+CREATE TABLE DeletedFiles(
+       uuid VARCHAR(64) NOT NULL,      -- 0
+       fileType INTEGER,               -- 1
+       compressedSize BIGINT,          -- 2
+       uncompressedSize BIGINT,        -- 3
+       compressionType INTEGER,        -- 4
+       uncompressedHash VARCHAR(40),   -- 5
+       compressedHash VARCHAR(40)      -- 6
+       );
+
+CREATE TABLE RemainingAncestor(
+       resourceType INTEGER NOT NULL,
+       publicId VARCHAR(64) NOT NULL
+       );
+
+CREATE TABLE DeletedResources(
+       resourceType INTEGER NOT NULL,
+       publicId VARCHAR(64) NOT NULL
+       );
+-- End of differences
+
+
+CREATE FUNCTION AttachedFileDeletedFunc() 
+RETURNS TRIGGER AS $body$
+BEGIN
+  INSERT INTO DeletedFiles VALUES
+    (old.uuid, old.filetype, old.compressedSize,
+     old.uncompressedSize, old.compressionType,
+     old.uncompressedHash, old.compressedHash);
+  RETURN NULL;
+END;
+$body$ LANGUAGE plpgsql;
+
+CREATE TRIGGER AttachedFileDeleted
+AFTER DELETE ON AttachedFiles
+FOR EACH ROW
+EXECUTE PROCEDURE AttachedFileDeletedFunc();
+
+
+-- The following trigger combines 2 triggers from SQLite:
+-- ResourceDeleted + ResourceDeletedParentCleaning
+CREATE FUNCTION ResourceDeletedFunc() 
+RETURNS TRIGGER AS $body$
+BEGIN
+  --RAISE NOTICE 'Delete resource %', old.parentId;
+  INSERT INTO DeletedResources VALUES (old.resourceType, old.publicId);
+
+  -- http://stackoverflow.com/a/11299968/881731
+  IF EXISTS (SELECT 1 FROM Resources WHERE parentId = old.parentId) THEN
+    -- Signal that the deleted resource has a remaining parent
+    INSERT INTO RemainingAncestor
+      SELECT resourceType, publicId FROM Resources WHERE internalId = old.parentId;
+  ELSE
+    -- Delete a parent resource when its unique child is deleted 
+    DELETE FROM Resources WHERE internalId = old.parentId;
+  END IF;
+  RETURN NULL;
+END;
+$body$ LANGUAGE plpgsql;
+
+CREATE TRIGGER ResourceDeleted
+AFTER DELETE ON Resources
+FOR EACH ROW
+EXECUTE PROCEDURE ResourceDeletedFunc();
+
+
+
+CREATE FUNCTION PatientAddedFunc() 
+RETURNS TRIGGER AS $body$
+BEGIN
+  -- The "0" corresponds to "OrthancPluginResourceType_Patient"
+  IF new.resourceType = 0 THEN
+    INSERT INTO PatientRecyclingOrder VALUES (DEFAULT, new.internalId);
+  END IF;
+  RETURN NULL;
+END;
+$body$ LANGUAGE plpgsql;
+
+CREATE TRIGGER PatientAdded
+AFTER INSERT ON Resources
+FOR EACH ROW
+EXECUTE PROCEDURE PatientAddedFunc();
+
+
+
+-- Set the version of the database schema
+-- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration
+INSERT INTO GlobalProperties VALUES (1, '5');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IndexPlugin/PostgreSQLUpserts.sql	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,24 @@
+-- Upsert functions ("insert or replace")
+-- http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-UPSERT-EXAMPLE
+CREATE FUNCTION ChangeMetadata(id_ BIGINT, type_ INT, value_ TEXT) RETURNS VOID AS
+$$
+BEGIN
+    LOOP
+        -- first try to update the property
+        UPDATE Metadata SET value = value_ WHERE id = id_ AND type = type_;
+        IF found THEN
+            RETURN;
+        END IF;
+        -- not there, so try to insert the property
+        -- if someone else inserts the same property concurrently,
+        -- we could get a unique-key failure
+        BEGIN
+            INSERT INTO Metadata VALUES (id_, type_, value_);
+            RETURN;
+        EXCEPTION WHEN unique_violation THEN
+            -- Do nothing, and loop to try the UPDATE again.
+        END;
+    END LOOP;
+END;
+$$
+LANGUAGE plpgsql;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IndexPlugin/PostgreSQLWrapper.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,1216 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "PostgreSQLWrapper.h"
+
+#include "EmbeddedResources.h"
+
+#include "../Core/Configuration.h"
+#include "../Core/PostgreSQLException.h"
+#include "../Core/PostgreSQLTransaction.h"
+
+#include <boost/lexical_cast.hpp>
+
+namespace OrthancPlugins
+{
+  PostgreSQLWrapper::PostgreSQLWrapper(PostgreSQLConnection* connection,
+                                       bool allowUnlock) :
+    connection_(connection),
+    globalProperties_(*connection, GlobalProperty_IndexLock)
+  {
+    globalProperties_.Lock(allowUnlock);
+
+    Prepare();
+
+
+    /**
+     * Below are the PostgreSQL precompiled statements that are used
+     * in more than 1 method of this class.
+     **/
+
+    getPublicId_.reset
+      (new PostgreSQLStatement
+       (*connection_, "SELECT publicId FROM Resources WHERE internalId=$1"));
+    getPublicId_->DeclareInputInteger64(0);
+
+    clearDeletedFiles_.reset
+      (new PostgreSQLStatement
+       (*connection_, "DELETE FROM DeletedFiles"));
+
+    clearDeletedResources_.reset
+      (new PostgreSQLStatement
+       (*connection_, "DELETE FROM DeletedResources"));
+  }
+
+
+  void PostgreSQLWrapper::SignalDeletedFilesAndResources()
+  {
+    if (getDeletedFiles_.get() == NULL ||
+        getDeletedResources_.get() == NULL)
+    {
+      getDeletedFiles_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT * FROM DeletedFiles"));
+
+      getDeletedResources_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT * FROM DeletedResources"));
+    }
+
+    {
+      PostgreSQLResult result(*getDeletedFiles_);
+
+      while (!result.IsDone())
+      {
+        GetOutput().SignalDeletedAttachment(result.GetString(0).c_str(),
+                                            result.GetInteger(1),
+                                            result.GetInteger64(3),
+                                            result.GetString(5).c_str(),
+                                            result.GetInteger(4),
+                                            result.GetInteger64(2),
+                                            result.GetString(6).c_str());
+
+        result.Step();
+      }
+    }
+
+    {
+      PostgreSQLResult result(*getDeletedResources_);
+
+      while (!result.IsDone())
+      {
+        OrthancPluginResourceType type = static_cast<OrthancPluginResourceType>(result.GetInteger(0));
+        GetOutput().SignalDeletedResource(result.GetString(1), type);
+
+        result.Step();
+      }
+    }
+  }
+
+
+  void PostgreSQLWrapper::Prepare()
+  {
+    PostgreSQLTransaction t(*connection_);
+
+    if (!connection_->DoesTableExist("Resources"))
+    {
+      std::string query;
+
+      EmbeddedResources::GetFileResource(query, EmbeddedResources::POSTGRESQL_PREPARE);
+      connection_->Execute(query);
+
+      EmbeddedResources::GetFileResource(query, EmbeddedResources::POSTGRESQL_UPSERTS);
+      connection_->Execute(query);
+    }
+
+    
+    // Check the version of the database
+    std::string version = "unknown";
+    if (!LookupGlobalProperty(version, GlobalProperty_DatabaseSchemaVersion))
+    {
+      throw PostgreSQLException("The database is corrupted. Drop it manually for Orthanc to recreate it");
+    }
+
+    bool ok = false;
+
+    try
+    {
+      unsigned int v = boost::lexical_cast<unsigned int>(version);
+      ok = (v == 5);
+    }
+    catch (boost::bad_lexical_cast&)
+    {
+    }
+   
+    if (!ok)
+    {
+      std::string message = "Incompatible version of the Orthanc PostgreSQL database: " + version;
+      throw PostgreSQLException(message);
+    }
+          
+    t.Commit();
+  }
+
+
+  PostgreSQLWrapper::~PostgreSQLWrapper()
+  {
+    globalProperties_.Unlock();
+  }
+
+
+  void PostgreSQLWrapper::AddAttachment(int64_t id,
+                                        const OrthancPluginAttachment& attachment)
+  {
+    if (attachFile_.get() == NULL)
+    {
+      attachFile_.reset
+        (new PostgreSQLStatement
+         (*connection_, "INSERT INTO AttachedFiles VALUES($1, $2, $3, $4, $5, $6, $7, $8)"));
+      attachFile_->DeclareInputInteger64(0);
+      attachFile_->DeclareInputInteger(1);
+      attachFile_->DeclareInputString(2);
+      attachFile_->DeclareInputInteger64(3);
+      attachFile_->DeclareInputInteger64(4);
+      attachFile_->DeclareInputInteger(5);
+      attachFile_->DeclareInputString(6);
+      attachFile_->DeclareInputString(7);
+    }
+
+    attachFile_->BindInteger64(0, id);
+    attachFile_->BindInteger(1, attachment.contentType);
+    attachFile_->BindString(2, attachment.uuid);
+    attachFile_->BindInteger64(3, attachment.compressedSize);
+    attachFile_->BindInteger64(4, attachment.uncompressedSize);
+    attachFile_->BindInteger(5, attachment.compressionType);
+    attachFile_->BindString(6, attachment.uncompressedHash);
+    attachFile_->BindString(7, attachment.compressedHash);
+    attachFile_->Run();
+  }
+
+
+  void PostgreSQLWrapper::AttachChild(int64_t parent,
+                                      int64_t child)
+  {
+    if (attachChild_.get() == NULL)
+    {
+      attachChild_.reset
+        (new PostgreSQLStatement
+         (*connection_, "UPDATE Resources SET parentId = $1 WHERE internalId = $2"));
+      attachChild_->DeclareInputInteger64(0);
+      attachChild_->DeclareInputInteger64(1);
+    }
+
+    attachChild_->BindInteger64(0, parent);
+    attachChild_->BindInteger64(1, child);
+    attachChild_->Run();
+  }
+
+
+  void PostgreSQLWrapper::ClearTable(const std::string& tableName)
+  {
+    connection_->Execute("DELETE FROM " + tableName);    
+  }
+
+
+  int64_t PostgreSQLWrapper::CreateResource(const char* publicId,
+                                            OrthancPluginResourceType type)
+  {
+    if (createResource_.get() == NULL)
+    {
+      createResource_.reset
+        (new PostgreSQLStatement
+         (*connection_, "INSERT INTO Resources VALUES(DEFAULT, $1, $2, NULL) RETURNING internalId"));
+      createResource_->DeclareInputInteger(0);
+      createResource_->DeclareInputString(1);
+    }
+
+    createResource_->BindInteger(0, static_cast<int>(type));
+    createResource_->BindString(1, publicId);
+   
+    PostgreSQLResult result(*createResource_);
+    if (result.IsDone())
+    {
+      throw PostgreSQLException();
+    }
+
+    return result.GetInteger64(0);
+  }
+
+
+  void PostgreSQLWrapper::DeleteAttachment(int64_t id,
+                                           int32_t attachment)
+  {
+    clearDeletedFiles_->Run();
+    clearDeletedResources_->Run();
+
+    if (deleteAttachment_.get() == NULL)
+    {
+      deleteAttachment_.reset
+        (new PostgreSQLStatement
+         (*connection_, "DELETE FROM AttachedFiles WHERE id=$1 AND fileType=$2"));
+      deleteAttachment_->DeclareInputInteger64(0);
+      deleteAttachment_->DeclareInputInteger(1);
+    }
+
+    deleteAttachment_->BindInteger64(0, id);
+    deleteAttachment_->BindInteger(1, static_cast<int>(attachment));
+    deleteAttachment_->Run();
+
+    SignalDeletedFilesAndResources();
+  }
+
+
+  void PostgreSQLWrapper::DeleteMetadata(int64_t id,
+                                         int32_t type)
+  {
+    if (deleteMetadata_.get() == NULL)
+    {
+      deleteMetadata_.reset
+        (new PostgreSQLStatement
+         (*connection_, "DELETE FROM Metadata WHERE id=$1 and type=$2"));
+      deleteMetadata_->DeclareInputInteger64(0);
+      deleteMetadata_->DeclareInputInteger(1);
+    }
+
+    deleteMetadata_->BindInteger64(0, id);
+    deleteMetadata_->BindInteger(1, static_cast<int>(type));
+    deleteMetadata_->Run();
+  }
+
+
+  void PostgreSQLWrapper::DeleteResource(int64_t id)
+  {
+    if (clearRemainingAncestor_.get() == NULL ||
+        getRemainingAncestor_.get() == NULL)
+    {
+      clearRemainingAncestor_.reset
+        (new PostgreSQLStatement
+         (*connection_, "DELETE FROM RemainingAncestor"));
+
+      getRemainingAncestor_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT * FROM RemainingAncestor"));
+    }
+
+    clearDeletedFiles_->Run();
+    clearDeletedResources_->Run();
+    clearRemainingAncestor_->Run();
+
+    if (deleteResource_.get() == NULL)
+    {
+      deleteResource_.reset
+        (new PostgreSQLStatement
+         (*connection_, "DELETE FROM Resources WHERE internalId=$1"));
+      deleteResource_->DeclareInputInteger64(0);
+    }
+
+    deleteResource_->BindInteger64(0, id);
+    deleteResource_->Run();
+
+    PostgreSQLResult result(*getRemainingAncestor_);
+    if (!result.IsDone())
+    {
+      GetOutput().SignalRemainingAncestor(result.GetString(1),
+                                          static_cast<OrthancPluginResourceType>(result.GetInteger(0)));
+
+      // There is at most 1 remaining ancestor
+      assert((result.Step(), result.IsDone()));
+    }
+
+    SignalDeletedFilesAndResources();
+  }
+
+
+  void PostgreSQLWrapper::GetAllPublicIds(std::list<std::string>& target,
+                                          OrthancPluginResourceType resourceType)
+  {
+    if (getAllPublicIds_.get() == NULL)
+    {
+      getAllPublicIds_.reset
+        (new PostgreSQLStatement(*connection_, 
+                                 "SELECT publicId FROM Resources WHERE resourceType=$1"));
+      getAllPublicIds_->DeclareInputInteger(0);
+    }
+
+    getAllPublicIds_->BindInteger(0, static_cast<int>(resourceType));
+    PostgreSQLResult result(*getAllPublicIds_);
+
+    target.clear();
+
+    while (!result.IsDone())
+    {
+      target.push_back(result.GetString(0));
+      result.Step();
+    }
+  }
+
+
+  void PostgreSQLWrapper::GetChangesInternal(bool& done,
+                                             PostgreSQLStatement& s,
+                                             uint32_t maxResults)
+  {
+    PostgreSQLResult result(s);
+    uint32_t count = 0;
+
+    while (count < maxResults && !result.IsDone())
+    {
+      GetOutput().AnswerChange(result.GetInteger64(0),
+                               result.GetInteger(1),
+                               static_cast<OrthancPluginResourceType>(result.GetInteger(3)),
+                               GetPublicId(result.GetInteger64(2)),
+                               result.GetString(4));
+      result.Step();
+      count++;
+    }
+
+    done = !(count == maxResults && !result.IsDone());
+  }
+
+  
+  void PostgreSQLWrapper::GetChanges(bool& done,
+                                     int64_t since,
+                                     uint32_t maxResults)
+  {
+    if (getChanges_.get() == NULL)
+    {
+      getChanges_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT * FROM Changes WHERE seq>$1 ORDER BY seq LIMIT $2"));
+      getChanges_->DeclareInputInteger64(0);
+      getChanges_->DeclareInputInteger(1);
+    }
+
+    getChanges_->BindInteger64(0, since);
+    getChanges_->BindInteger(1, maxResults + 1);
+    GetChangesInternal(done, *getChanges_, maxResults);
+  }
+
+  void PostgreSQLWrapper::GetLastChange()
+  {
+    if (getLastChange_.get() == NULL)
+    {
+      getLastChange_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT * FROM Changes ORDER BY seq DESC LIMIT 1"));
+    }
+
+    bool done;  // Ignored
+    GetChangesInternal(done, *getLastChange_, 1);
+  }
+
+
+  void PostgreSQLWrapper::GetChildrenInternalId(std::list<int64_t>& target,
+                                                int64_t id)
+  {
+    if (getChildrenInternalId_.get() == NULL)
+    {
+      getChildrenInternalId_.reset
+        (new PostgreSQLStatement(*connection_, 
+                                 "SELECT a.internalId FROM Resources AS a, Resources AS b  "
+                                 "WHERE a.parentId = b.internalId AND b.internalId = $1"));
+      getChildrenInternalId_->DeclareInputInteger64(0);
+    }
+
+    getChildrenInternalId_->BindInteger64(0, id);
+    PostgreSQLResult result(*getChildrenInternalId_);
+
+    target.clear();
+
+    while (!result.IsDone())
+    {
+      target.push_back(result.GetInteger64(0));
+      result.Step();
+    }
+  }
+
+
+
+  void PostgreSQLWrapper::GetChildrenPublicId(std::list<std::string>& target,
+                                              int64_t id)
+  {
+    if (getChildrenPublicId_.get() == NULL)
+    {
+      getChildrenPublicId_.reset
+        (new PostgreSQLStatement(*connection_, 
+                                 "SELECT a.publicId FROM Resources AS a, Resources AS b  "
+                                 "WHERE a.parentId = b.internalId AND b.internalId = $1"));
+      getChildrenPublicId_->DeclareInputInteger64(0);
+    }
+
+    getChildrenPublicId_->BindInteger64(0, id);
+    PostgreSQLResult result(*getChildrenPublicId_);
+
+    target.clear();
+
+    while (!result.IsDone())
+    {
+      target.push_back(result.GetString(0));
+      result.Step();
+    }
+  }
+
+
+  void PostgreSQLWrapper::GetExportedResourcesInternal(bool& done,
+                                                       PostgreSQLStatement& s,
+                                                       uint32_t maxResults)
+  {
+    PostgreSQLResult result(s);
+    uint32_t count = 0;
+
+    while (count < maxResults && !result.IsDone())
+    {
+      int64_t seq = result.GetInteger64(0);
+      OrthancPluginResourceType resourceType = static_cast<OrthancPluginResourceType>(result.GetInteger(1));
+      std::string publicId = result.GetString(2);
+
+      GetOutput().AnswerExportedResource(seq, 
+                                         resourceType,
+                                         publicId,
+                                         result.GetString(3),  // modality
+                                         result.GetString(8),  // date
+                                         result.GetString(4),  // patient ID
+                                         result.GetString(5),  // study instance UID
+                                         result.GetString(6),  // series instance UID
+                                         result.GetString(7)); // sop instance UID
+
+      result.Step();
+      count++;
+    }
+
+    done = !(count == maxResults && !result.IsDone());
+  }
+
+  void PostgreSQLWrapper::GetExportedResources(bool& done,
+                                               int64_t since,
+                                               uint32_t maxResults)
+  {
+    if (getExports_.get() == NULL)
+    {
+      getExports_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT * FROM ExportedResources WHERE seq>$1 ORDER BY seq LIMIT $2"));
+      getExports_->DeclareInputInteger64(0);
+      getExports_->DeclareInputInteger(1);
+    }
+
+    getExports_->BindInteger64(0, since);
+    getExports_->BindInteger(1, maxResults + 1);
+    GetExportedResourcesInternal(done, *getExports_, maxResults);
+  }
+
+  void PostgreSQLWrapper::GetLastExportedResource()
+  {
+    if (getLastExport_.get() == NULL)
+    {
+      getLastExport_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT * FROM ExportedResources ORDER BY seq DESC LIMIT 1"));
+    }
+
+    bool done;  // Ignored
+    GetExportedResourcesInternal(done, *getLastExport_, 1);
+  }
+
+
+  void PostgreSQLWrapper::GetMainDicomTags(int64_t id)
+  {
+    if (getMainDicomTags1_.get() == NULL ||
+        getMainDicomTags2_.get() == NULL)
+    {
+      getMainDicomTags1_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT * FROM MainDicomTags WHERE id=$1"));
+      getMainDicomTags1_->DeclareInputInteger64(0);
+
+      getMainDicomTags2_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT * FROM DicomIdentifiers WHERE id=$1"));
+      getMainDicomTags2_->DeclareInputInteger64(0);
+    }
+
+    {
+      getMainDicomTags1_->BindInteger64(0, id);
+      PostgreSQLResult result(*getMainDicomTags1_);
+
+      while (!result.IsDone())
+      {
+        GetOutput().AnswerDicomTag(static_cast<uint16_t>(result.GetInteger(1)),
+                                   static_cast<uint16_t>(result.GetInteger(2)),
+                                   result.GetString(3));
+        result.Step();
+      }
+    }
+
+    {
+      getMainDicomTags2_->BindInteger64(0, id);
+      PostgreSQLResult result(*getMainDicomTags2_);
+
+      while (!result.IsDone())
+      {
+        GetOutput().AnswerDicomTag(static_cast<uint16_t>(result.GetInteger(1)),
+                                   static_cast<uint16_t>(result.GetInteger(2)),
+                                   result.GetString(3));
+        result.Step();
+      }
+    }
+  }
+
+
+  std::string PostgreSQLWrapper::GetPublicId(int64_t resourceId)
+  {
+    getPublicId_->BindInteger64(0, resourceId);
+    
+    PostgreSQLResult result(*getPublicId_);
+    if (result.IsDone())
+    { 
+      throw PostgreSQLException("Unknown resource");
+    }
+
+    return result.GetString(0);
+  }
+
+
+
+  uint64_t PostgreSQLWrapper::GetResourceCount(OrthancPluginResourceType resourceType)
+  {
+    if (getResourceCount_.get() == NULL)
+    {
+      getResourceCount_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT CAST(COUNT(*) AS BIGINT) FROM Resources WHERE resourceType=$1"));
+      getResourceCount_->DeclareInputInteger(0);
+    }
+
+    getResourceCount_->BindInteger(0, static_cast<int>(resourceType));
+
+    PostgreSQLResult result(*getResourceCount_);
+    if (result.IsDone())
+    {
+      throw PostgreSQLException();
+    }
+
+    if (result.IsNull(0))
+    {
+      return 0;
+    }
+    else
+    {
+      return result.GetInteger64(0);
+    }
+  }
+
+
+
+  OrthancPluginResourceType PostgreSQLWrapper::GetResourceType(int64_t resourceId)
+  {
+    if (getResourceType_.get() == NULL)
+    {
+      getResourceType_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT resourceType FROM Resources WHERE internalId=$1"));
+      getResourceType_->DeclareInputInteger64(0);
+    }
+
+    getResourceType_->BindInteger64(0, resourceId);
+    
+    PostgreSQLResult result(*getResourceType_);
+    if (result.IsDone())
+    { 
+      throw PostgreSQLException("Unknown resource");
+    }
+
+    return static_cast<OrthancPluginResourceType>(result.GetInteger(0));
+  }
+
+
+  uint64_t PostgreSQLWrapper::GetTotalCompressedSize()
+  {
+    if (getTotalCompressedSize_.get() == NULL)
+    {
+      getTotalCompressedSize_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT CAST(SUM(compressedSize) AS BIGINT) FROM AttachedFiles"));
+    }
+
+    PostgreSQLResult result(*getTotalCompressedSize_);
+    if (result.IsDone())
+    {
+      throw PostgreSQLException();
+    }
+
+    if (result.IsNull(0))
+    {
+      return 0;
+    }
+    else
+    {
+      return result.GetInteger64(0);
+    }
+  }
+    
+
+  uint64_t PostgreSQLWrapper::GetTotalUncompressedSize()
+  {
+    if (getTotalUncompressedSize_.get() == NULL)
+    {
+      getTotalUncompressedSize_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT CAST(SUM(uncompressedSize) AS BIGINT) FROM AttachedFiles"));
+    }
+
+    PostgreSQLResult result(*getTotalUncompressedSize_);
+    if (result.IsDone())
+    {
+      throw PostgreSQLException();
+    }
+
+    if (result.IsNull(0))
+    {
+      return 0;
+    }
+    else
+    {
+      return result.GetInteger64(0);
+    }
+  }
+
+
+  bool PostgreSQLWrapper::IsExistingResource(int64_t internalId)
+  {
+    getPublicId_->BindInteger64(0, internalId);
+    PostgreSQLResult result(*getPublicId_);
+    return !result.IsDone();
+  }
+
+
+  bool PostgreSQLWrapper::IsProtectedPatient(int64_t internalId)
+  {
+    if (isProtectedPatient_.get() == NULL)
+    {
+      isProtectedPatient_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT * FROM PatientRecyclingOrder WHERE patientId = $1"));
+      isProtectedPatient_->DeclareInputInteger64(0);
+    }
+
+    isProtectedPatient_->BindInteger64(0, internalId);
+    PostgreSQLResult result(*isProtectedPatient_);
+    return result.IsDone();
+  }
+
+
+  void PostgreSQLWrapper::ListAvailableMetadata(std::list<int32_t>& target,
+                                                int64_t id)
+  {
+    if (listMetadata_.get() == NULL)
+    {
+      listMetadata_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT type FROM Metadata WHERE id=$1"));
+      listMetadata_->DeclareInputInteger64(0);
+    }
+
+    listMetadata_->BindInteger64(0, id);
+    PostgreSQLResult result(*listMetadata_);
+
+    target.clear();
+
+    while (!result.IsDone())
+    {
+      target.push_back(static_cast<int32_t>(result.GetInteger(0)));
+      result.Step();
+    }
+  }
+
+
+  void PostgreSQLWrapper::ListAvailableAttachments(std::list<int32_t>& target,
+                                                   int64_t id)
+  {
+    if (listAttachments_.get() == NULL)
+    {
+      listAttachments_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT fileType FROM AttachedFiles WHERE id=$1"));
+      listAttachments_->DeclareInputInteger64(0);
+    }
+
+    listAttachments_->BindInteger64(0, id);
+    PostgreSQLResult result(*listAttachments_);
+
+    target.clear();
+
+    while (!result.IsDone())
+    {
+      target.push_back(static_cast<int32_t>(result.GetInteger(0)));
+      result.Step();
+    }
+  }
+
+
+  void PostgreSQLWrapper::LogChange(const OrthancPluginChange& change)
+  {
+    if (logChange_.get() == NULL)
+    {
+      logChange_.reset
+        (new PostgreSQLStatement
+         (*connection_, "INSERT INTO Changes VALUES(DEFAULT, $1, $2, $3, $4)"));
+      logChange_->DeclareInputInteger(0);
+      logChange_->DeclareInputInteger64(1);
+      logChange_->DeclareInputInteger(2);
+      logChange_->DeclareInputString(3);
+    }
+
+    int64_t id;
+    OrthancPluginResourceType type;
+    if (!LookupResource(id, type, change.publicId) ||
+        type != change.resourceType)
+    {
+      throw PostgreSQLException();
+    }
+
+    logChange_->BindInteger(0, change.changeType);
+    logChange_->BindInteger64(1, id);
+    logChange_->BindInteger(2, change.resourceType);
+    logChange_->BindString(3, change.date);
+    logChange_->Run();      
+  }
+
+
+
+
+  void PostgreSQLWrapper::LogExportedResource(const OrthancPluginExportedResource& resource)
+  {
+    if (logExport_.get() == NULL)
+    {
+      logExport_.reset
+        (new PostgreSQLStatement
+         (*connection_, "INSERT INTO ExportedResources VALUES(DEFAULT, $1, $2, $3, $4, $5, $6, $7, $8)"));
+      logExport_->DeclareInputInteger(0);
+      logExport_->DeclareInputString(1);
+      logExport_->DeclareInputString(2);
+      logExport_->DeclareInputString(3);
+      logExport_->DeclareInputString(4);
+      logExport_->DeclareInputString(5);
+      logExport_->DeclareInputString(6);
+      logExport_->DeclareInputString(7);
+    }
+
+    logExport_->BindInteger(0, resource.resourceType);
+    logExport_->BindString(1, resource.publicId);
+    logExport_->BindString(2, resource.modality);
+    logExport_->BindString(3, resource.patientId);
+    logExport_->BindString(4, resource.studyInstanceUid);
+    logExport_->BindString(5, resource.seriesInstanceUid);
+    logExport_->BindString(6, resource.sopInstanceUid);
+    logExport_->BindString(7, resource.date);
+    logExport_->Run();      
+  }
+
+
+
+
+  bool PostgreSQLWrapper::LookupAttachment(int64_t id,
+                                           int32_t contentType)
+  {
+    if (lookupAttachment_.get() == NULL)
+    {
+      lookupAttachment_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT uuid, uncompressedSize, compressionType, compressedSize, "
+          "uncompressedHash, compressedHash FROM AttachedFiles WHERE id=$1 AND fileType=$2"));
+      lookupAttachment_->DeclareInputInteger64(0);
+      lookupAttachment_->DeclareInputInteger(1);
+    }
+
+    lookupAttachment_->BindInteger64(0, id);
+    lookupAttachment_->BindInteger(1, static_cast<int>(contentType));
+
+    PostgreSQLResult result(*lookupAttachment_);
+    if (!result.IsDone())
+    {
+      GetOutput().AnswerAttachment(result.GetString(0),
+                                   contentType,
+                                   result.GetInteger64(1),
+                                   result.GetString(4),
+                                   result.GetInteger(2),
+                                   result.GetInteger64(3),
+                                   result.GetString(5));
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+  void PostgreSQLWrapper::LookupIdentifier(std::list<int64_t>& target,
+                                           uint16_t group,
+                                           uint16_t element,
+                                           const char* value)
+  {
+    if (lookupIdentifier1_.get() == NULL)
+    {
+      lookupIdentifier1_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT id FROM DicomIdentifiers WHERE tagGroup=$1 AND tagElement=$2 and value=$3"));
+      lookupIdentifier1_->DeclareInputInteger(0);
+      lookupIdentifier1_->DeclareInputInteger(1);
+      lookupIdentifier1_->DeclareInputBinary(2);
+    }
+
+
+    lookupIdentifier1_->BindInteger(0, group);
+    lookupIdentifier1_->BindInteger(1, element);
+    lookupIdentifier1_->BindString(2, value);
+
+    PostgreSQLResult result(*lookupIdentifier1_);
+    target.clear();
+
+    while (!result.IsDone())
+    {
+      target.push_back(result.GetInteger64(0));
+      result.Step();
+    }
+  }
+
+  void PostgreSQLWrapper::LookupIdentifier(std::list<int64_t>& target,
+                                           const char* value)
+  {
+    if (lookupIdentifier2_.get() == NULL)
+    {
+      lookupIdentifier2_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT id FROM DicomIdentifiers WHERE value=$1"));
+      lookupIdentifier2_->DeclareInputBinary(0);
+    }
+
+    lookupIdentifier2_->BindString(0, value);
+
+    PostgreSQLResult result(*lookupIdentifier2_);
+    target.clear();
+
+    while (!result.IsDone())
+    {
+      target.push_back(result.GetInteger64(0));
+      result.Step();
+    }
+  }
+
+
+  bool PostgreSQLWrapper::LookupMetadata(std::string& target,
+                                         int64_t id,
+                                         int32_t type)
+  {
+    if (lookupMetadata_.get() == NULL)
+    {
+      lookupMetadata_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT value FROM Metadata WHERE id=$1 and type=$2"));
+      lookupMetadata_->DeclareInputInteger64(0);
+      lookupMetadata_->DeclareInputInteger(1);
+    }
+
+    lookupMetadata_->BindInteger64(0, id);
+    lookupMetadata_->BindInteger(1, static_cast<int>(type));
+
+    PostgreSQLResult result(*lookupMetadata_);
+    if (result.IsDone())
+    {
+      return false;
+    }
+    else
+    {
+      target = result.GetString(0);
+      return true;
+    }
+  }
+
+
+  bool PostgreSQLWrapper::LookupParent(int64_t& parentId,
+                                       int64_t resourceId)
+  {
+    if (lookupParent_.get() == NULL)
+    {
+      lookupParent_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT parentId FROM Resources WHERE internalId=$1"));
+      lookupParent_->DeclareInputInteger64(0);
+    }
+
+    lookupParent_->BindInteger64(0, resourceId);
+
+    PostgreSQLResult result(*lookupParent_);
+    if (result.IsDone())
+    {
+      throw PostgreSQLException("Unknown resource");
+    }
+
+    if (result.IsNull(0))
+    {
+      return false;
+    }
+    else
+    {
+      parentId = result.GetInteger64(0);
+      return true;
+    }
+  }
+
+
+  bool PostgreSQLWrapper::LookupResource(int64_t& id,
+                                         OrthancPluginResourceType& type,
+                                         const char* publicId)
+  {
+    if (lookupResource_.get() == NULL)
+    {
+      lookupResource_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT internalId, resourceType FROM Resources WHERE publicId=$1"));
+      lookupResource_->DeclareInputString(0);
+    }
+
+    lookupResource_->BindString(0, publicId);
+
+    PostgreSQLResult result(*lookupResource_);
+    if (result.IsDone())
+    {
+      return false;
+    }
+    else
+    {
+      id = result.GetInteger64(0);
+      type = static_cast<OrthancPluginResourceType>(result.GetInteger(1));
+      return true;
+    }
+  }
+
+
+  bool PostgreSQLWrapper::SelectPatientToRecycle(int64_t& internalId)
+  {
+    if (selectPatientToRecycle_.get() == NULL)
+    {
+      selectPatientToRecycle_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT patientId FROM PatientRecyclingOrder ORDER BY seq ASC LIMIT 1"));
+    }
+
+    PostgreSQLResult result(*selectPatientToRecycle_);
+
+    if (result.IsDone())
+    {
+      // No patient remaining or all the patients are protected
+      return false;
+    }
+    else
+    {
+      internalId = result.GetInteger64(0);
+      return true;
+    }   
+  }
+
+
+  bool PostgreSQLWrapper::SelectPatientToRecycle(int64_t& internalId,
+                                                 int64_t patientIdToAvoid)
+  {
+    if (selectPatientToRecycleAvoid_.get() == NULL)
+    {
+      selectPatientToRecycleAvoid_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT patientId FROM PatientRecyclingOrder WHERE patientId != $1 ORDER BY seq ASC LIMIT 1"));
+      selectPatientToRecycleAvoid_->DeclareInputInteger64(0);
+    }
+
+    selectPatientToRecycleAvoid_->BindInteger64(0, patientIdToAvoid);
+    PostgreSQLResult result(*selectPatientToRecycleAvoid_);
+
+    if (result.IsDone())
+    {
+      // No patient remaining or all the patients are protected
+      return false;
+    }
+    else
+    {
+      internalId = result.GetInteger64(0);
+      return true;
+    }   
+  }
+
+
+  static void SetTagInternal(PostgreSQLStatement& s,
+                             int64_t id,
+                             uint16_t group,
+                             uint16_t element,
+                             const char* value)
+  {
+    s.BindInteger64(0, id);
+    s.BindInteger(1, group);
+    s.BindInteger(2, element);
+    s.BindString(3, value);
+    s.Run();
+  }
+
+
+  void PostgreSQLWrapper::SetMainDicomTag(int64_t id,
+                                          uint16_t group,
+                                          uint16_t element,
+                                          const char* value)
+  {
+    if (setMainDicomTags_.get() == NULL)
+    {
+      setMainDicomTags_.reset
+        (new PostgreSQLStatement
+         (*connection_, "INSERT INTO MainDicomTags VALUES($1, $2, $3, $4)"));
+      setMainDicomTags_->DeclareInputInteger64(0);
+      setMainDicomTags_->DeclareInputInteger(1);
+      setMainDicomTags_->DeclareInputInteger(2);
+      setMainDicomTags_->DeclareInputBinary(3);
+    }
+
+    SetTagInternal(*setMainDicomTags_, id, group, element, value);
+  }
+
+  void PostgreSQLWrapper::SetIdentifierTag(int64_t id,
+                                           uint16_t group,
+                                           uint16_t element,
+                                           const char* value)
+  {
+    if (setIdentifierTag_.get() == NULL)
+    {
+      setIdentifierTag_.reset
+        (new PostgreSQLStatement
+         (*connection_, "INSERT INTO DicomIdentifiers VALUES($1, $2, $3, $4)"));
+      setIdentifierTag_->DeclareInputInteger64(0);
+      setIdentifierTag_->DeclareInputInteger(1);
+      setIdentifierTag_->DeclareInputInteger(2);
+      setIdentifierTag_->DeclareInputBinary(3);
+    }
+
+    SetTagInternal(*setIdentifierTag_, id, group, element, value);
+  }
+
+
+  void PostgreSQLWrapper::SetMetadata(int64_t id,
+                                      int32_t type,
+                                      const char* value)
+  {
+    if (setMetadata_.get() == NULL)
+    {
+      setMetadata_.reset
+        (new PostgreSQLStatement
+         (*connection_, "SELECT ChangeMetadata($1, $2, $3)"));
+      setMetadata_->DeclareInputInteger64(0);
+      setMetadata_->DeclareInputInteger(1);
+      setMetadata_->DeclareInputString(2);
+    }
+
+    setMetadata_->BindInteger64(0, id);
+    setMetadata_->BindInteger(1, static_cast<int>(type));
+    setMetadata_->BindString(2, value);
+    setMetadata_->Run();
+  }
+
+
+
+  void PostgreSQLWrapper::SetProtectedPatient(int64_t internalId, 
+                                              bool isProtected)
+  {
+    if (protectPatient1_.get() == NULL ||
+        protectPatient2_.get() == NULL)
+    {
+      protectPatient1_.reset
+        (new PostgreSQLStatement
+         (*connection_, "DELETE FROM PatientRecyclingOrder WHERE patientId=$1"));
+      protectPatient1_->DeclareInputInteger64(0);
+    
+      protectPatient2_.reset
+        (new PostgreSQLStatement
+         (*connection_, "INSERT INTO PatientRecyclingOrder VALUES(DEFAULT, $1)"));
+      protectPatient2_->DeclareInputInteger64(0);
+    }
+
+    if (isProtected)
+    {
+      protectPatient1_->BindInteger64(0, internalId);
+      protectPatient1_->Run();
+    }
+    else if (IsProtectedPatient(internalId))
+    {
+      protectPatient2_->BindInteger64(0, internalId);
+      protectPatient2_->Run();
+    }
+    else
+    {
+      // Nothing to do: The patient is already unprotected
+    }
+  }
+
+
+
+  // For unit testing only!
+  void PostgreSQLWrapper::GetChildren(std::list<std::string>& childrenPublicIds,
+                                      int64_t id)
+  {
+    PostgreSQLStatement s(*connection_, "SELECT publicId FROM Resources WHERE parentId=$1");
+    s.DeclareInputInteger64(0);
+    s.BindInteger64(0, id);
+
+    PostgreSQLResult result(s);
+
+    childrenPublicIds.clear();
+
+    while (!result.IsDone())
+    {
+      childrenPublicIds.push_back(result.GetString(0));
+      result.Step();
+    }
+  }
+
+
+
+
+  // For unit testing only!
+  int64_t PostgreSQLWrapper::GetTableRecordCount(const std::string& table)
+  {
+    char buf[128];
+    sprintf(buf, "SELECT CAST(COUNT(*) AS BIGINT) FROM %s", table.c_str());
+    PostgreSQLStatement s(*connection_, buf);
+
+    PostgreSQLResult result(s);
+    if (result.IsDone())
+    {
+      throw PostgreSQLException();
+    }
+
+    if (result.IsNull(0))
+    {
+      return 0;
+    }
+    else
+    {
+      return result.GetInteger64(0);
+    }
+  }
+    
+
+
+  // For unit testing only!
+  bool PostgreSQLWrapper::GetParentPublicId(std::string& target,
+                                            int64_t id)
+  {
+    PostgreSQLStatement s(*connection_, 
+                          "SELECT a.publicId FROM Resources AS a, Resources AS b "
+                          "WHERE a.internalId = b.parentId AND b.internalId = $1");
+    s.DeclareInputInteger64(0);
+    s.BindInteger64(0, id);
+
+    PostgreSQLResult result(s);
+
+    if (result.IsDone())
+    {
+      return false;
+    }
+    else
+    {
+      target = result.GetString(0);
+      return true;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IndexPlugin/PostgreSQLWrapper.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,276 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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 <orthanc/OrthancCppDatabasePlugin.h>
+
+#include "../Core/GlobalProperties.h"
+#include "../Core/PostgreSQLConnection.h"
+#include "../Core/PostgreSQLStatement.h"
+#include "../Core/PostgreSQLResult.h"
+#include "../Core/PostgreSQLTransaction.h"
+
+#include <list>
+
+namespace OrthancPlugins
+{
+  class PostgreSQLWrapper : public IDatabaseBackend
+  {
+  private:
+    std::auto_ptr<PostgreSQLConnection> connection_;
+    std::auto_ptr<PostgreSQLTransaction>  transaction_;
+    GlobalProperties  globalProperties_;
+
+    std::auto_ptr<PostgreSQLStatement> attachFile_;
+    std::auto_ptr<PostgreSQLStatement> attachChild_;
+    std::auto_ptr<PostgreSQLStatement> createResource_;
+    std::auto_ptr<PostgreSQLStatement> deleteAttachment_;
+    std::auto_ptr<PostgreSQLStatement> deleteMetadata_;
+    std::auto_ptr<PostgreSQLStatement> deleteResource_;
+    std::auto_ptr<PostgreSQLStatement> getAllMetadata_;
+    std::auto_ptr<PostgreSQLStatement> getAllPublicIds_;
+    std::auto_ptr<PostgreSQLStatement> getChanges_;
+    std::auto_ptr<PostgreSQLStatement> getLastChange_;
+    std::auto_ptr<PostgreSQLStatement> getChildrenInternalId_;
+    std::auto_ptr<PostgreSQLStatement> getChildrenPublicId_;
+    std::auto_ptr<PostgreSQLStatement> getExports_;
+    std::auto_ptr<PostgreSQLStatement> getLastExport_;
+    std::auto_ptr<PostgreSQLStatement> getMainDicomTags1_;
+    std::auto_ptr<PostgreSQLStatement> getMainDicomTags2_;
+    std::auto_ptr<PostgreSQLStatement> getPublicId_;
+    std::auto_ptr<PostgreSQLStatement> getResourceCount_;
+    std::auto_ptr<PostgreSQLStatement> getResourceType_;
+    std::auto_ptr<PostgreSQLStatement> getTotalCompressedSize_;
+    std::auto_ptr<PostgreSQLStatement> getTotalUncompressedSize_;
+    std::auto_ptr<PostgreSQLStatement> isProtectedPatient_;
+    std::auto_ptr<PostgreSQLStatement> listMetadata_;
+    std::auto_ptr<PostgreSQLStatement> listAttachments_;
+    std::auto_ptr<PostgreSQLStatement> logChange_;
+    std::auto_ptr<PostgreSQLStatement> logExport_;
+    std::auto_ptr<PostgreSQLStatement> lookupAttachment_;
+    std::auto_ptr<PostgreSQLStatement> lookupIdentifier1_;
+    std::auto_ptr<PostgreSQLStatement> lookupIdentifier2_;
+    std::auto_ptr<PostgreSQLStatement> lookupMetadata_;
+    std::auto_ptr<PostgreSQLStatement> lookupParent_;
+    std::auto_ptr<PostgreSQLStatement> lookupResource_;
+    std::auto_ptr<PostgreSQLStatement> selectPatientToRecycle_;
+    std::auto_ptr<PostgreSQLStatement> selectPatientToRecycleAvoid_;
+    std::auto_ptr<PostgreSQLStatement> setMainDicomTags_;
+    std::auto_ptr<PostgreSQLStatement> setIdentifierTag_;
+    std::auto_ptr<PostgreSQLStatement> setMetadata_;
+    std::auto_ptr<PostgreSQLStatement> protectPatient1_;
+    std::auto_ptr<PostgreSQLStatement> protectPatient2_;
+
+    std::auto_ptr<PostgreSQLStatement> clearDeletedFiles_;
+    std::auto_ptr<PostgreSQLStatement> clearDeletedResources_;
+    std::auto_ptr<PostgreSQLStatement> clearRemainingAncestor_;
+    std::auto_ptr<PostgreSQLStatement> getDeletedFiles_;
+    std::auto_ptr<PostgreSQLStatement> getDeletedResources_;
+    std::auto_ptr<PostgreSQLStatement> getRemainingAncestor_;
+ 
+    void Prepare();
+
+    void SignalDeletedFilesAndResources();
+
+    void GetChangesInternal(bool& done,
+                            PostgreSQLStatement& s,
+                            uint32_t maxResults);
+
+    void GetExportedResourcesInternal(bool& done,
+                                      PostgreSQLStatement& s,
+                                      uint32_t maxResults);
+
+    void ClearTable(const std::string& tableName);
+
+  public:
+    PostgreSQLWrapper(PostgreSQLConnection* connection,  // Takes the ownership of the connection
+                      bool allowUnlock);
+
+    virtual ~PostgreSQLWrapper();
+
+    virtual void Open()
+    {
+      connection_->Open();
+    }
+
+    virtual void Close()
+    {
+      transaction_.reset(NULL);
+    }
+
+    virtual void AddAttachment(int64_t id,
+                               const OrthancPluginAttachment& attachment);
+
+    virtual void AttachChild(int64_t parent,
+                             int64_t child);
+
+    virtual void ClearChanges()
+    {
+      ClearTable("Changes");
+    }
+
+    virtual void ClearExportedResources()
+    {
+      ClearTable("ExportedResources");
+    }
+
+    virtual int64_t CreateResource(const char* publicId,
+                                   OrthancPluginResourceType type);
+
+    virtual void DeleteAttachment(int64_t id,
+                                  int32_t attachment);
+
+    virtual void DeleteMetadata(int64_t id,
+                                int32_t type);
+
+    virtual void DeleteResource(int64_t id);
+
+    virtual void GetAllPublicIds(std::list<std::string>& target,
+                                 OrthancPluginResourceType resourceType);
+
+    virtual void GetChanges(bool& done /*out*/,
+                            int64_t since,
+                            uint32_t maxResults);
+
+    virtual void GetChildrenInternalId(std::list<int64_t>& result,
+                                       int64_t id);
+
+    virtual void GetChildrenPublicId(std::list<std::string>& result,
+                                     int64_t id);
+
+    virtual void GetExportedResources(bool& done /*out*/,
+                                      int64_t since,
+                                      uint32_t maxResults);
+
+    virtual void GetLastChange();
+
+    virtual void GetLastExportedResource();
+    
+    virtual void GetMainDicomTags(int64_t id);
+
+    virtual std::string GetPublicId(int64_t resourceId);
+
+    virtual uint64_t GetResourceCount(OrthancPluginResourceType resourceType);
+
+    virtual OrthancPluginResourceType GetResourceType(int64_t resourceId);
+
+    virtual uint64_t GetTotalCompressedSize();
+    
+    virtual uint64_t GetTotalUncompressedSize();
+
+    virtual bool IsExistingResource(int64_t internalId);
+
+    virtual bool IsProtectedPatient(int64_t internalId);
+
+    virtual void ListAvailableMetadata(std::list<int32_t>& target,
+                                       int64_t id);
+
+    virtual void ListAvailableAttachments(std::list<int32_t>& result,
+                                          int64_t id);
+
+    virtual void LogChange(const OrthancPluginChange& change);
+
+    virtual void LogExportedResource(const OrthancPluginExportedResource& resource);
+    
+    virtual bool LookupAttachment(int64_t id,
+                                  int32_t contentType);
+
+    virtual bool LookupGlobalProperty(std::string& target,
+                                      int32_t property)
+    {
+      return globalProperties_.LookupGlobalProperty(target, property);
+    }
+
+    virtual void LookupIdentifier(std::list<int64_t>& result,
+                                  uint16_t group,
+                                  uint16_t element,
+                                  const char* value);
+
+    virtual void LookupIdentifier(std::list<int64_t>& result,
+                                  const char* value);
+
+    virtual bool LookupMetadata(std::string& target,
+                                int64_t id,
+                                int32_t type);
+
+    virtual bool LookupParent(int64_t& parentId,
+                              int64_t resourceId);
+
+    virtual bool LookupResource(int64_t& id /*out*/,
+                                OrthancPluginResourceType& type /*out*/,
+                                const char* publicId);
+
+    virtual bool SelectPatientToRecycle(int64_t& internalId);
+
+    virtual bool SelectPatientToRecycle(int64_t& internalId,
+                                        int64_t patientIdToAvoid);
+
+    virtual void SetGlobalProperty(int32_t property,
+                                   const char* value)
+    {
+      return globalProperties_.SetGlobalProperty(property, value);
+    }
+
+    virtual void SetMainDicomTag(int64_t id,
+                                 uint16_t group,
+                                 uint16_t element,
+                                 const char* value);
+
+    virtual void SetIdentifierTag(int64_t id,
+                                  uint16_t group,
+                                  uint16_t element,
+                                  const char* value);
+
+    virtual void SetMetadata(int64_t id,
+                             int32_t type,
+                             const char* value);
+
+    virtual void SetProtectedPatient(int64_t internalId, 
+                                     bool isProtected);
+
+    virtual void StartTransaction()
+    {
+      transaction_.reset(new PostgreSQLTransaction(*connection_));
+    }
+
+    virtual void RollbackTransaction()
+    {
+      transaction_.reset(NULL);
+    }
+
+    virtual void CommitTransaction()
+    {
+      transaction_->Commit();
+      transaction_.reset(NULL);
+    }
+
+    // For unit tests only!
+    void GetChildren(std::list<std::string>& childrenPublicIds,
+                     int64_t id);
+
+    // For unit tests only!
+    int64_t GetTableRecordCount(const std::string& table);
+
+    // For unit tests only!
+    bool GetParentPublicId(std::string& result,
+                           int64_t id);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NEWS	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,4 @@
+Version 1.0.0 (2015/02/06)
+==========================
+
+* Initial release
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,44 @@
+PostgreSQL plugins for Orthanc
+==============================
+
+
+General Information
+-------------------
+
+This repository contains the source code of 2 plugins for Orthanc, the
+lightweight, RESTful DICOM server. These 2 plugins enable Orthanc to
+store its files and its index as PostgreSQL databases.
+
+
+Supported Platforms
+-------------------
+
+Currently, the supported platforms are:
+
+* Linux 32bit.
+* Linux 64bit.
+* Windows 32bit.
+
+
+Licensing
+---------
+
+The PostgreSQL plugins for Orthanc are licensed under the AGPL license.
+
+We also kindly ask scientific works and clinical studies that make
+use of Orthanc to cite Orthanc in their associated publications.
+Similarly, we ask open-source and closed-source products that make
+use of Orthanc to warn us about this use. You can cite our work
+using the following BibTeX entry:
+
+@inproceedings{Jodogne:ISBI2013,
+  author = {Jodogne, S. and Bernard, C. and Devillers, M. and Lenaerts, E. and Coucke, P.},
+  title = {Orthanc -- {A} Lightweight, {REST}ful {DICOM} Server for Healthcare and Medical Research},
+  booktitle={Biomedical Imaging ({ISBI}), {IEEE} 10th International Symposium on}, 
+  year={2013}, 
+  pages={190-193}, 
+  ISSN={1945-7928},
+  month=apr,
+  url={http://ieeexplore.ieee.org/xpl/articleDetails.jsp?tp=&arnumber=6556444},
+  address={San Francisco, {CA}, {USA}}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/CMake/AutoGeneratedCode.cmake	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,59 @@
+# Orthanc - A Lightweight, RESTful DICOM Store
+# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+# Department, University Hospital of Liege, 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/>.
+
+
+set(AUTOGENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/AUTOGENERATED")
+set(AUTOGENERATED_SOURCES)
+
+file(MAKE_DIRECTORY ${AUTOGENERATED_DIR})
+include_directories(${AUTOGENERATED_DIR})
+
+macro(EmbedResources)
+  # Convert a semicolon separated list to a whitespace separated string
+  set(SCRIPT_ARGUMENTS)
+  set(DEPENDENCIES)
+  set(IS_PATH_NAME false)
+  foreach(arg ${ARGN})
+    if (${IS_PATH_NAME})
+      list(APPEND SCRIPT_ARGUMENTS "${arg}")
+      list(APPEND DEPENDENCIES "${arg}")
+      set(IS_PATH_NAME false)
+    else()
+      list(APPEND SCRIPT_ARGUMENTS "${arg}")
+      set(IS_PATH_NAME true)
+    endif()
+  endforeach()
+
+  set(TARGET_BASE "${AUTOGENERATED_DIR}/EmbeddedResources")
+  add_custom_command(
+    OUTPUT
+    "${TARGET_BASE}.h"
+    "${TARGET_BASE}.cpp"
+    COMMAND 
+    python
+    "${CMAKE_CURRENT_SOURCE_DIR}/Resources/EmbedResources.py"
+    "${AUTOGENERATED_DIR}/EmbeddedResources"
+    ${SCRIPT_ARGUMENTS}
+    DEPENDS
+    "${CMAKE_CURRENT_SOURCE_DIR}/Resources/EmbedResources.py"
+    ${DEPENDENCIES}
+    )
+
+  list(APPEND AUTOGENERATED_SOURCES
+    "${AUTOGENERATED_DIR}/EmbeddedResources.cpp"
+    ) 
+endmacro()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/CMake/BoostConfiguration.cmake	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,74 @@
+# Orthanc - A Lightweight, RESTful DICOM Store
+# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+# Department, University Hospital of Liege, 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/>.
+
+
+if (STATIC_BUILD OR NOT USE_SYSTEM_BOOST)
+  set(BOOST_STATIC 1)
+else()
+  include(FindBoost)
+  set(BOOST_STATIC 0)
+  find_package(Boost COMPONENTS )
+
+  if (NOT Boost_FOUND)
+    message(FATAL_ERROR "Unable to locate Boost on this system")
+  endif()
+
+  include_directories(${Boost_INCLUDE_DIRS})
+  link_libraries(${Boost_LIBRARIES})
+endif()
+
+
+if (BOOST_STATIC)
+  # Parameters for Boost 1.55.0
+  set(BOOST_NAME boost_1_55_0)
+  set(BOOST_BCP_SUFFIX bcpdigest-0.7.4)
+  set(BOOST_MD5 "409f7a0e4fb1f5659d07114f3133b67b")
+  set(BOOST_FILESYSTEM_SOURCES_DIR "${BOOST_NAME}/libs/filesystem/src")
+  
+  set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME})
+  DownloadPackage(
+    "${BOOST_MD5}"
+    "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz"
+    "${BOOST_SOURCES_DIR}"
+    )
+
+  add_definitions(
+    # Static build of Boost
+    -DBOOST_ALL_NO_LIB 
+    -DBOOST_ALL_NOLIB 
+    -DBOOST_DATE_TIME_NO_LIB 
+    -DBOOST_THREAD_BUILD_LIB
+    -DBOOST_PROGRAM_OPTIONS_NO_LIB
+    -DBOOST_REGEX_NO_LIB
+    -DBOOST_SYSTEM_NO_LIB
+    -DBOOST_LOCALE_NO_LIB
+    )
+
+  if (${CMAKE_COMPILER_IS_GNUCXX})
+    add_definitions(-isystem ${BOOST_SOURCES_DIR})
+  endif()
+
+  include_directories(
+    ${BOOST_SOURCES_DIR}
+    )
+
+  list(APPEND BOOST_SOURCES
+    ${BOOST_SOURCES_DIR}/libs/system/src/error_code.cpp
+    )
+
+  source_group(ThirdParty\\Boost REGULAR_EXPRESSION ${BOOST_SOURCES_DIR}/.*)
+endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/CMake/DownloadPackage.cmake	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,156 @@
+# Orthanc - A Lightweight, RESTful DICOM Store
+# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+# Department, University Hospital of Liege, 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/>.
+
+
+macro(GetUrlFilename TargetVariable Url)
+  string(REGEX REPLACE "^.*/" "" ${TargetVariable} "${Url}")
+endmacro()
+
+
+macro(GetUrlExtension TargetVariable Url)
+  #string(REGEX REPLACE "^.*/[^.]*\\." "" TMP "${Url}")
+  string(REGEX REPLACE "^.*\\." "" TMP "${Url}")
+  string(TOLOWER "${TMP}" "${TargetVariable}")
+endmacro()
+
+
+##
+## Check the existence of the required decompression tools
+##
+
+if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
+  find_program(ZIP_EXECUTABLE 7z 
+    PATHS 
+    "$ENV{ProgramFiles}/7-Zip"
+    "$ENV{ProgramW6432}/7-Zip"
+    )
+
+  if (${ZIP_EXECUTABLE} MATCHES "ZIP_EXECUTABLE-NOTFOUND")
+    message(FATAL_ERROR "Please install the '7-zip' software (http://www.7-zip.org/)")
+  endif()
+
+else()
+  find_program(UNZIP_EXECUTABLE unzip)
+  if (${UNZIP_EXECUTABLE} MATCHES "UNZIP_EXECUTABLE-NOTFOUND")
+    message(FATAL_ERROR "Please install the 'unzip' package")
+  endif()
+
+  find_program(TAR_EXECUTABLE tar)
+  if (${TAR_EXECUTABLE} MATCHES "TAR_EXECUTABLE-NOTFOUND")
+    message(FATAL_ERROR "Please install the 'tar' package")
+  endif()
+endif()
+
+
+macro(DownloadPackage MD5 Url TargetDirectory)
+  if (NOT IS_DIRECTORY "${TargetDirectory}")
+    GetUrlFilename(TMP_FILENAME "${Url}")
+
+    set(TMP_PATH "${CMAKE_SOURCE_DIR}/ThirdPartyDownloads/${TMP_FILENAME}")
+    if (NOT EXISTS "${TMP_PATH}")
+      message("Downloading ${Url}")
+
+      # This fixes issue 6: "I think cmake shouldn't download the
+      # packages which are not in the system, it should stop and let
+      # user know."
+      # https://code.google.com/p/orthanc/issues/detail?id=6
+      if (NOT STATIC_BUILD AND NOT ALLOW_DOWNLOADS)
+	message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON")
+      endif()
+
+      file(DOWNLOAD "${Url}" "${TMP_PATH}" SHOW_PROGRESS EXPECTED_MD5 "${MD5}")
+    else()
+      message("Using local copy of ${Url}")
+    endif()
+
+    GetUrlExtension(TMP_EXTENSION "${Url}")
+    #message(${TMP_EXTENSION})
+    message("Uncompressing ${TMP_FILENAME}")
+
+    if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
+      # How to silently extract files using 7-zip
+      # http://superuser.com/questions/331148/7zip-command-line-extract-silently-quietly
+
+      if (("${TMP_EXTENSION}" STREQUAL "gz") OR ("${TMP_EXTENSION}" STREQUAL "tgz"))
+        execute_process(
+          COMMAND ${ZIP_EXECUTABLE} e -y ${TMP_PATH}
+          WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+          RESULT_VARIABLE Failure
+          OUTPUT_QUIET
+          )
+
+        if (Failure)
+          message(FATAL_ERROR "Error while running the uncompression tool")
+        endif()
+
+        if ("${TMP_EXTENSION}" STREQUAL "tgz")
+          string(REGEX REPLACE ".tgz$" ".tar" TMP_FILENAME2 "${TMP_FILENAME}")
+        else()
+          string(REGEX REPLACE ".gz$" "" TMP_FILENAME2 "${TMP_FILENAME}")
+        endif()
+
+        execute_process(
+          COMMAND ${ZIP_EXECUTABLE} x -y ${TMP_FILENAME2}
+          WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+          RESULT_VARIABLE Failure
+          OUTPUT_QUIET
+          )
+      elseif ("${TMP_EXTENSION}" STREQUAL "zip")
+        execute_process(
+          COMMAND ${ZIP_EXECUTABLE} x -y ${TMP_PATH}
+          WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+          RESULT_VARIABLE Failure
+          OUTPUT_QUIET
+          )
+      else()
+        message(FATAL_ERROR "Support your platform here")
+      endif()
+
+    else()
+      if ("${TMP_EXTENSION}" STREQUAL "zip")
+        execute_process(
+          COMMAND sh -c "${UNZIP_EXECUTABLE} -q ${TMP_PATH}"
+          WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+          RESULT_VARIABLE Failure
+        )
+      elseif (("${TMP_EXTENSION}" STREQUAL "gz") OR ("${TMP_EXTENSION}" STREQUAL "tgz"))
+        #message("tar xvfz ${TMP_PATH}")
+        execute_process(
+          COMMAND sh -c "${TAR_EXECUTABLE} xfz ${TMP_PATH}"
+          WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+          RESULT_VARIABLE Failure
+          )
+      elseif ("${TMP_EXTENSION}" STREQUAL "bz2")
+        execute_process(
+          COMMAND sh -c "${TAR_EXECUTABLE} xfj ${TMP_PATH}"
+          WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+          RESULT_VARIABLE Failure
+          )
+      else()
+        message(FATAL_ERROR "Unknown package format.")
+      endif()
+    endif()
+   
+    if (Failure)
+      message(FATAL_ERROR "Error while running the uncompression tool")
+    endif()
+
+    if (NOT IS_DIRECTORY "${TargetDirectory}")
+      message(FATAL_ERROR "The package was not uncompressed at the proper location. Check the CMake instructions.")
+    endif()
+  endif()
+endmacro()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/CMake/FindPostgreSQL.cmake	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,177 @@
+# Fixed by SJ
+# http://stackoverflow.com/questions/13920383/findpostgresql-cmake-wont-work-on-ubuntu
+
+
+# - Find the PostgreSQL installation.
+# In Windows, we make the assumption that, if the PostgreSQL files are installed, the default directory
+# will be C:\Program Files\PostgreSQL.
+#
+# This module defines
+#  PostgreSQL_LIBRARIES - the PostgreSQL libraries needed for linking
+#  PostgreSQL_INCLUDE_DIRS - the directories of the PostgreSQL headers
+#  PostgreSQL_VERSION_STRING - the version of PostgreSQL found (since CMake 2.8.8)
+
+#=============================================================================
+# Copyright 2004-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# ----------------------------------------------------------------------------
+# History:
+# This module is derived from the module originally found in the VTK source tree.
+#
+# ----------------------------------------------------------------------------
+# Note:
+# PostgreSQL_ADDITIONAL_VERSIONS is a variable that can be used to set the
+# version mumber of the implementation of PostgreSQL.
+# In Windows the default installation of PostgreSQL uses that as part of the path.
+# E.g C:\Program Files\PostgreSQL\8.4.
+# Currently, the following version numbers are known to this module:
+# "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0"
+#
+# To use this variable just do something like this:
+# set(PostgreSQL_ADDITIONAL_VERSIONS "9.2" "8.4.4")
+# before calling FIND_PACKAGE(PostgreSQL) in your CMakeLists.txt file.
+# This will mean that the versions you set here will be found first in the order
+# specified before the default ones are searched.
+#
+# ----------------------------------------------------------------------------
+# You may need to manually set:
+#  PostgreSQL_INCLUDE_DIR  - the path to where the PostgreSQL include files are.
+#  PostgreSQL_LIBRARY_DIR  - The path to where the PostgreSQL library files are.
+# If FindPostgreSQL.cmake cannot find the include files or the library files.
+#
+# ----------------------------------------------------------------------------
+# The following variables are set if PostgreSQL is found:
+#  PostgreSQL_FOUND         - Set to true when PostgreSQL is found.
+#  PostgreSQL_INCLUDE_DIRS  - Include directories for PostgreSQL
+#  PostgreSQL_LIBRARY_DIRS  - Link directories for PostgreSQL libraries
+#  PostgreSQL_LIBRARIES     - The PostgreSQL libraries.
+#
+# ----------------------------------------------------------------------------
+# If you have installed PostgreSQL in a non-standard location.
+# (Please note that in the following comments, it is assumed that <Your Path>
+# points to the root directory of the include directory of PostgreSQL.)
+# Then you have three options.
+# 1) After CMake runs, set PostgreSQL_INCLUDE_DIR to <Your Path>/include and
+#    PostgreSQL_LIBRARY_DIR to wherever the library pq (or libpq in windows) is
+# 2) Use CMAKE_INCLUDE_PATH to set a path to <Your Path>/PostgreSQL<-version>. This will allow find_path()
+#    to locate PostgreSQL_INCLUDE_DIR by utilizing the PATH_SUFFIXES option. e.g. In your CMakeLists.txt file
+#    SET(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "<Your Path>/include")
+# 3) Set an environment variable called ${PostgreSQL_ROOT} that points to the root of where you have
+#    installed PostgreSQL, e.g. <Your Path>.
+#
+# ----------------------------------------------------------------------------
+
+set(PostgreSQL_INCLUDE_PATH_DESCRIPTION "top-level directory containing the PostgreSQL include directories. E.g /usr/local/include/PostgreSQL/8.4 or C:/Program Files/PostgreSQL/8.4/include")
+set(PostgreSQL_INCLUDE_DIR_MESSAGE "Set the PostgreSQL_INCLUDE_DIR cmake cache entry to the ${PostgreSQL_INCLUDE_PATH_DESCRIPTION}")
+set(PostgreSQL_LIBRARY_PATH_DESCRIPTION "top-level directory containing the PostgreSQL libraries.")
+set(PostgreSQL_LIBRARY_DIR_MESSAGE "Set the PostgreSQL_LIBRARY_DIR cmake cache entry to the ${PostgreSQL_LIBRARY_PATH_DESCRIPTION}")
+set(PostgreSQL_ROOT_DIR_MESSAGE "Set the PostgreSQL_ROOT system variable to where PostgreSQL is found on the machine E.g C:/Program Files/PostgreSQL/8.4")
+
+
+set(PostgreSQL_ROOT_DIRECTORIES $ENV{PostgreSQL_ROOT})
+if(PostgreSQL_ROOT_DIRECTORIES)
+  file(TO_CMAKE_PATH ${PostgreSQL_ROOT_DIRECTORIES} PostgreSQL_ROOT_DIRECTORIES)
+endif(PostgreSQL_ROOT_DIRECTORIES)
+
+set(PostgreSQL_KNOWN_VERSIONS ${PostgreSQL_ADDITIONAL_VERSIONS}
+    "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0")
+
+# Define additional search paths for root directories.
+if ( WIN32 )
+  foreach (suffix ${PostgreSQL_KNOWN_VERSIONS} )
+    set(PostgreSQL_ADDITIONAL_SEARCH_PATHS ${PostgreSQL_ADDITIONAL_SEARCH_PATHS} "C:/Program Files/PostgreSQL/${suffix}" )
+  endforeach(suffix)
+endif( WIN32 )
+set( PostgreSQL_ROOT_DIRECTORIES
+   ${PostgreSQL_ROOT_DIRECTORIES}
+   ${PostgreSQL_ROOT}
+   ${PostgreSQL_ADDITIONAL_SEARCH_PATHS}
+)
+
+#
+# Look for an installation.
+#
+find_path(PostgreSQL_INCLUDE_DIR
+  NAMES libpq-fe.h
+  PATHS
+   # Look in other places.
+   ${PostgreSQL_ROOT_DIRECTORIES}
+  PATH_SUFFIXES
+    pgsql
+    postgresql
+    include
+  # Help the user find it if we cannot.
+  DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}"
+)
+
+find_path(PostgreSQL_TYPE_INCLUDE_DIR
+  NAMES catalog/pg_type.h
+  PATHS
+   # Look in other places.
+   ${PostgreSQL_ROOT_DIRECTORIES}
+  PATH_SUFFIXES
+    postgresql   # Fix by SJ: http://stackoverflow.com/questions/13920383/findpostgresql-cmake-wont-work-on-ubuntu
+    pgsql/server
+    postgresql/server
+    include/server
+  # Help the user find it if we cannot.
+  DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}"
+)
+
+# The PostgreSQL library.
+set (PostgreSQL_LIBRARY_TO_FIND pq)
+# Setting some more prefixes for the library
+set (PostgreSQL_LIB_PREFIX "")
+if ( WIN32 )
+  set (PostgreSQL_LIB_PREFIX ${PostgreSQL_LIB_PREFIX} "lib")
+  set ( PostgreSQL_LIBRARY_TO_FIND ${PostgreSQL_LIB_PREFIX}${PostgreSQL_LIBRARY_TO_FIND})
+endif()
+
+find_library( PostgreSQL_LIBRARY
+ NAMES ${PostgreSQL_LIBRARY_TO_FIND}
+ PATHS
+   ${PostgreSQL_ROOT_DIRECTORIES}
+ PATH_SUFFIXES
+   lib
+)
+get_filename_component(PostgreSQL_LIBRARY_DIR ${PostgreSQL_LIBRARY} PATH)
+
+if (PostgreSQL_INCLUDE_DIR AND EXISTS "${PostgreSQL_INCLUDE_DIR}/pg_config.h")
+  file(STRINGS "${PostgreSQL_INCLUDE_DIR}/pg_config.h" pgsql_version_str
+       REGEX "^#define[\t ]+PG_VERSION[\t ]+\".*\"")
+
+  string(REGEX REPLACE "^#define[\t ]+PG_VERSION[\t ]+\"([^\"]*)\".*" "\\1"
+         PostgreSQL_VERSION_STRING "${pgsql_version_str}")
+  unset(pgsql_version_str)
+endif()
+
+# Did we find anything?
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(PostgreSQL
+                                  REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR
+                                  VERSION_VAR PostgreSQL_VERSION_STRING)
+set( PostgreSQL_FOUND  ${POSTGRESQL_FOUND})
+
+# Now try to get the include and library path.
+if(PostgreSQL_FOUND)
+
+  set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR} ${PostgreSQL_TYPE_INCLUDE_DIR} )
+  set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR} )
+  set(PostgreSQL_LIBRARIES ${PostgreSQL_LIBRARY_TO_FIND})
+
+  #message("Final PostgreSQL include dir: ${PostgreSQL_INCLUDE_DIRS}")
+  #message("Final PostgreSQL library dir: ${PostgreSQL_LIBRARY_DIRS}")
+  #message("Final PostgreSQL libraries:   ${PostgreSQL_LIBRARIES}")
+endif(PostgreSQL_FOUND)
+
+mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR PostgreSQL_LIBRARY )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/CMake/GoogleTestConfiguration.cmake	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,57 @@
+# Orthanc - A Lightweight, RESTful DICOM Store
+# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+# Department, University Hospital of Liege, 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/>.
+
+
+if (USE_GTEST_DEBIAN_SOURCE_PACKAGE)
+  set(GTEST_SOURCES /usr/src/gtest/src/gtest-all.cc)
+  include_directories(/usr/src/gtest)
+
+  if (NOT EXISTS /usr/include/gtest/gtest.h OR
+      NOT EXISTS ${GTEST_SOURCES})
+    message(FATAL_ERROR "Please install the libgtest-dev package")
+  endif()
+
+elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST)
+  set(GTEST_SOURCES_DIR ${CMAKE_BINARY_DIR}/gtest-1.7.0)
+  DownloadPackage(
+    "2d6ec8ccdf5c46b05ba54a9fd1d130d7"
+    "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/gtest-1.7.0.zip"
+    "${GTEST_SOURCES_DIR}")
+
+  include_directories(
+    ${GTEST_SOURCES_DIR}/include
+    ${GTEST_SOURCES_DIR}
+    )
+
+  set(GTEST_SOURCES
+    ${GTEST_SOURCES_DIR}/src/gtest-all.cc
+    )
+
+  # https://code.google.com/p/googletest/issues/detail?id=412
+  if (MSVC) # VS2012 does not support tuples correctly yet
+    add_definitions(/D _VARIADIC_MAX=10)
+  endif()
+
+else()
+  include(FindGTest)
+  if (NOT GTEST_FOUND)
+    message(FATAL_ERROR "Unable to find GoogleTest")
+  endif()
+
+  include_directories(${GTEST_INCLUDE_DIRS})
+  link_libraries(${GTEST_LIBRARIES})
+endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/CMake/JsonCppConfiguration.cmake	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,47 @@
+# Orthanc - A Lightweight, RESTful DICOM Store
+# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+# Department, University Hospital of Liege, 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/>.
+
+
+if (STATIC_BUILD OR NOT USE_SYSTEM_JSONCPP)
+  set(JSONCPP_SOURCES_DIR ${CMAKE_BINARY_DIR}/jsoncpp-src-0.6.0-rc2)
+  DownloadPackage(
+    "363e2f4cbd3aeb63bf4e571f377400fb"
+    "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/jsoncpp-src-0.6.0-rc2.tar.gz"
+    "${JSONCPP_SOURCES_DIR}")
+
+  list(APPEND JSONCPP_SOURCES
+    ${JSONCPP_SOURCES_DIR}/src/lib_json/json_reader.cpp
+    ${JSONCPP_SOURCES_DIR}/src/lib_json/json_value.cpp
+    ${JSONCPP_SOURCES_DIR}/src/lib_json/json_writer.cpp
+    )
+
+  include_directories(
+    ${JSONCPP_SOURCES_DIR}/include
+    )
+
+  source_group(ThirdParty\\JsonCpp REGULAR_EXPRESSION ${JSONCPP_SOURCES_DIR}/.*)
+
+else()
+  CHECK_INCLUDE_FILE_CXX(jsoncpp/json/reader.h HAVE_JSONCPP_H)
+  if (NOT HAVE_JSONCPP_H)
+    message(FATAL_ERROR "Please install the libjsoncpp-dev package")
+  endif()
+
+  include_directories(/usr/include/jsoncpp)
+  link_libraries(jsoncpp)
+
+endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/CMake/PostgreSQLConfiguration.cmake	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,183 @@
+# Orthanc - A Lightweight, RESTful DICOM Store
+# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+# Department, University Hospital of Liege, 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/>.
+
+
+#####################################################################
+## PostgreSQL
+#####################################################################
+
+if (STATIC_BUILD OR NOT USE_SYSTEM_LIBPQ)
+  SET(PQ_SOURCES_DIR ${CMAKE_BINARY_DIR}/postgresql-9.4.0)
+  DownloadPackage(
+    "349552802c809c4e8b09d8045a437787"
+    "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/postgresql-9.4.0.tar.gz"
+    "${PQ_SOURCES_DIR}")
+
+  if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+    set(PQ_CONFIG_H ${PQ_SOURCES_DIR}/src/include/pg_config.h.win32)
+
+    if (${MSVC})
+      configure_file(
+        ${PQ_SOURCES_DIR}/src/include/pg_config.h.win32
+        ${AUTOGENERATED_DIR}/pg_config.h
+        COPY_ONLY)
+
+      configure_file(
+        ${PQ_SOURCES_DIR}/src/include/pg_config_ext.h.win32
+        ${AUTOGENERATED_DIR}/pg_config_ext.h
+        COPY_ONLY)
+
+    else()
+      if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+        set(PQ_CONFIG_H ${CMAKE_SOURCE_DIR}/Resources/Platforms/pg_config-windows64.h)
+      else()
+        set(PQ_CONFIG_H ${CMAKE_SOURCE_DIR}/Resources/Platforms/pg_config-windows32.h)
+      endif()
+    endif()
+
+    add_definitions(
+      -DEXEC_BACKEND
+      )
+
+    configure_file(
+      ${PQ_SOURCES_DIR}/src/include/port/win32.h
+      ${AUTOGENERATED_DIR}/pg_config_os.h
+      COPY_ONLY)
+
+  else()
+    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread")
+
+    if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+      set(PQ_CONFIG_H ${CMAKE_SOURCE_DIR}/Resources/Platforms/pg_config-linux64.h)
+    else()
+      set(PQ_CONFIG_H ${CMAKE_SOURCE_DIR}/Resources/Platforms/pg_config-linux32.h)
+    endif()
+
+    add_definitions(
+      -D_GNU_SOURCE
+      -D_THREAD_SAFE
+      -D_POSIX_PTHREAD_SEMANTICS
+      )
+
+    configure_file(
+      ${PQ_SOURCES_DIR}/src/include/port/linux.h
+      ${AUTOGENERATED_DIR}/pg_config_os.h
+      COPY_ONLY)
+  endif()
+
+
+  configure_file(
+    ${PQ_CONFIG_H}
+    ${AUTOGENERATED_DIR}/pg_config.h
+    COPY_ONLY
+    )
+
+  configure_file(
+    ${CMAKE_SOURCE_DIR}/Resources/Platforms/pg_config_ext.h
+    ${AUTOGENERATED_DIR}/pg_config_ext.h
+    COPY_ONLY
+    )
+
+  file(WRITE
+    ${AUTOGENERATED_DIR}/pg_config_paths.h
+    "")
+
+  add_definitions(
+    -D_REENTRANT
+    -DFRONTEND
+    -DUNSAFE_STAT_OK
+    -DSYSCONFDIR=""
+    )
+
+  include_directories(
+    ${PQ_SOURCES_DIR}/src/include
+    ${PQ_SOURCES_DIR}/src/include/libpq
+    ${PQ_SOURCES_DIR}/src/interfaces/libpq
+    )
+
+  set(LIBPQ_SOURCES
+    ${PQ_SOURCES_DIR}/src/interfaces/libpq/fe-auth.c 
+    ${PQ_SOURCES_DIR}/src/interfaces/libpq/fe-connect.c
+    ${PQ_SOURCES_DIR}/src/interfaces/libpq/fe-exec.c
+    ${PQ_SOURCES_DIR}/src/interfaces/libpq/fe-lobj.c
+    ${PQ_SOURCES_DIR}/src/interfaces/libpq/fe-misc.c
+    ${PQ_SOURCES_DIR}/src/interfaces/libpq/fe-print.c
+    ${PQ_SOURCES_DIR}/src/interfaces/libpq/fe-protocol2.c
+    ${PQ_SOURCES_DIR}/src/interfaces/libpq/fe-protocol3.c
+    ${PQ_SOURCES_DIR}/src/interfaces/libpq/fe-secure.c
+    ${PQ_SOURCES_DIR}/src/interfaces/libpq/libpq-events.c
+    ${PQ_SOURCES_DIR}/src/interfaces/libpq/pqexpbuffer.c
+
+    # libpgport C files we always use
+    ${PQ_SOURCES_DIR}/src/port/chklocale.c
+    ${PQ_SOURCES_DIR}/src/port/inet_net_ntop.c
+    ${PQ_SOURCES_DIR}/src/port/noblock.c
+    ${PQ_SOURCES_DIR}/src/port/pgstrcasecmp.c
+    ${PQ_SOURCES_DIR}/src/port/pqsignal.c
+    ${PQ_SOURCES_DIR}/src/port/thread.c
+
+    ${PQ_SOURCES_DIR}/src/backend/libpq/ip.c
+    ${PQ_SOURCES_DIR}/src/backend/libpq/md5.c
+    ${PQ_SOURCES_DIR}/src/backend/utils/mb/encnames.c
+    ${PQ_SOURCES_DIR}/src/backend/utils/mb/wchar.c
+    ${PQ_SOURCES_DIR}/src/port/strlcpy.c
+    )
+
+  if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+    include_directories(
+      ${PQ_SOURCES_DIR}/src/include/port/win32
+      ${PQ_SOURCES_DIR}/src/port
+      )
+    
+    LIST(APPEND LIBPQ_SOURCES
+      # libpgport C files that are needed if identified by configure
+      ${PQ_SOURCES_DIR}/src/interfaces/libpq/pthread-win32.c
+      ${PQ_SOURCES_DIR}/src/interfaces/libpq/win32.c
+      ${PQ_SOURCES_DIR}/src/port/crypt.c 
+      ${PQ_SOURCES_DIR}/src/port/inet_aton.c
+      ${PQ_SOURCES_DIR}/src/port/open.c
+      ${PQ_SOURCES_DIR}/src/port/pgsleep.c
+      ${PQ_SOURCES_DIR}/src/port/snprintf.c
+      ${PQ_SOURCES_DIR}/src/port/system.c 
+      ${PQ_SOURCES_DIR}/src/port/win32error.c
+      ${PQ_SOURCES_DIR}/src/port/win32setlocale.c
+      ${PQ_SOURCES_DIR}/src/port/getaddrinfo.c
+      )
+  endif()
+
+  if (${CMAKE_COMPILER_IS_GNUCXX})
+    LIST(APPEND LIBPQ_SOURCES
+      ${PQ_SOURCES_DIR}/src/port/getpeereid.c
+      )
+  elseif (${MSVC})
+    include_directories(
+      ${PQ_SOURCES_DIR}/src/include/port/win32_msvc
+      )
+    
+    LIST(APPEND LIBPQ_SOURCES
+      ${PQ_SOURCES_DIR}/src/port/dirent.c 
+      ${PQ_SOURCES_DIR}/src/port/dirmod.c 
+      )
+  endif()
+
+  source_group(ThirdParty\\PostgreSQL REGULAR_EXPRESSION ${PQ_SOURCES_DIR}/.*)
+
+else()
+  include(${CMAKE_SOURCE_DIR}/Resources/CMake/FindPostgreSQL.cmake)
+  include_directories(${PostgreSQL_INCLUDE_DIR})
+  link_libraries(${PostgreSQL_LIBRARY})
+endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/EmbedResources.py	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,391 @@
+# Orthanc - A Lightweight, RESTful DICOM Store
+# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+# Department, University Hospital of Liege, 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/>.
+
+
+import sys
+import os
+import os.path
+import pprint
+import re
+
+UPCASE_CHECK = True
+ARGS = []
+for i in range(len(sys.argv)):
+    if not sys.argv[i].startswith('--'):
+        ARGS.append(sys.argv[i])
+    elif sys.argv[i].lower() == '--no-upcase-check':
+        UPCASE_CHECK = False
+
+if len(ARGS) < 2 or len(ARGS) % 2 != 0:
+    print ('Usage:')
+    print ('python %s [--no-upcase-check] <TargetBaseFilename> [ <Name> <Source> ]*' % sys.argv[0])
+    exit(-1)
+
+TARGET_BASE_FILENAME = ARGS[1]
+SOURCES = ARGS[2:]
+
+try:
+    # Make sure the destination directory exists
+    os.makedirs(os.path.normpath(os.path.join(TARGET_BASE_FILENAME, '..')))
+except:
+    pass
+
+
+#####################################################################
+## Read each resource file
+#####################################################################
+
+def CheckNoUpcase(s):
+    global UPCASE_CHECK
+    if (UPCASE_CHECK and
+        re.search('[A-Z]', s) != None):
+        raise Exception("Path in a directory with an upcase letter: %s" % s)
+
+resources = {}
+
+counter = 0
+i = 0
+while i < len(SOURCES):
+    resourceName = SOURCES[i].upper()
+    pathName = SOURCES[i + 1]
+
+    if not os.path.exists(pathName):
+        raise Exception("Non existing path: %s" % pathName)
+
+    if resourceName in resources:
+        raise Exception("Twice the same resource: " + resourceName)
+    
+    if os.path.isdir(pathName):
+        # The resource is a directory: Recursively explore its files
+        content = {}
+        for root, dirs, files in os.walk(pathName):
+            base = os.path.relpath(root, pathName)
+
+            # Fix issue #24 (Build fails on OSX when directory has .DS_Store files):
+            # Ignore folders whose name starts with a dot (".")
+            if base.find('/.') != -1:
+                print('Ignoring folder: %s' % root)
+                continue
+
+            for f in files:
+                if f.find('~') == -1:  # Ignore Emacs backup files
+                    if base == '.':
+                        r = f
+                    else:
+                        r = os.path.join(base, f)
+
+                    CheckNoUpcase(r)
+                    r = '/' + r.replace('\\', '/')
+                    if r in content:
+                        raise Exception("Twice the same filename (check case): " + r)
+
+                    content[r] = {
+                        'Filename' : os.path.join(root, f),
+                        'Index' : counter
+                        }
+                    counter += 1
+
+        resources[resourceName] = {
+            'Type' : 'Directory',
+            'Files' : content
+            }
+
+    elif os.path.isfile(pathName):
+        resources[resourceName] = {
+            'Type' : 'File',
+            'Index' : counter,
+            'Filename' : pathName
+            }
+        counter += 1
+
+    else:
+        raise Exception("Not a regular file, nor a directory: " + pathName)
+
+    i += 2
+
+#pprint.pprint(resources)
+
+
+#####################################################################
+## Write .h header
+#####################################################################
+
+header = open(TARGET_BASE_FILENAME + '.h', 'w')
+
+header.write("""
+#pragma once
+
+#include <string>
+#include <list>
+
+namespace OrthancPlugins
+{
+  namespace EmbeddedResources
+  {
+    enum FileResourceId
+    {
+""")
+
+isFirst = True
+for name in resources:
+    if resources[name]['Type'] == 'File':
+        if isFirst:
+            isFirst = False
+        else:    
+            header.write(',\n')
+        header.write('      %s' % name)
+
+header.write("""
+    };
+
+    enum DirectoryResourceId
+    {
+""")
+
+isFirst = True
+for name in resources:
+    if resources[name]['Type'] == 'Directory':
+        if isFirst:
+            isFirst = False
+        else:    
+            header.write(',\n')
+        header.write('      %s' % name)
+
+header.write("""
+    };
+
+    const void* GetFileResourceBuffer(FileResourceId id);
+    size_t GetFileResourceSize(FileResourceId id);
+    void GetFileResource(std::string& result, FileResourceId id);
+
+    const void* GetDirectoryResourceBuffer(DirectoryResourceId id, const char* path);
+    size_t GetDirectoryResourceSize(DirectoryResourceId id, const char* path);
+    void GetDirectoryResource(std::string& result, DirectoryResourceId id, const char* path);
+
+    void ListResources(std::list<std::string>& result, DirectoryResourceId id);
+  }
+}
+""")
+header.close()
+
+
+
+#####################################################################
+## Write the resource content in the .cpp source
+#####################################################################
+
+PYTHON_MAJOR_VERSION = sys.version_info[0]
+
+def WriteResource(cpp, item):
+    cpp.write('    static const uint8_t resource%dBuffer[] = {' % item['Index'])
+
+    f = open(item['Filename'], "rb")
+    content = f.read()
+    f.close()
+
+    # http://stackoverflow.com/a/1035360
+    pos = 0
+    for b in content:
+        if PYTHON_MAJOR_VERSION == 2:
+            c = ord(b[0])
+        else:
+            c = b
+
+        if pos > 0:
+            cpp.write(', ')
+
+        if (pos % 16) == 0:
+            cpp.write('\n    ')
+
+        if c < 0:
+            raise Exception("Internal error")
+
+        cpp.write("0x%02x" % c)
+        pos += 1
+
+    cpp.write('  };\n')
+    cpp.write('    static const size_t resource%dSize = %d;\n' % (item['Index'], pos))
+
+
+cpp = open(TARGET_BASE_FILENAME + '.cpp', 'w')
+
+cpp.write("""
+#include "%s.h"
+
+#include <stdexcept>
+#include <stdint.h>
+#include <string.h>
+
+namespace OrthancPlugins
+{
+  namespace EmbeddedResources
+  {
+""" % (os.path.basename(TARGET_BASE_FILENAME)))
+
+
+for name in resources:
+    if resources[name]['Type'] == 'File':
+        WriteResource(cpp, resources[name])
+    else:
+        for f in resources[name]['Files']:
+            WriteResource(cpp, resources[name]['Files'][f])
+
+
+
+#####################################################################
+## Write the accessors to the file resources in .cpp
+#####################################################################
+
+cpp.write("""
+    const void* GetFileResourceBuffer(FileResourceId id)
+    {
+      switch (id)
+      {
+""")
+for name in resources:
+    if resources[name]['Type'] == 'File':
+        cpp.write('      case %s:\n' % name)
+        cpp.write('        return resource%dBuffer;\n' % resources[name]['Index'])
+
+cpp.write("""
+      default:
+        throw std::runtime_error("Parameter out of range");
+      }
+    }
+
+    size_t GetFileResourceSize(FileResourceId id)
+    {
+      switch (id)
+      {
+""")
+
+for name in resources:
+    if resources[name]['Type'] == 'File':
+        cpp.write('      case %s:\n' % name)
+        cpp.write('        return resource%dSize;\n' % resources[name]['Index'])
+
+cpp.write("""
+      default:
+        throw std::runtime_error("Parameter out of range");
+      }
+    }
+""")
+
+
+
+#####################################################################
+## Write the accessors to the directory resources in .cpp
+#####################################################################
+
+cpp.write("""
+    const void* GetDirectoryResourceBuffer(DirectoryResourceId id, const char* path)
+    {
+      switch (id)
+      {
+""")
+
+for name in resources:
+    if resources[name]['Type'] == 'Directory':
+        cpp.write('      case %s:\n' % name)
+        isFirst = True
+        for path in resources[name]['Files']:
+            cpp.write('        if (!strcmp(path, "%s"))\n' % path)
+            cpp.write('          return resource%dBuffer;\n' % resources[name]['Files'][path]['Index'])
+        cpp.write('        throw std::runtime_error("Unknown path in a directory resource");\n\n')
+
+cpp.write("""      default:
+        throw std::runtime_error("Parameter out of range");
+      }
+    }
+
+    size_t GetDirectoryResourceSize(DirectoryResourceId id, const char* path)
+    {
+      switch (id)
+      {
+""")
+
+for name in resources:
+    if resources[name]['Type'] == 'Directory':
+        cpp.write('      case %s:\n' % name)
+        isFirst = True
+        for path in resources[name]['Files']:
+            cpp.write('        if (!strcmp(path, "%s"))\n' % path)
+            cpp.write('          return resource%dSize;\n' % resources[name]['Files'][path]['Index'])
+        cpp.write('        throw std::runtime_error("Unknown path in a directory resource");\n\n')
+
+cpp.write("""      default:
+        throw std::runtime_error("Parameter out of range");
+      }
+    }
+""")
+
+
+
+
+#####################################################################
+## List the resources in a directory
+#####################################################################
+
+cpp.write("""
+    void ListResources(std::list<std::string>& result, DirectoryResourceId id)
+    {
+      result.clear();
+
+      switch (id)
+      {
+""")
+
+for name in resources:
+    if resources[name]['Type'] == 'Directory':
+        cpp.write('      case %s:\n' % name)
+        for path in sorted(resources[name]['Files']):
+            cpp.write('        result.push_back("%s");\n' % path)
+        cpp.write('        break;\n\n')
+
+cpp.write("""      default:
+        throw std::runtime_error("Parameter out of range");
+      }
+    }
+""")
+
+
+
+
+#####################################################################
+## Write the convenience wrappers in .cpp
+#####################################################################
+
+cpp.write("""
+    void GetFileResource(std::string& result, FileResourceId id)
+    {
+      size_t size = GetFileResourceSize(id);
+      result.resize(size);
+      if (size > 0)
+        memcpy(&result[0], GetFileResourceBuffer(id), size);
+    }
+
+    void GetDirectoryResource(std::string& result, DirectoryResourceId id, const char* path)
+    {
+      size_t size = GetDirectoryResourceSize(id, path);
+      result.resize(size);
+      if (size > 0)
+        memcpy(&result[0], GetDirectoryResourceBuffer(id, path), size);
+    }
+  }
+}
+""")
+cpp.close()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Platforms/pg_config-linux32.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,863 @@
+/* src/include/pg_config.h.  Generated from pg_config.h.in by configure.  */
+/* src/include/pg_config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define to the type of arg 1 of 'accept' */
+#define ACCEPT_TYPE_ARG1 int
+
+/* Define to the type of arg 2 of 'accept' */
+#define ACCEPT_TYPE_ARG2 struct sockaddr *
+
+/* Define to the type of arg 3 of 'accept' */
+#define ACCEPT_TYPE_ARG3 size_t
+
+/* Define to the return type of 'accept' */
+#define ACCEPT_TYPE_RETURN int
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* The normal alignment of `double', in bytes. */
+#define ALIGNOF_DOUBLE 4
+
+/* The normal alignment of `int', in bytes. */
+#define ALIGNOF_INT 4
+
+/* The normal alignment of `long', in bytes. */
+#define ALIGNOF_LONG 4
+
+/* The normal alignment of `long long int', in bytes. */
+#define ALIGNOF_LONG_LONG_INT 4
+
+/* The normal alignment of `short', in bytes. */
+#define ALIGNOF_SHORT 2
+
+/* Size of a disk block --- this also limits the size of a tuple. You can set
+   it bigger if you need bigger tuples (although TOAST should reduce the need
+   to have large tuples, since fields can be spread across multiple tuples).
+   BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
+   currently 2^15 (32768). This is determined by the 15-bit widths of the
+   lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
+   Changing BLCKSZ requires an initdb. */
+#define BLCKSZ 8192
+
+/* Define to the default TCP port number on which the server listens and to
+   which clients will try to connect. This can be overridden at run-time, but
+   it's convenient if your clients have the right default compiled in.
+   (--with-pgport=PORTNUM) */
+#define DEF_PGPORT 5432
+
+/* Define to the default TCP port number as a string constant. */
+#define DEF_PGPORT_STR "5432"
+
+/* Define to build with GSSAPI support. (--with-gssapi) */
+/* #undef ENABLE_GSS */
+
+/* Define to 1 if you want National Language Support. (--enable-nls) */
+/* #undef ENABLE_NLS */
+
+/* Define to 1 to build client libraries as thread-safe code.
+   (--enable-thread-safety) */
+#define ENABLE_THREAD_SAFETY 1
+
+/* Define to nothing if C supports flexible array members, and to 1 if it does
+   not. That way, with a declaration like `struct s { int n; double
+   d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99
+   compilers. When computing the size of such an object, don't use 'sizeof
+   (struct s)' as it overestimates the size. Use 'offsetof (struct s, d)'
+   instead. Don't use 'offsetof (struct s, d[0])', as this doesn't work with
+   MSVC and with C++ compilers. */
+#define FLEXIBLE_ARRAY_MEMBER /**/
+
+/* float4 values are passed by value if 'true', by reference if 'false' */
+#define FLOAT4PASSBYVAL true
+
+/* float8, int8, and related values are passed by value if 'true', by
+   reference if 'false' */
+#define FLOAT8PASSBYVAL false
+
+/* Define to 1 if getpwuid_r() takes a 5th argument. */
+#define GETPWUID_R_5ARG 1
+
+/* Define to 1 if gettimeofday() takes only 1 argument. */
+/* #undef GETTIMEOFDAY_1ARG */
+
+#ifdef GETTIMEOFDAY_1ARG
+# define gettimeofday(a,b) gettimeofday(a)
+#endif
+
+/* Define to 1 if you have the `append_history' function. */
+/* #undef HAVE_APPEND_HISTORY */
+
+/* Define to 1 if you have the `cbrt' function. */
+#define HAVE_CBRT 1
+
+/* Define to 1 if you have the `class' function. */
+/* #undef HAVE_CLASS */
+
+/* Define to 1 if you have the <crtdefs.h> header file. */
+/* #undef HAVE_CRTDEFS_H */
+
+/* Define to 1 if you have the `crypt' function. */
+#define HAVE_CRYPT 1
+
+/* Define to 1 if you have the <crypt.h> header file. */
+#define HAVE_CRYPT_H 1
+
+/* Define to 1 if you have the declaration of `fdatasync', and to 0 if you
+   don't. */
+#define HAVE_DECL_FDATASYNC 1
+
+/* Define to 1 if you have the declaration of `F_FULLFSYNC', and to 0 if you
+   don't. */
+#define HAVE_DECL_F_FULLFSYNC 0
+
+/* Define to 1 if you have the declaration of `posix_fadvise', and to 0 if you
+   don't. */
+#define HAVE_DECL_POSIX_FADVISE 1
+
+/* Define to 1 if you have the declaration of `snprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL_SNPRINTF 1
+
+/* Define to 1 if you have the declaration of `strlcat', and to 0 if you
+   don't. */
+#define HAVE_DECL_STRLCAT 0
+
+/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you
+   don't. */
+#define HAVE_DECL_STRLCPY 0
+
+/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you
+   don't. */
+#define HAVE_DECL_SYS_SIGLIST 1
+
+/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL_VSNPRINTF 1
+
+/* Define to 1 if you have the <dld.h> header file. */
+/* #undef HAVE_DLD_H */
+
+/* Define to 1 if you have the `dlopen' function. */
+#define HAVE_DLOPEN 1
+
+/* Define to 1 if you have the <editline/history.h> header file. */
+/* #undef HAVE_EDITLINE_HISTORY_H */
+
+/* Define to 1 if you have the <editline/readline.h> header file. */
+/* #undef HAVE_EDITLINE_READLINE_H */
+
+/* Define to 1 if you have the `fdatasync' function. */
+#define HAVE_FDATASYNC 1
+
+/* Define to 1 if you have the `fls' function. */
+/* #undef HAVE_FLS */
+
+/* Define to 1 if you have the `fpclass' function. */
+/* #undef HAVE_FPCLASS */
+
+/* Define to 1 if you have the `fp_class' function. */
+/* #undef HAVE_FP_CLASS */
+
+/* Define to 1 if you have the `fp_class_d' function. */
+/* #undef HAVE_FP_CLASS_D */
+
+/* Define to 1 if you have the <fp_class.h> header file. */
+/* #undef HAVE_FP_CLASS_H */
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#define HAVE_FSEEKO 1
+
+/* Define to 1 if your compiler understands __func__. */
+#define HAVE_FUNCNAME__FUNC 1
+
+/* Define to 1 if your compiler understands __FUNCTION__. */
+/* #undef HAVE_FUNCNAME__FUNCTION */
+
+/* Define to 1 if you have __sync_lock_test_and_set(int *) and friends. */
+#define HAVE_GCC_INT_ATOMICS 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `gethostbyname_r' function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* Define to 1 if you have the `getifaddrs' function. */
+#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the `getopt' function. */
+#define HAVE_GETOPT 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define to 1 if you have the `getpeereid' function. */
+/* #undef HAVE_GETPEEREID */
+
+/* Define to 1 if you have the `getpeerucred' function. */
+/* #undef HAVE_GETPEERUCRED */
+
+/* Define to 1 if you have the `getpwuid_r' function. */
+#define HAVE_GETPWUID_R 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the `getrusage' function. */
+#define HAVE_GETRUSAGE 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+/* #undef HAVE_GETTIMEOFDAY */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_H */
+
+/* Define to 1 if you have the <history.h> header file. */
+/* #undef HAVE_HISTORY_H */
+
+/* Define to 1 if you have the `history_truncate_file' function. */
+/* #undef HAVE_HISTORY_TRUNCATE_FILE */
+
+/* Define to 1 if you have the <ieeefp.h> header file. */
+/* #undef HAVE_IEEEFP_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#define HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the `inet_aton' function. */
+#define HAVE_INET_ATON 1
+
+/* Define to 1 if the system has the type `int64'. */
+/* #undef HAVE_INT64 */
+
+/* Define to 1 if the system has the type `int8'. */
+/* #undef HAVE_INT8 */
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#define HAVE_INTPTR_T 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the global variable 'int opterr'. */
+#define HAVE_INT_OPTERR 1
+
+/* Define to 1 if you have the global variable 'int optreset'. */
+/* #undef HAVE_INT_OPTRESET */
+
+/* Define to 1 if you have the global variable 'int timezone'. */
+#define HAVE_INT_TIMEZONE 1
+
+/* Define to 1 if you have support for IPv6. */
+#define HAVE_IPV6 1
+
+/* Define to 1 if you have isinf(). */
+#define HAVE_ISINF 1
+
+/* Define to 1 if you have the <langinfo.h> header file. */
+#define HAVE_LANGINFO_H 1
+
+/* Define to 1 if you have the <ldap.h> header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+/* #undef HAVE_LIBCRYPTO */
+
+/* Define to 1 if you have the `ldap' library (-lldap). */
+/* #undef HAVE_LIBLDAP */
+
+/* Define to 1 if you have the `ldap_r' library (-lldap_r). */
+/* #undef HAVE_LIBLDAP_R */
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Define to 1 if you have the `pam' library (-lpam). */
+/* #undef HAVE_LIBPAM */
+
+/* Define if you have a function readline library */
+/* #undef HAVE_LIBREADLINE */
+
+/* Define to 1 if you have the `selinux' library (-lselinux). */
+/* #undef HAVE_LIBSELINUX */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* Define to 1 if you have the `wldap32' library (-lwldap32). */
+/* #undef HAVE_LIBWLDAP32 */
+
+/* Define to 1 if you have the `xml2' library (-lxml2). */
+/* #undef HAVE_LIBXML2 */
+
+/* Define to 1 if you have the `xslt' library (-lxslt). */
+/* #undef HAVE_LIBXSLT */
+
+/* Define to 1 if you have the `z' library (-lz). */
+/* #undef HAVE_LIBZ */
+
+/* Define to 1 if constants of type 'long long int' should have the suffix LL.
+   */
+#define HAVE_LL_CONSTANTS 1
+
+/* Define to 1 if the system has the type `locale_t'. */
+#define HAVE_LOCALE_T 1
+
+/* Define to 1 if `long int' works and is 64 bits. */
+/* #undef HAVE_LONG_INT_64 */
+
+/* Define to 1 if the system has the type `long long int'. */
+#define HAVE_LONG_LONG_INT 1
+
+/* Define to 1 if `long long int' works and is 64 bits. */
+#define HAVE_LONG_LONG_INT_64 1
+
+/* Define to 1 if you have the `mbstowcs_l' function. */
+/* #undef HAVE_MBSTOWCS_L */
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if the system has the type `MINIDUMP_TYPE'. */
+/* #undef HAVE_MINIDUMP_TYPE */
+
+/* Define to 1 if you have the `mkdtemp' function. */
+#define HAVE_MKDTEMP 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if you have the <ossp/uuid.h> header file. */
+/* #undef HAVE_OSSP_UUID_H */
+
+/* Define to 1 if you have the <pam/pam_appl.h> header file. */
+/* #undef HAVE_PAM_PAM_APPL_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `posix_fadvise' function. */
+#define HAVE_POSIX_FADVISE 1
+
+/* Define to 1 if you have the POSIX signal interface. */
+#define HAVE_POSIX_SIGNALS 1
+
+/* Define to 1 if the assembler supports PPC's LWARX mutex hint bit. */
+/* #undef HAVE_PPC_LWARX_MUTEX_HINT */
+
+/* Define to 1 if you have the `pstat' function. */
+/* #undef HAVE_PSTAT */
+
+/* Define to 1 if the PS_STRINGS thing exists. */
+/* #undef HAVE_PS_STRINGS */
+
+/* Define if you have POSIX threads libraries and header files. */
+/* #undef HAVE_PTHREAD */
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `random' function. */
+#define HAVE_RANDOM 1
+
+/* Define to 1 if you have the <readline.h> header file. */
+/* #undef HAVE_READLINE_H */
+
+/* Define to 1 if you have the <readline/history.h> header file. */
+/* #undef HAVE_READLINE_HISTORY_H */
+
+/* Define to 1 if you have the <readline/readline.h> header file. */
+/* #undef HAVE_READLINE_READLINE_H */
+
+/* Define to 1 if you have the `readlink' function. */
+#define HAVE_READLINK 1
+
+/* Define to 1 if you have the `rint' function. */
+#define HAVE_RINT 1
+
+/* Define to 1 if you have the global variable
+   'rl_completion_append_character'. */
+/* #undef HAVE_RL_COMPLETION_APPEND_CHARACTER */
+
+/* Define to 1 if you have the `rl_completion_matches' function. */
+/* #undef HAVE_RL_COMPLETION_MATCHES */
+
+/* Define to 1 if you have the `rl_filename_completion_function' function. */
+/* #undef HAVE_RL_FILENAME_COMPLETION_FUNCTION */
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+/* #undef HAVE_SECURITY_PAM_APPL_H */
+
+/* Define to 1 if you have the `setproctitle' function. */
+/* #undef HAVE_SETPROCTITLE */
+
+/* Define to 1 if you have the `setsid' function. */
+#define HAVE_SETSID 1
+
+/* Define to 1 if you have the `shm_open' function. */
+#define HAVE_SHM_OPEN 1
+
+/* Define to 1 if you have the `sigprocmask' function. */
+#define HAVE_SIGPROCMASK 1
+
+/* Define to 1 if you have sigsetjmp(). */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if the system has the type `sig_atomic_t'. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+
+/* Define to 1 if you have spinlocks. */
+#define HAVE_SPINLOCKS 1
+
+/* Define to 1 if you have the `srandom' function. */
+#define HAVE_SRANDOM 1
+
+/* Define to 1 if you have the `SSL_get_current_compression' function. */
+/* #undef HAVE_SSL_GET_CURRENT_COMPRESSION */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+/* #undef HAVE_STRLCAT */
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if you have the `strtoq' function. */
+/* #undef HAVE_STRTOQ */
+
+/* Define to 1 if you have the `strtoull' function. */
+#define HAVE_STRTOULL 1
+
+/* Define to 1 if you have the `strtouq' function. */
+/* #undef HAVE_STRTOUQ */
+
+/* Define to 1 if the system has the type `struct addrinfo'. */
+#define HAVE_STRUCT_ADDRINFO 1
+
+/* Define to 1 if the system has the type `struct cmsgcred'. */
+/* #undef HAVE_STRUCT_CMSGCRED */
+
+/* Define to 1 if the system has the type `struct option'. */
+#define HAVE_STRUCT_OPTION 1
+
+/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */
+/* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */
+
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
+#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1
+
+/* Define to 1 if `ss_len' is a member of `struct sockaddr_storage'. */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */
+
+/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY */
+
+/* Define to 1 if `__ss_len' is a member of `struct sockaddr_storage'. */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN */
+
+/* Define to 1 if `tm_zone' is a member of `struct tm'. */
+#define HAVE_STRUCT_TM_TM_ZONE 1
+
+/* Define to 1 if you have the `symlink' function. */
+#define HAVE_SYMLINK 1
+
+/* Define to 1 if you have the `sync_file_range' function. */
+#define HAVE_SYNC_FILE_RANGE 1
+
+/* Define to 1 if you have the syslog interface. */
+#define HAVE_SYSLOG 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+#define HAVE_SYS_IPC_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/pstat.h> header file. */
+/* #undef HAVE_SYS_PSTAT_H */
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/sem.h> header file. */
+#define HAVE_SYS_SEM_H 1
+
+/* Define to 1 if you have the <sys/shm.h> header file. */
+#define HAVE_SYS_SHM_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/tas.h> header file. */
+/* #undef HAVE_SYS_TAS_H */
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/ucred.h> header file. */
+/* #undef HAVE_SYS_UCRED_H */
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+   `HAVE_STRUCT_TM_TM_ZONE' instead. */
+#define HAVE_TM_ZONE 1
+
+/* Define to 1 if you have the `towlower' function. */
+#define HAVE_TOWLOWER 1
+
+/* Define to 1 if you have the external array `tzname'. */
+#define HAVE_TZNAME 1
+
+/* Define to 1 if you have the <ucred.h> header file. */
+/* #undef HAVE_UCRED_H */
+
+/* Define to 1 if the system has the type `uint64'. */
+/* #undef HAVE_UINT64 */
+
+/* Define to 1 if the system has the type `uint8'. */
+/* #undef HAVE_UINT8 */
+
+/* Define to 1 if the system has the type `uintptr_t'. */
+#define HAVE_UINTPTR_T 1
+
+/* Define to 1 if the system has the type `union semun'. */
+/* #undef HAVE_UNION_SEMUN */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have unix sockets. */
+#define HAVE_UNIX_SOCKETS 1
+
+/* Define to 1 if you have the `unsetenv' function. */
+#define HAVE_UNSETENV 1
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+#define HAVE_UTIMES 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have BSD UUID support. */
+/* #undef HAVE_UUID_BSD */
+
+/* Define to 1 if you have E2FS UUID support. */
+/* #undef HAVE_UUID_E2FS */
+
+/* Define to 1 if you have the <uuid.h> header file. */
+/* #undef HAVE_UUID_H */
+
+/* Define to 1 if you have OSSP UUID support. */
+/* #undef HAVE_UUID_OSSP */
+
+/* Define to 1 if you have the <uuid/uuid.h> header file. */
+/* #undef HAVE_UUID_UUID_H */
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the `wcstombs' function. */
+#define HAVE_WCSTOMBS 1
+
+/* Define to 1 if you have the `wcstombs_l' function. */
+/* #undef HAVE_WCSTOMBS_L */
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define to 1 if you have the <winldap.h> header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if your compiler understands __builtin_constant_p. */
+#define HAVE__BUILTIN_CONSTANT_P 1
+
+/* Define to 1 if your compiler understands __builtin_types_compatible_p. */
+#define HAVE__BUILTIN_TYPES_COMPATIBLE_P 1
+
+/* Define to 1 if your compiler understands __builtin_unreachable. */
+#define HAVE__BUILTIN_UNREACHABLE 1
+
+/* Define to 1 if your compiler understands _Static_assert. */
+#define HAVE__STATIC_ASSERT 1
+
+/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
+#define HAVE__VA_ARGS 1
+
+/* Define to the appropriate snprintf format for 64-bit ints. */
+#define INT64_FORMAT "%lld"
+
+/* Define to 1 if `locale_t' requires <xlocale.h>. */
+/* #undef LOCALE_T_IN_XLOCALE */
+
+/* Define as the maximum alignment requirement of any C data type. */
+#define MAXIMUM_ALIGNOF 4
+
+/* Define bytes to use libc memset(). */
+#define MEMSET_LOOP_LIMIT 1024
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "pgsql-bugs@postgresql.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "PostgreSQL"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "PostgreSQL 9.4.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "postgresql"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "9.4.0"
+
+/* Define to the name of a signed 64-bit integer type. */
+#define PG_INT64_TYPE long long int
+
+/* Define to the name of the default PostgreSQL service principal in Kerberos
+   (GSSAPI). (--with-krb-srvnam=NAME) */
+#define PG_KRB_SRVNAM "postgres"
+
+/* PostgreSQL major version as a string */
+#define PG_MAJORVERSION "9.4"
+
+/* Define to 1 if "static inline" works without unwanted warnings from
+   compilations where static inline functions are defined but not called. */
+#define PG_USE_INLINE 1
+
+/* PostgreSQL version as a string */
+#define PG_VERSION "9.4.0"
+
+/* PostgreSQL version as a number */
+#define PG_VERSION_NUM 90400
+
+/* A string containing the version number, platform, and C compiler */
+#define PG_VERSION_STR "PostgreSQL 9.4.0 on i686-pc-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2, 32-bit"
+
+/* Define to 1 to allow profiling output to be saved separately for each
+   process. */
+/* #undef PROFILE_PID_DIR */
+
+/* Define to the necessary symbol if this constant uses a non-standard name on
+   your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* RELSEG_SIZE is the maximum number of blocks allowed in one disk file. Thus,
+   the maximum size of a single file is RELSEG_SIZE * BLCKSZ; relations bigger
+   than that are divided into multiple files. RELSEG_SIZE * BLCKSZ must be
+   less than your OS' limit on file size. This is often 2 GB or 4GB in a
+   32-bit operating system, unless you have large file support enabled. By
+   default, we make the limit 1 GB to avoid any possible integer-overflow
+   problems within the OS. A limit smaller than necessary only means we divide
+   a large relation into more chunks than necessary, so it seems best to err
+   in the direction of a small limit. A power-of-2 value is recommended to
+   save a few cycles in md.c, but is not absolutely required. Changing
+   RELSEG_SIZE requires an initdb. */
+#define RELSEG_SIZE 131072
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if strerror_r() returns a int. */
+/* #undef STRERROR_R_INT */
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define to the appropriate snprintf format for unsigned 64-bit ints. */
+#define UINT64_FORMAT "%llu"
+
+/* Define to 1 to build with assertion checks. (--enable-cassert) */
+/* #undef USE_ASSERT_CHECKING */
+
+/* Define to 1 to build with Bonjour support. (--with-bonjour) */
+/* #undef USE_BONJOUR */
+
+/* Define to 1 if you want float4 values to be passed by value.
+   (--enable-float4-byval) */
+#define USE_FLOAT4_BYVAL 1
+
+/* Define to 1 if you want float8, int8, etc values to be passed by value.
+   (--enable-float8-byval) */
+/* #undef USE_FLOAT8_BYVAL */
+
+/* Define to 1 if you want 64-bit integer timestamp and interval support.
+   (--enable-integer-datetimes) */
+#define USE_INTEGER_DATETIMES 1
+
+/* Define to 1 to build with LDAP support. (--with-ldap) */
+/* #undef USE_LDAP */
+
+/* Define to 1 to build with XML support. (--with-libxml) */
+/* #undef USE_LIBXML */
+
+/* Define to 1 to use XSLT support when building contrib/xml2.
+   (--with-libxslt) */
+/* #undef USE_LIBXSLT */
+
+/* Define to select named POSIX semaphores. */
+/* #undef USE_NAMED_POSIX_SEMAPHORES */
+
+/* Define to 1 to build with PAM support. (--with-pam) */
+/* #undef USE_PAM */
+
+/* Use replacement snprintf() functions. */
+/* #undef USE_REPL_SNPRINTF */
+
+/* Define to build with (Open)SSL support. (--with-openssl) */
+/* #undef USE_SSL */
+
+/* Define to select SysV-style semaphores. */
+#define USE_SYSV_SEMAPHORES 1
+
+/* Define to select SysV-style shared memory. */
+#define USE_SYSV_SHARED_MEMORY 1
+
+/* Define to select unnamed POSIX semaphores. */
+/* #undef USE_UNNAMED_POSIX_SEMAPHORES */
+
+/* Define to select Win32-style semaphores. */
+/* #undef USE_WIN32_SEMAPHORES */
+
+/* Define to select Win32-style shared memory. */
+/* #undef USE_WIN32_SHARED_MEMORY */
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* #  undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Size of a WAL file block. This need have no particular relation to BLCKSZ.
+   XLOG_BLCKSZ must be a power of 2, and if your system supports O_DIRECT I/O,
+   XLOG_BLCKSZ must be a multiple of the alignment requirement for direct-I/O
+   buffers, else direct I/O may fail. Changing XLOG_BLCKSZ requires an initdb.
+   */
+#define XLOG_BLCKSZ 8192
+
+/* XLOG_SEG_SIZE is the size of a single WAL file. This must be a power of 2
+   and larger than XLOG_BLCKSZ (preferably, a great deal larger than
+   XLOG_BLCKSZ). Changing XLOG_SEG_SIZE requires an initdb. */
+#define XLOG_SEG_SIZE (16 * 1024 * 1024)
+
+
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#define _FILE_OFFSET_BITS 64
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to the type of a signed integer type wide enough to hold a pointer,
+   if such a type exists, and if the system does not define it. */
+/* #undef intptr_t */
+
+/* Define to empty if the C compiler does not understand signed types. */
+/* #undef signed */
+
+/* Define to the type of an unsigned integer type wide enough to hold a
+   pointer, if such a type exists, and if the system does not define it. */
+/* #undef uintptr_t */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Platforms/pg_config-linux64.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,863 @@
+/* src/include/pg_config.h.  Generated from pg_config.h.in by configure.  */
+/* src/include/pg_config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define to the type of arg 1 of 'accept' */
+#define ACCEPT_TYPE_ARG1 int
+
+/* Define to the type of arg 2 of 'accept' */
+#define ACCEPT_TYPE_ARG2 struct sockaddr *
+
+/* Define to the type of arg 3 of 'accept' */
+#define ACCEPT_TYPE_ARG3 socklen_t
+
+/* Define to the return type of 'accept' */
+#define ACCEPT_TYPE_RETURN int
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* The normal alignment of `double', in bytes. */
+#define ALIGNOF_DOUBLE 8
+
+/* The normal alignment of `int', in bytes. */
+#define ALIGNOF_INT 4
+
+/* The normal alignment of `long', in bytes. */
+#define ALIGNOF_LONG 8
+
+/* The normal alignment of `long long int', in bytes. */
+/* #undef ALIGNOF_LONG_LONG_INT */
+
+/* The normal alignment of `short', in bytes. */
+#define ALIGNOF_SHORT 2
+
+/* Size of a disk block --- this also limits the size of a tuple. You can set
+   it bigger if you need bigger tuples (although TOAST should reduce the need
+   to have large tuples, since fields can be spread across multiple tuples).
+   BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
+   currently 2^15 (32768). This is determined by the 15-bit widths of the
+   lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
+   Changing BLCKSZ requires an initdb. */
+#define BLCKSZ 8192
+
+/* Define to the default TCP port number on which the server listens and to
+   which clients will try to connect. This can be overridden at run-time, but
+   it's convenient if your clients have the right default compiled in.
+   (--with-pgport=PORTNUM) */
+#define DEF_PGPORT 5432
+
+/* Define to the default TCP port number as a string constant. */
+#define DEF_PGPORT_STR "5432"
+
+/* Define to build with GSSAPI support. (--with-gssapi) */
+/* #undef ENABLE_GSS */
+
+/* Define to 1 if you want National Language Support. (--enable-nls) */
+/* #undef ENABLE_NLS */
+
+/* Define to 1 to build client libraries as thread-safe code.
+   (--enable-thread-safety) */
+#define ENABLE_THREAD_SAFETY 1
+
+/* Define to nothing if C supports flexible array members, and to 1 if it does
+   not. That way, with a declaration like `struct s { int n; double
+   d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99
+   compilers. When computing the size of such an object, don't use 'sizeof
+   (struct s)' as it overestimates the size. Use 'offsetof (struct s, d)'
+   instead. Don't use 'offsetof (struct s, d[0])', as this doesn't work with
+   MSVC and with C++ compilers. */
+#define FLEXIBLE_ARRAY_MEMBER /**/
+
+/* float4 values are passed by value if 'true', by reference if 'false' */
+#define FLOAT4PASSBYVAL true
+
+/* float8, int8, and related values are passed by value if 'true', by
+   reference if 'false' */
+#define FLOAT8PASSBYVAL true
+
+/* Define to 1 if getpwuid_r() takes a 5th argument. */
+#define GETPWUID_R_5ARG 1
+
+/* Define to 1 if gettimeofday() takes only 1 argument. */
+/* #undef GETTIMEOFDAY_1ARG */
+
+#ifdef GETTIMEOFDAY_1ARG
+# define gettimeofday(a,b) gettimeofday(a)
+#endif
+
+/* Define to 1 if you have the `append_history' function. */
+/* #undef HAVE_APPEND_HISTORY */
+
+/* Define to 1 if you have the `cbrt' function. */
+#define HAVE_CBRT 1
+
+/* Define to 1 if you have the `class' function. */
+/* #undef HAVE_CLASS */
+
+/* Define to 1 if you have the <crtdefs.h> header file. */
+/* #undef HAVE_CRTDEFS_H */
+
+/* Define to 1 if you have the `crypt' function. */
+#define HAVE_CRYPT 1
+
+/* Define to 1 if you have the <crypt.h> header file. */
+#define HAVE_CRYPT_H 1
+
+/* Define to 1 if you have the declaration of `fdatasync', and to 0 if you
+   don't. */
+#define HAVE_DECL_FDATASYNC 1
+
+/* Define to 1 if you have the declaration of `F_FULLFSYNC', and to 0 if you
+   don't. */
+#define HAVE_DECL_F_FULLFSYNC 0
+
+/* Define to 1 if you have the declaration of `posix_fadvise', and to 0 if you
+   don't. */
+#define HAVE_DECL_POSIX_FADVISE 1
+
+/* Define to 1 if you have the declaration of `snprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL_SNPRINTF 1
+
+/* Define to 1 if you have the declaration of `strlcat', and to 0 if you
+   don't. */
+#define HAVE_DECL_STRLCAT 0
+
+/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you
+   don't. */
+#define HAVE_DECL_STRLCPY 0
+
+/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you
+   don't. */
+#define HAVE_DECL_SYS_SIGLIST 1
+
+/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL_VSNPRINTF 1
+
+/* Define to 1 if you have the <dld.h> header file. */
+/* #undef HAVE_DLD_H */
+
+/* Define to 1 if you have the `dlopen' function. */
+#define HAVE_DLOPEN 1
+
+/* Define to 1 if you have the <editline/history.h> header file. */
+/* #undef HAVE_EDITLINE_HISTORY_H */
+
+/* Define to 1 if you have the <editline/readline.h> header file. */
+/* #undef HAVE_EDITLINE_READLINE_H */
+
+/* Define to 1 if you have the `fdatasync' function. */
+#define HAVE_FDATASYNC 1
+
+/* Define to 1 if you have the `fls' function. */
+/* #undef HAVE_FLS */
+
+/* Define to 1 if you have the `fpclass' function. */
+/* #undef HAVE_FPCLASS */
+
+/* Define to 1 if you have the `fp_class' function. */
+/* #undef HAVE_FP_CLASS */
+
+/* Define to 1 if you have the `fp_class_d' function. */
+/* #undef HAVE_FP_CLASS_D */
+
+/* Define to 1 if you have the <fp_class.h> header file. */
+/* #undef HAVE_FP_CLASS_H */
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#define HAVE_FSEEKO 1
+
+/* Define to 1 if your compiler understands __func__. */
+#define HAVE_FUNCNAME__FUNC 1
+
+/* Define to 1 if your compiler understands __FUNCTION__. */
+/* #undef HAVE_FUNCNAME__FUNCTION */
+
+/* Define to 1 if you have __sync_lock_test_and_set(int *) and friends. */
+#define HAVE_GCC_INT_ATOMICS 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `gethostbyname_r' function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* Define to 1 if you have the `getifaddrs' function. */
+#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the `getopt' function. */
+#define HAVE_GETOPT 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define to 1 if you have the `getpeereid' function. */
+/* #undef HAVE_GETPEEREID */
+
+/* Define to 1 if you have the `getpeerucred' function. */
+/* #undef HAVE_GETPEERUCRED */
+
+/* Define to 1 if you have the `getpwuid_r' function. */
+#define HAVE_GETPWUID_R 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the `getrusage' function. */
+#define HAVE_GETRUSAGE 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+/* #undef HAVE_GETTIMEOFDAY */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_H */
+
+/* Define to 1 if you have the <history.h> header file. */
+/* #undef HAVE_HISTORY_H */
+
+/* Define to 1 if you have the `history_truncate_file' function. */
+/* #undef HAVE_HISTORY_TRUNCATE_FILE */
+
+/* Define to 1 if you have the <ieeefp.h> header file. */
+/* #undef HAVE_IEEEFP_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#define HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the `inet_aton' function. */
+#define HAVE_INET_ATON 1
+
+/* Define to 1 if the system has the type `int64'. */
+/* #undef HAVE_INT64 */
+
+/* Define to 1 if the system has the type `int8'. */
+/* #undef HAVE_INT8 */
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#define HAVE_INTPTR_T 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the global variable 'int opterr'. */
+#define HAVE_INT_OPTERR 1
+
+/* Define to 1 if you have the global variable 'int optreset'. */
+/* #undef HAVE_INT_OPTRESET */
+
+/* Define to 1 if you have the global variable 'int timezone'. */
+#define HAVE_INT_TIMEZONE 1
+
+/* Define to 1 if you have support for IPv6. */
+#define HAVE_IPV6 1
+
+/* Define to 1 if you have isinf(). */
+#define HAVE_ISINF 1
+
+/* Define to 1 if you have the <langinfo.h> header file. */
+#define HAVE_LANGINFO_H 1
+
+/* Define to 1 if you have the <ldap.h> header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+/* #undef HAVE_LIBCRYPTO */
+
+/* Define to 1 if you have the `ldap' library (-lldap). */
+/* #undef HAVE_LIBLDAP */
+
+/* Define to 1 if you have the `ldap_r' library (-lldap_r). */
+/* #undef HAVE_LIBLDAP_R */
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Define to 1 if you have the `pam' library (-lpam). */
+/* #undef HAVE_LIBPAM */
+
+/* Define if you have a function readline library */
+/* #undef HAVE_LIBREADLINE */
+
+/* Define to 1 if you have the `selinux' library (-lselinux). */
+/* #undef HAVE_LIBSELINUX */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* Define to 1 if you have the `wldap32' library (-lwldap32). */
+/* #undef HAVE_LIBWLDAP32 */
+
+/* Define to 1 if you have the `xml2' library (-lxml2). */
+/* #undef HAVE_LIBXML2 */
+
+/* Define to 1 if you have the `xslt' library (-lxslt). */
+/* #undef HAVE_LIBXSLT */
+
+/* Define to 1 if you have the `z' library (-lz). */
+/* #undef HAVE_LIBZ */
+
+/* Define to 1 if constants of type 'long long int' should have the suffix LL.
+   */
+/* #undef HAVE_LL_CONSTANTS */
+
+/* Define to 1 if the system has the type `locale_t'. */
+#define HAVE_LOCALE_T 1
+
+/* Define to 1 if `long int' works and is 64 bits. */
+#define HAVE_LONG_INT_64 1
+
+/* Define to 1 if the system has the type `long long int'. */
+#define HAVE_LONG_LONG_INT 1
+
+/* Define to 1 if `long long int' works and is 64 bits. */
+/* #undef HAVE_LONG_LONG_INT_64 */
+
+/* Define to 1 if you have the `mbstowcs_l' function. */
+/* #undef HAVE_MBSTOWCS_L */
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if the system has the type `MINIDUMP_TYPE'. */
+/* #undef HAVE_MINIDUMP_TYPE */
+
+/* Define to 1 if you have the `mkdtemp' function. */
+#define HAVE_MKDTEMP 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if you have the <ossp/uuid.h> header file. */
+/* #undef HAVE_OSSP_UUID_H */
+
+/* Define to 1 if you have the <pam/pam_appl.h> header file. */
+/* #undef HAVE_PAM_PAM_APPL_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `posix_fadvise' function. */
+#define HAVE_POSIX_FADVISE 1
+
+/* Define to 1 if you have the POSIX signal interface. */
+#define HAVE_POSIX_SIGNALS 1
+
+/* Define to 1 if the assembler supports PPC's LWARX mutex hint bit. */
+/* #undef HAVE_PPC_LWARX_MUTEX_HINT */
+
+/* Define to 1 if you have the `pstat' function. */
+/* #undef HAVE_PSTAT */
+
+/* Define to 1 if the PS_STRINGS thing exists. */
+/* #undef HAVE_PS_STRINGS */
+
+/* Define if you have POSIX threads libraries and header files. */
+/* #undef HAVE_PTHREAD */
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `random' function. */
+#define HAVE_RANDOM 1
+
+/* Define to 1 if you have the <readline.h> header file. */
+/* #undef HAVE_READLINE_H */
+
+/* Define to 1 if you have the <readline/history.h> header file. */
+/* #undef HAVE_READLINE_HISTORY_H */
+
+/* Define to 1 if you have the <readline/readline.h> header file. */
+/* #undef HAVE_READLINE_READLINE_H */
+
+/* Define to 1 if you have the `readlink' function. */
+#define HAVE_READLINK 1
+
+/* Define to 1 if you have the `rint' function. */
+#define HAVE_RINT 1
+
+/* Define to 1 if you have the global variable
+   'rl_completion_append_character'. */
+/* #undef HAVE_RL_COMPLETION_APPEND_CHARACTER */
+
+/* Define to 1 if you have the `rl_completion_matches' function. */
+/* #undef HAVE_RL_COMPLETION_MATCHES */
+
+/* Define to 1 if you have the `rl_filename_completion_function' function. */
+/* #undef HAVE_RL_FILENAME_COMPLETION_FUNCTION */
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+/* #undef HAVE_SECURITY_PAM_APPL_H */
+
+/* Define to 1 if you have the `setproctitle' function. */
+/* #undef HAVE_SETPROCTITLE */
+
+/* Define to 1 if you have the `setsid' function. */
+#define HAVE_SETSID 1
+
+/* Define to 1 if you have the `shm_open' function. */
+#define HAVE_SHM_OPEN 1
+
+/* Define to 1 if you have the `sigprocmask' function. */
+#define HAVE_SIGPROCMASK 1
+
+/* Define to 1 if you have sigsetjmp(). */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if the system has the type `sig_atomic_t'. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+
+/* Define to 1 if you have spinlocks. */
+#define HAVE_SPINLOCKS 1
+
+/* Define to 1 if you have the `srandom' function. */
+#define HAVE_SRANDOM 1
+
+/* Define to 1 if you have the `SSL_get_current_compression' function. */
+/* #undef HAVE_SSL_GET_CURRENT_COMPRESSION */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+/* #undef HAVE_STRLCAT */
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if you have the `strtoq' function. */
+/* #undef HAVE_STRTOQ */
+
+/* Define to 1 if you have the `strtoull' function. */
+#define HAVE_STRTOULL 1
+
+/* Define to 1 if you have the `strtouq' function. */
+/* #undef HAVE_STRTOUQ */
+
+/* Define to 1 if the system has the type `struct addrinfo'. */
+#define HAVE_STRUCT_ADDRINFO 1
+
+/* Define to 1 if the system has the type `struct cmsgcred'. */
+/* #undef HAVE_STRUCT_CMSGCRED */
+
+/* Define to 1 if the system has the type `struct option'. */
+#define HAVE_STRUCT_OPTION 1
+
+/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */
+/* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */
+
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
+#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1
+
+/* Define to 1 if `ss_len' is a member of `struct sockaddr_storage'. */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */
+
+/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY */
+
+/* Define to 1 if `__ss_len' is a member of `struct sockaddr_storage'. */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN */
+
+/* Define to 1 if `tm_zone' is a member of `struct tm'. */
+#define HAVE_STRUCT_TM_TM_ZONE 1
+
+/* Define to 1 if you have the `symlink' function. */
+#define HAVE_SYMLINK 1
+
+/* Define to 1 if you have the `sync_file_range' function. */
+#define HAVE_SYNC_FILE_RANGE 1
+
+/* Define to 1 if you have the syslog interface. */
+#define HAVE_SYSLOG 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+#define HAVE_SYS_IPC_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/pstat.h> header file. */
+/* #undef HAVE_SYS_PSTAT_H */
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/sem.h> header file. */
+#define HAVE_SYS_SEM_H 1
+
+/* Define to 1 if you have the <sys/shm.h> header file. */
+#define HAVE_SYS_SHM_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/tas.h> header file. */
+/* #undef HAVE_SYS_TAS_H */
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/ucred.h> header file. */
+/* #undef HAVE_SYS_UCRED_H */
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+   `HAVE_STRUCT_TM_TM_ZONE' instead. */
+#define HAVE_TM_ZONE 1
+
+/* Define to 1 if you have the `towlower' function. */
+#define HAVE_TOWLOWER 1
+
+/* Define to 1 if you have the external array `tzname'. */
+#define HAVE_TZNAME 1
+
+/* Define to 1 if you have the <ucred.h> header file. */
+/* #undef HAVE_UCRED_H */
+
+/* Define to 1 if the system has the type `uint64'. */
+/* #undef HAVE_UINT64 */
+
+/* Define to 1 if the system has the type `uint8'. */
+/* #undef HAVE_UINT8 */
+
+/* Define to 1 if the system has the type `uintptr_t'. */
+#define HAVE_UINTPTR_T 1
+
+/* Define to 1 if the system has the type `union semun'. */
+/* #undef HAVE_UNION_SEMUN */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have unix sockets. */
+#define HAVE_UNIX_SOCKETS 1
+
+/* Define to 1 if you have the `unsetenv' function. */
+#define HAVE_UNSETENV 1
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+#define HAVE_UTIMES 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have BSD UUID support. */
+/* #undef HAVE_UUID_BSD */
+
+/* Define to 1 if you have E2FS UUID support. */
+/* #undef HAVE_UUID_E2FS */
+
+/* Define to 1 if you have the <uuid.h> header file. */
+/* #undef HAVE_UUID_H */
+
+/* Define to 1 if you have OSSP UUID support. */
+/* #undef HAVE_UUID_OSSP */
+
+/* Define to 1 if you have the <uuid/uuid.h> header file. */
+/* #undef HAVE_UUID_UUID_H */
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the `wcstombs' function. */
+#define HAVE_WCSTOMBS 1
+
+/* Define to 1 if you have the `wcstombs_l' function. */
+/* #undef HAVE_WCSTOMBS_L */
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define to 1 if you have the <winldap.h> header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if your compiler understands __builtin_constant_p. */
+#define HAVE__BUILTIN_CONSTANT_P 1
+
+/* Define to 1 if your compiler understands __builtin_types_compatible_p. */
+#define HAVE__BUILTIN_TYPES_COMPATIBLE_P 1
+
+/* Define to 1 if your compiler understands __builtin_unreachable. */
+#define HAVE__BUILTIN_UNREACHABLE 1
+
+/* Define to 1 if your compiler understands _Static_assert. */
+#define HAVE__STATIC_ASSERT 1
+
+/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
+#define HAVE__VA_ARGS 1
+
+/* Define to the appropriate snprintf format for 64-bit ints. */
+#define INT64_FORMAT "%ld"
+
+/* Define to 1 if `locale_t' requires <xlocale.h>. */
+/* #undef LOCALE_T_IN_XLOCALE */
+
+/* Define as the maximum alignment requirement of any C data type. */
+#define MAXIMUM_ALIGNOF 8
+
+/* Define bytes to use libc memset(). */
+#define MEMSET_LOOP_LIMIT 1024
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "pgsql-bugs@postgresql.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "PostgreSQL"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "PostgreSQL 9.4.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "postgresql"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "9.4.0"
+
+/* Define to the name of a signed 64-bit integer type. */
+#define PG_INT64_TYPE long int
+
+/* Define to the name of the default PostgreSQL service principal in Kerberos
+   (GSSAPI). (--with-krb-srvnam=NAME) */
+#define PG_KRB_SRVNAM "postgres"
+
+/* PostgreSQL major version as a string */
+#define PG_MAJORVERSION "9.4"
+
+/* Define to 1 if "static inline" works without unwanted warnings from
+   compilations where static inline functions are defined but not called. */
+#define PG_USE_INLINE 1
+
+/* PostgreSQL version as a string */
+#define PG_VERSION "9.4.0"
+
+/* PostgreSQL version as a number */
+#define PG_VERSION_NUM 90400
+
+/* A string containing the version number, platform, and C compiler */
+#define PG_VERSION_STR "PostgreSQL 9.4.0 on i686-pc-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2, 64-bit"
+
+/* Define to 1 to allow profiling output to be saved separately for each
+   process. */
+/* #undef PROFILE_PID_DIR */
+
+/* Define to the necessary symbol if this constant uses a non-standard name on
+   your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* RELSEG_SIZE is the maximum number of blocks allowed in one disk file. Thus,
+   the maximum size of a single file is RELSEG_SIZE * BLCKSZ; relations bigger
+   than that are divided into multiple files. RELSEG_SIZE * BLCKSZ must be
+   less than your OS' limit on file size. This is often 2 GB or 4GB in a
+   32-bit operating system, unless you have large file support enabled. By
+   default, we make the limit 1 GB to avoid any possible integer-overflow
+   problems within the OS. A limit smaller than necessary only means we divide
+   a large relation into more chunks than necessary, so it seems best to err
+   in the direction of a small limit. A power-of-2 value is recommended to
+   save a few cycles in md.c, but is not absolutely required. Changing
+   RELSEG_SIZE requires an initdb. */
+#define RELSEG_SIZE 131072
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if strerror_r() returns a int. */
+/* #undef STRERROR_R_INT */
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define to the appropriate snprintf format for unsigned 64-bit ints. */
+#define UINT64_FORMAT "%lu"
+
+/* Define to 1 to build with assertion checks. (--enable-cassert) */
+/* #undef USE_ASSERT_CHECKING */
+
+/* Define to 1 to build with Bonjour support. (--with-bonjour) */
+/* #undef USE_BONJOUR */
+
+/* Define to 1 if you want float4 values to be passed by value.
+   (--enable-float4-byval) */
+#define USE_FLOAT4_BYVAL 1
+
+/* Define to 1 if you want float8, int8, etc values to be passed by value.
+   (--enable-float8-byval) */
+#define USE_FLOAT8_BYVAL 1
+
+/* Define to 1 if you want 64-bit integer timestamp and interval support.
+   (--enable-integer-datetimes) */
+#define USE_INTEGER_DATETIMES 1
+
+/* Define to 1 to build with LDAP support. (--with-ldap) */
+/* #undef USE_LDAP */
+
+/* Define to 1 to build with XML support. (--with-libxml) */
+/* #undef USE_LIBXML */
+
+/* Define to 1 to use XSLT support when building contrib/xml2.
+   (--with-libxslt) */
+/* #undef USE_LIBXSLT */
+
+/* Define to select named POSIX semaphores. */
+/* #undef USE_NAMED_POSIX_SEMAPHORES */
+
+/* Define to 1 to build with PAM support. (--with-pam) */
+/* #undef USE_PAM */
+
+/* Use replacement snprintf() functions. */
+/* #undef USE_REPL_SNPRINTF */
+
+/* Define to build with (Open)SSL support. (--with-openssl) */
+/* #undef USE_SSL */
+
+/* Define to select SysV-style semaphores. */
+#define USE_SYSV_SEMAPHORES 1
+
+/* Define to select SysV-style shared memory. */
+#define USE_SYSV_SHARED_MEMORY 1
+
+/* Define to select unnamed POSIX semaphores. */
+/* #undef USE_UNNAMED_POSIX_SEMAPHORES */
+
+/* Define to select Win32-style semaphores. */
+/* #undef USE_WIN32_SEMAPHORES */
+
+/* Define to select Win32-style shared memory. */
+/* #undef USE_WIN32_SHARED_MEMORY */
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* #  undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Size of a WAL file block. This need have no particular relation to BLCKSZ.
+   XLOG_BLCKSZ must be a power of 2, and if your system supports O_DIRECT I/O,
+   XLOG_BLCKSZ must be a multiple of the alignment requirement for direct-I/O
+   buffers, else direct I/O may fail. Changing XLOG_BLCKSZ requires an initdb.
+   */
+#define XLOG_BLCKSZ 8192
+
+/* XLOG_SEG_SIZE is the size of a single WAL file. This must be a power of 2
+   and larger than XLOG_BLCKSZ (preferably, a great deal larger than
+   XLOG_BLCKSZ). Changing XLOG_SEG_SIZE requires an initdb. */
+#define XLOG_SEG_SIZE (16 * 1024 * 1024)
+
+
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to the type of a signed integer type wide enough to hold a pointer,
+   if such a type exists, and if the system does not define it. */
+/* #undef intptr_t */
+
+/* Define to empty if the C compiler does not understand signed types. */
+/* #undef signed */
+
+/* Define to the type of an unsigned integer type wide enough to hold a
+   pointer, if such a type exists, and if the system does not define it. */
+/* #undef uintptr_t */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Platforms/pg_config-windows32.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,863 @@
+/* src/include/pg_config.h.  Generated from pg_config.h.in by configure.  */
+/* src/include/pg_config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define to the type of arg 1 of 'accept' */
+#define ACCEPT_TYPE_ARG1 unsigned int
+
+/* Define to the type of arg 2 of 'accept' */
+#define ACCEPT_TYPE_ARG2 struct sockaddr *
+
+/* Define to the type of arg 3 of 'accept' */
+#define ACCEPT_TYPE_ARG3 int
+
+/* Define to the return type of 'accept' */
+#define ACCEPT_TYPE_RETURN unsigned int PASCAL
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* The normal alignment of `double', in bytes. */
+#define ALIGNOF_DOUBLE 8
+
+/* The normal alignment of `int', in bytes. */
+#define ALIGNOF_INT 4
+
+/* The normal alignment of `long', in bytes. */
+#define ALIGNOF_LONG 4
+
+/* The normal alignment of `long long int', in bytes. */
+#define ALIGNOF_LONG_LONG_INT 8
+
+/* The normal alignment of `short', in bytes. */
+#define ALIGNOF_SHORT 2
+
+/* Size of a disk block --- this also limits the size of a tuple. You can set
+   it bigger if you need bigger tuples (although TOAST should reduce the need
+   to have large tuples, since fields can be spread across multiple tuples).
+   BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
+   currently 2^15 (32768). This is determined by the 15-bit widths of the
+   lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
+   Changing BLCKSZ requires an initdb. */
+#define BLCKSZ 8192
+
+/* Define to the default TCP port number on which the server listens and to
+   which clients will try to connect. This can be overridden at run-time, but
+   it's convenient if your clients have the right default compiled in.
+   (--with-pgport=PORTNUM) */
+#define DEF_PGPORT 5432
+
+/* Define to the default TCP port number as a string constant. */
+#define DEF_PGPORT_STR "5432"
+
+/* Define to build with GSSAPI support. (--with-gssapi) */
+/* #undef ENABLE_GSS */
+
+/* Define to 1 if you want National Language Support. (--enable-nls) */
+/* #undef ENABLE_NLS */
+
+/* Define to 1 to build client libraries as thread-safe code.
+   (--enable-thread-safety) */
+#define ENABLE_THREAD_SAFETY 1
+
+/* Define to nothing if C supports flexible array members, and to 1 if it does
+   not. That way, with a declaration like `struct s { int n; double
+   d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99
+   compilers. When computing the size of such an object, don't use 'sizeof
+   (struct s)' as it overestimates the size. Use 'offsetof (struct s, d)'
+   instead. Don't use 'offsetof (struct s, d[0])', as this doesn't work with
+   MSVC and with C++ compilers. */
+#define FLEXIBLE_ARRAY_MEMBER /**/
+
+/* float4 values are passed by value if 'true', by reference if 'false' */
+#define FLOAT4PASSBYVAL true
+
+/* float8, int8, and related values are passed by value if 'true', by
+   reference if 'false' */
+#define FLOAT8PASSBYVAL false
+
+/* Define to 1 if getpwuid_r() takes a 5th argument. */
+/* #undef GETPWUID_R_5ARG */
+
+/* Define to 1 if gettimeofday() takes only 1 argument. */
+/* #undef GETTIMEOFDAY_1ARG */
+
+#ifdef GETTIMEOFDAY_1ARG
+# define gettimeofday(a,b) gettimeofday(a)
+#endif
+
+/* Define to 1 if you have the `append_history' function. */
+/* #undef HAVE_APPEND_HISTORY */
+
+/* Define to 1 if you have the `cbrt' function. */
+#define HAVE_CBRT 1
+
+/* Define to 1 if you have the `class' function. */
+/* #undef HAVE_CLASS */
+
+/* Define to 1 if you have the <crtdefs.h> header file. */
+#define HAVE_CRTDEFS_H 1
+
+/* Define to 1 if you have the `crypt' function. */
+/* #undef HAVE_CRYPT */
+
+/* Define to 1 if you have the <crypt.h> header file. */
+/* #undef HAVE_CRYPT_H */
+
+/* Define to 1 if you have the declaration of `fdatasync', and to 0 if you
+   don't. */
+#define HAVE_DECL_FDATASYNC 0
+
+/* Define to 1 if you have the declaration of `F_FULLFSYNC', and to 0 if you
+   don't. */
+#define HAVE_DECL_F_FULLFSYNC 0
+
+/* Define to 1 if you have the declaration of `posix_fadvise', and to 0 if you
+   don't. */
+#define HAVE_DECL_POSIX_FADVISE 0
+
+/* Define to 1 if you have the declaration of `snprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL_SNPRINTF 1
+
+/* Define to 1 if you have the declaration of `strlcat', and to 0 if you
+   don't. */
+#define HAVE_DECL_STRLCAT 0
+
+/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you
+   don't. */
+#define HAVE_DECL_STRLCPY 0
+
+/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you
+   don't. */
+#define HAVE_DECL_SYS_SIGLIST 0
+
+/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL_VSNPRINTF 1
+
+/* Define to 1 if you have the <dld.h> header file. */
+/* #undef HAVE_DLD_H */
+
+/* Define to 1 if you have the `dlopen' function. */
+/* #undef HAVE_DLOPEN */
+
+/* Define to 1 if you have the <editline/history.h> header file. */
+/* #undef HAVE_EDITLINE_HISTORY_H */
+
+/* Define to 1 if you have the <editline/readline.h> header file. */
+/* #undef HAVE_EDITLINE_READLINE_H */
+
+/* Define to 1 if you have the `fdatasync' function. */
+/* #undef HAVE_FDATASYNC */
+
+/* Define to 1 if you have the `fls' function. */
+/* #undef HAVE_FLS */
+
+/* Define to 1 if you have the `fpclass' function. */
+/* #undef HAVE_FPCLASS */
+
+/* Define to 1 if you have the `fp_class' function. */
+/* #undef HAVE_FP_CLASS */
+
+/* Define to 1 if you have the `fp_class_d' function. */
+/* #undef HAVE_FP_CLASS_D */
+
+/* Define to 1 if you have the <fp_class.h> header file. */
+/* #undef HAVE_FP_CLASS_H */
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#define HAVE_FSEEKO 1
+
+/* Define to 1 if your compiler understands __func__. */
+#define HAVE_FUNCNAME__FUNC 1
+
+/* Define to 1 if your compiler understands __FUNCTION__. */
+/* #undef HAVE_FUNCNAME__FUNCTION */
+
+/* Define to 1 if you have __sync_lock_test_and_set(int *) and friends. */
+#define HAVE_GCC_INT_ATOMICS 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+/* #undef HAVE_GETADDRINFO */
+
+/* Define to 1 if you have the `gethostbyname_r' function. */
+/* #undef HAVE_GETHOSTBYNAME_R */
+
+/* Define to 1 if you have the `getifaddrs' function. */
+/* #undef HAVE_GETIFADDRS */
+
+/* Define to 1 if you have the `getopt' function. */
+#define HAVE_GETOPT 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define to 1 if you have the `getpeereid' function. */
+#define HAVE_GETPEEREID 1
+
+/* Define to 1 if you have the `getpeerucred' function. */
+/* #undef HAVE_GETPEERUCRED */
+
+/* Define to 1 if you have the `getpwuid_r' function. */
+/* #undef HAVE_GETPWUID_R */
+
+/* Define to 1 if you have the `getrlimit' function. */
+/* #undef HAVE_GETRLIMIT */
+
+/* Define to 1 if you have the `getrusage' function. */
+/* #undef HAVE_GETRUSAGE */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_H */
+
+/* Define to 1 if you have the <history.h> header file. */
+/* #undef HAVE_HISTORY_H */
+
+/* Define to 1 if you have the `history_truncate_file' function. */
+/* #undef HAVE_HISTORY_TRUNCATE_FILE */
+
+/* Define to 1 if you have the <ieeefp.h> header file. */
+/* #undef HAVE_IEEEFP_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+/* #undef HAVE_IFADDRS_H */
+
+/* Define to 1 if you have the `inet_aton' function. */
+/* #undef HAVE_INET_ATON */
+
+/* Define to 1 if the system has the type `int64'. */
+/* #undef HAVE_INT64 */
+
+/* Define to 1 if the system has the type `int8'. */
+/* #undef HAVE_INT8 */
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#define HAVE_INTPTR_T 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the global variable 'int opterr'. */
+#define HAVE_INT_OPTERR 1
+
+/* Define to 1 if you have the global variable 'int optreset'. */
+#define HAVE_INT_OPTRESET 1
+
+/* Define to 1 if you have the global variable 'int timezone'. */
+#define HAVE_INT_TIMEZONE 1
+
+/* Define to 1 if you have support for IPv6. */
+#define HAVE_IPV6 1
+
+/* Define to 1 if you have isinf(). */
+#define HAVE_ISINF 1
+
+/* Define to 1 if you have the <langinfo.h> header file. */
+/* #undef HAVE_LANGINFO_H */
+
+/* Define to 1 if you have the <ldap.h> header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+/* #undef HAVE_LIBCRYPTO */
+
+/* Define to 1 if you have the `ldap' library (-lldap). */
+/* #undef HAVE_LIBLDAP */
+
+/* Define to 1 if you have the `ldap_r' library (-lldap_r). */
+/* #undef HAVE_LIBLDAP_R */
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Define to 1 if you have the `pam' library (-lpam). */
+/* #undef HAVE_LIBPAM */
+
+/* Define if you have a function readline library */
+/* #undef HAVE_LIBREADLINE */
+
+/* Define to 1 if you have the `selinux' library (-lselinux). */
+/* #undef HAVE_LIBSELINUX */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* Define to 1 if you have the `wldap32' library (-lwldap32). */
+/* #undef HAVE_LIBWLDAP32 */
+
+/* Define to 1 if you have the `xml2' library (-lxml2). */
+/* #undef HAVE_LIBXML2 */
+
+/* Define to 1 if you have the `xslt' library (-lxslt). */
+/* #undef HAVE_LIBXSLT */
+
+/* Define to 1 if you have the `z' library (-lz). */
+/* #undef HAVE_LIBZ */
+
+/* Define to 1 if constants of type 'long long int' should have the suffix LL.
+   */
+#define HAVE_LL_CONSTANTS 1
+
+/* Define to 1 if the system has the type `locale_t'. */
+/* #undef HAVE_LOCALE_T */
+
+/* Define to 1 if `long int' works and is 64 bits. */
+/* #undef HAVE_LONG_INT_64 */
+
+/* Define to 1 if the system has the type `long long int'. */
+#define HAVE_LONG_LONG_INT 1
+
+/* Define to 1 if `long long int' works and is 64 bits. */
+#define HAVE_LONG_LONG_INT_64 1
+
+/* Define to 1 if you have the `mbstowcs_l' function. */
+/* #undef HAVE_MBSTOWCS_L */
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if the system has the type `MINIDUMP_TYPE'. */
+#define HAVE_MINIDUMP_TYPE 1
+
+/* Define to 1 if you have the `mkdtemp' function. */
+/* #undef HAVE_MKDTEMP */
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+/* #undef HAVE_NETINET_TCP_H */
+
+/* Define to 1 if you have the <net/if.h> header file. */
+/* #undef HAVE_NET_IF_H */
+
+/* Define to 1 if you have the <ossp/uuid.h> header file. */
+/* #undef HAVE_OSSP_UUID_H */
+
+/* Define to 1 if you have the <pam/pam_appl.h> header file. */
+/* #undef HAVE_PAM_PAM_APPL_H */
+
+/* Define to 1 if you have the `poll' function. */
+/* #undef HAVE_POLL */
+
+/* Define to 1 if you have the <poll.h> header file. */
+/* #undef HAVE_POLL_H */
+
+/* Define to 1 if you have the `posix_fadvise' function. */
+/* #undef HAVE_POSIX_FADVISE */
+
+/* Define to 1 if you have the POSIX signal interface. */
+/* #undef HAVE_POSIX_SIGNALS */
+
+/* Define to 1 if the assembler supports PPC's LWARX mutex hint bit. */
+/* #undef HAVE_PPC_LWARX_MUTEX_HINT */
+
+/* Define to 1 if you have the `pstat' function. */
+/* #undef HAVE_PSTAT */
+
+/* Define to 1 if the PS_STRINGS thing exists. */
+/* #undef HAVE_PS_STRINGS */
+
+/* Define if you have POSIX threads libraries and header files. */
+/* #undef HAVE_PTHREAD */
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `random' function. */
+/* #undef HAVE_RANDOM */
+
+/* Define to 1 if you have the <readline.h> header file. */
+/* #undef HAVE_READLINE_H */
+
+/* Define to 1 if you have the <readline/history.h> header file. */
+/* #undef HAVE_READLINE_HISTORY_H */
+
+/* Define to 1 if you have the <readline/readline.h> header file. */
+/* #undef HAVE_READLINE_READLINE_H */
+
+/* Define to 1 if you have the `readlink' function. */
+/* #undef HAVE_READLINK */
+
+/* Define to 1 if you have the `rint' function. */
+#define HAVE_RINT 1
+
+/* Define to 1 if you have the global variable
+   'rl_completion_append_character'. */
+/* #undef HAVE_RL_COMPLETION_APPEND_CHARACTER */
+
+/* Define to 1 if you have the `rl_completion_matches' function. */
+/* #undef HAVE_RL_COMPLETION_MATCHES */
+
+/* Define to 1 if you have the `rl_filename_completion_function' function. */
+/* #undef HAVE_RL_FILENAME_COMPLETION_FUNCTION */
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+/* #undef HAVE_SECURITY_PAM_APPL_H */
+
+/* Define to 1 if you have the `setproctitle' function. */
+/* #undef HAVE_SETPROCTITLE */
+
+/* Define to 1 if you have the `setsid' function. */
+/* #undef HAVE_SETSID */
+
+/* Define to 1 if you have the `shm_open' function. */
+/* #undef HAVE_SHM_OPEN */
+
+/* Define to 1 if you have the `sigprocmask' function. */
+/* #undef HAVE_SIGPROCMASK */
+
+/* Define to 1 if you have sigsetjmp(). */
+/* #undef HAVE_SIGSETJMP */
+
+/* Define to 1 if the system has the type `sig_atomic_t'. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if you have the `snprintf' function. */
+/* #undef HAVE_SNPRINTF */
+
+/* Define to 1 if you have spinlocks. */
+#define HAVE_SPINLOCKS 1
+
+/* Define to 1 if you have the `srandom' function. */
+/* #undef HAVE_SRANDOM */
+
+/* Define to 1 if you have the `SSL_get_current_compression' function. */
+/* #undef HAVE_SSL_GET_CURRENT_COMPRESSION */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+/* #undef HAVE_STRERROR_R */
+
+/* Define to 1 if you have the <strings.h> header file. */
+/* #undef HAVE_STRINGS_H */
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+/* #undef HAVE_STRLCAT */
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if you have the `strtoq' function. */
+/* #undef HAVE_STRTOQ */
+
+/* Define to 1 if you have the `strtoull' function. */
+#define HAVE_STRTOULL 1
+
+/* Define to 1 if you have the `strtouq' function. */
+/* #undef HAVE_STRTOUQ */
+
+/* Define to 1 if the system has the type `struct addrinfo'. */
+#define HAVE_STRUCT_ADDRINFO 1
+
+/* Define to 1 if the system has the type `struct cmsgcred'. */
+/* #undef HAVE_STRUCT_CMSGCRED */
+
+/* Define to 1 if the system has the type `struct option'. */
+#define HAVE_STRUCT_OPTION 1
+
+/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */
+/* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */
+
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
+#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1
+
+/* Define to 1 if `ss_len' is a member of `struct sockaddr_storage'. */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */
+
+/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY */
+
+/* Define to 1 if `__ss_len' is a member of `struct sockaddr_storage'. */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN */
+
+/* Define to 1 if `tm_zone' is a member of `struct tm'. */
+/* #undef HAVE_STRUCT_TM_TM_ZONE */
+
+/* Define to 1 if you have the `symlink' function. */
+#define HAVE_SYMLINK 1
+
+/* Define to 1 if you have the `sync_file_range' function. */
+/* #undef HAVE_SYNC_FILE_RANGE */
+
+/* Define to 1 if you have the syslog interface. */
+/* #undef HAVE_SYSLOG */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+/* #undef HAVE_SYS_IOCTL_H */
+
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+/* #undef HAVE_SYS_IPC_H */
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+/* #undef HAVE_SYS_POLL_H */
+
+/* Define to 1 if you have the <sys/pstat.h> header file. */
+/* #undef HAVE_SYS_PSTAT_H */
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+/* #undef HAVE_SYS_RESOURCE_H */
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+/* #undef HAVE_SYS_SELECT_H */
+
+/* Define to 1 if you have the <sys/sem.h> header file. */
+/* #undef HAVE_SYS_SEM_H */
+
+/* Define to 1 if you have the <sys/shm.h> header file. */
+/* #undef HAVE_SYS_SHM_H */
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/tas.h> header file. */
+/* #undef HAVE_SYS_TAS_H */
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/ucred.h> header file. */
+/* #undef HAVE_SYS_UCRED_H */
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+/* #undef HAVE_SYS_UN_H */
+
+/* Define to 1 if you have the <termios.h> header file. */
+/* #undef HAVE_TERMIOS_H */
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+   `HAVE_STRUCT_TM_TM_ZONE' instead. */
+/* #undef HAVE_TM_ZONE */
+
+/* Define to 1 if you have the `towlower' function. */
+#define HAVE_TOWLOWER 1
+
+/* Define to 1 if you have the external array `tzname'. */
+/* #undef HAVE_TZNAME */
+
+/* Define to 1 if you have the <ucred.h> header file. */
+/* #undef HAVE_UCRED_H */
+
+/* Define to 1 if the system has the type `uint64'. */
+/* #undef HAVE_UINT64 */
+
+/* Define to 1 if the system has the type `uint8'. */
+/* #undef HAVE_UINT8 */
+
+/* Define to 1 if the system has the type `uintptr_t'. */
+#define HAVE_UINTPTR_T 1
+
+/* Define to 1 if the system has the type `union semun'. */
+/* #undef HAVE_UNION_SEMUN */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have unix sockets. */
+/* #undef HAVE_UNIX_SOCKETS */
+
+/* Define to 1 if you have the `unsetenv' function. */
+#define HAVE_UNSETENV 1
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+/* #undef HAVE_UTIMES */
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have BSD UUID support. */
+/* #undef HAVE_UUID_BSD */
+
+/* Define to 1 if you have E2FS UUID support. */
+/* #undef HAVE_UUID_E2FS */
+
+/* Define to 1 if you have the <uuid.h> header file. */
+/* #undef HAVE_UUID_H */
+
+/* Define to 1 if you have OSSP UUID support. */
+/* #undef HAVE_UUID_OSSP */
+
+/* Define to 1 if you have the <uuid/uuid.h> header file. */
+/* #undef HAVE_UUID_UUID_H */
+
+/* Define to 1 if you have the `vsnprintf' function. */
+/* #undef HAVE_VSNPRINTF */
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the `wcstombs' function. */
+#define HAVE_WCSTOMBS 1
+
+/* Define to 1 if you have the `wcstombs_l' function. */
+/* #undef HAVE_WCSTOMBS_L */
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define to 1 if you have the <winldap.h> header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if your compiler understands __builtin_constant_p. */
+#define HAVE__BUILTIN_CONSTANT_P 1
+
+/* Define to 1 if your compiler understands __builtin_types_compatible_p. */
+#define HAVE__BUILTIN_TYPES_COMPATIBLE_P 1
+
+/* Define to 1 if your compiler understands __builtin_unreachable. */
+#define HAVE__BUILTIN_UNREACHABLE 1
+
+/* Define to 1 if your compiler understands _Static_assert. */
+#define HAVE__STATIC_ASSERT 1
+
+/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
+#define HAVE__VA_ARGS 1
+
+/* Define to the appropriate snprintf format for 64-bit ints. */
+#define INT64_FORMAT "%lld"
+
+/* Define to 1 if `locale_t' requires <xlocale.h>. */
+/* #undef LOCALE_T_IN_XLOCALE */
+
+/* Define as the maximum alignment requirement of any C data type. */
+#define MAXIMUM_ALIGNOF 8
+
+/* Define bytes to use libc memset(). */
+#define MEMSET_LOOP_LIMIT 1024
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "pgsql-bugs@postgresql.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "PostgreSQL"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "PostgreSQL 9.4.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "postgresql"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "9.4.0"
+
+/* Define to the name of a signed 64-bit integer type. */
+#define PG_INT64_TYPE long long int
+
+/* Define to the name of the default PostgreSQL service principal in Kerberos
+   (GSSAPI). (--with-krb-srvnam=NAME) */
+#define PG_KRB_SRVNAM "postgres"
+
+/* PostgreSQL major version as a string */
+#define PG_MAJORVERSION "9.4"
+
+/* Define to 1 if "static inline" works without unwanted warnings from
+   compilations where static inline functions are defined but not called. */
+#define PG_USE_INLINE 1
+
+/* PostgreSQL version as a string */
+#define PG_VERSION "9.4.0"
+
+/* PostgreSQL version as a number */
+#define PG_VERSION_NUM 90400
+
+/* A string containing the version number, platform, and C compiler */
+#define PG_VERSION_STR "PostgreSQL 9.4.0 on i586-pc-mingw32msvc, compiled by i586-mingw32msvc-gcc (GCC) 4.6.3, 32-bit"
+
+/* Define to 1 to allow profiling output to be saved separately for each
+   process. */
+/* #undef PROFILE_PID_DIR */
+
+/* Define to the necessary symbol if this constant uses a non-standard name on
+   your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* RELSEG_SIZE is the maximum number of blocks allowed in one disk file. Thus,
+   the maximum size of a single file is RELSEG_SIZE * BLCKSZ; relations bigger
+   than that are divided into multiple files. RELSEG_SIZE * BLCKSZ must be
+   less than your OS' limit on file size. This is often 2 GB or 4GB in a
+   32-bit operating system, unless you have large file support enabled. By
+   default, we make the limit 1 GB to avoid any possible integer-overflow
+   problems within the OS. A limit smaller than necessary only means we divide
+   a large relation into more chunks than necessary, so it seems best to err
+   in the direction of a small limit. A power-of-2 value is recommended to
+   save a few cycles in md.c, but is not absolutely required. Changing
+   RELSEG_SIZE requires an initdb. */
+#define RELSEG_SIZE 131072
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 4
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if strerror_r() returns a int. */
+/* #undef STRERROR_R_INT */
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define to the appropriate snprintf format for unsigned 64-bit ints. */
+#define UINT64_FORMAT "%llu"
+
+/* Define to 1 to build with assertion checks. (--enable-cassert) */
+/* #undef USE_ASSERT_CHECKING */
+
+/* Define to 1 to build with Bonjour support. (--with-bonjour) */
+/* #undef USE_BONJOUR */
+
+/* Define to 1 if you want float4 values to be passed by value.
+   (--enable-float4-byval) */
+#define USE_FLOAT4_BYVAL 1
+
+/* Define to 1 if you want float8, int8, etc values to be passed by value.
+   (--enable-float8-byval) */
+/* #undef USE_FLOAT8_BYVAL */
+
+/* Define to 1 if you want 64-bit integer timestamp and interval support.
+   (--enable-integer-datetimes) */
+#define USE_INTEGER_DATETIMES 1
+
+/* Define to 1 to build with LDAP support. (--with-ldap) */
+/* #undef USE_LDAP */
+
+/* Define to 1 to build with XML support. (--with-libxml) */
+/* #undef USE_LIBXML */
+
+/* Define to 1 to use XSLT support when building contrib/xml2.
+   (--with-libxslt) */
+/* #undef USE_LIBXSLT */
+
+/* Define to select named POSIX semaphores. */
+/* #undef USE_NAMED_POSIX_SEMAPHORES */
+
+/* Define to 1 to build with PAM support. (--with-pam) */
+/* #undef USE_PAM */
+
+/* Use replacement snprintf() functions. */
+#define USE_REPL_SNPRINTF 1
+
+/* Define to build with (Open)SSL support. (--with-openssl) */
+/* #undef USE_SSL */
+
+/* Define to select SysV-style semaphores. */
+/* #undef USE_SYSV_SEMAPHORES */
+
+/* Define to select SysV-style shared memory. */
+/* #undef USE_SYSV_SHARED_MEMORY */
+
+/* Define to select unnamed POSIX semaphores. */
+/* #undef USE_UNNAMED_POSIX_SEMAPHORES */
+
+/* Define to select Win32-style semaphores. */
+#define USE_WIN32_SEMAPHORES 1
+
+/* Define to select Win32-style shared memory. */
+#define USE_WIN32_SHARED_MEMORY 1
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* #  undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Size of a WAL file block. This need have no particular relation to BLCKSZ.
+   XLOG_BLCKSZ must be a power of 2, and if your system supports O_DIRECT I/O,
+   XLOG_BLCKSZ must be a multiple of the alignment requirement for direct-I/O
+   buffers, else direct I/O may fail. Changing XLOG_BLCKSZ requires an initdb.
+   */
+#define XLOG_BLCKSZ 8192
+
+/* XLOG_SEG_SIZE is the size of a single WAL file. This must be a power of 2
+   and larger than XLOG_BLCKSZ (preferably, a great deal larger than
+   XLOG_BLCKSZ). Changing XLOG_SEG_SIZE requires an initdb. */
+#define XLOG_SEG_SIZE (16 * 1024 * 1024)
+
+
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to the type of a signed integer type wide enough to hold a pointer,
+   if such a type exists, and if the system does not define it. */
+/* #undef intptr_t */
+
+/* Define to empty if the C compiler does not understand signed types. */
+/* #undef signed */
+
+/* Define to the type of an unsigned integer type wide enough to hold a
+   pointer, if such a type exists, and if the system does not define it. */
+/* #undef uintptr_t */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Platforms/pg_config-windows64.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,863 @@
+/* src/include/pg_config.h.  Generated from pg_config.h.in by configure.  */
+/* src/include/pg_config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define to the type of arg 1 of 'accept' */
+#define ACCEPT_TYPE_ARG1 unsigned int
+
+/* Define to the type of arg 2 of 'accept' */
+#define ACCEPT_TYPE_ARG2 struct sockaddr *
+
+/* Define to the type of arg 3 of 'accept' */
+#define ACCEPT_TYPE_ARG3 int
+
+/* Define to the return type of 'accept' */
+#define ACCEPT_TYPE_RETURN unsigned int PASCAL
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* The normal alignment of `double', in bytes. */
+#define ALIGNOF_DOUBLE 8
+
+/* The normal alignment of `int', in bytes. */
+#define ALIGNOF_INT 4
+
+/* The normal alignment of `long', in bytes. */
+#define ALIGNOF_LONG 4
+
+/* The normal alignment of `long long int', in bytes. */
+#define ALIGNOF_LONG_LONG_INT 8
+
+/* The normal alignment of `short', in bytes. */
+#define ALIGNOF_SHORT 2
+
+/* Size of a disk block --- this also limits the size of a tuple. You can set
+   it bigger if you need bigger tuples (although TOAST should reduce the need
+   to have large tuples, since fields can be spread across multiple tuples).
+   BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
+   currently 2^15 (32768). This is determined by the 15-bit widths of the
+   lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
+   Changing BLCKSZ requires an initdb. */
+#define BLCKSZ 8192
+
+/* Define to the default TCP port number on which the server listens and to
+   which clients will try to connect. This can be overridden at run-time, but
+   it's convenient if your clients have the right default compiled in.
+   (--with-pgport=PORTNUM) */
+#define DEF_PGPORT 5432
+
+/* Define to the default TCP port number as a string constant. */
+#define DEF_PGPORT_STR "5432"
+
+/* Define to build with GSSAPI support. (--with-gssapi) */
+/* #undef ENABLE_GSS */
+
+/* Define to 1 if you want National Language Support. (--enable-nls) */
+/* #undef ENABLE_NLS */
+
+/* Define to 1 to build client libraries as thread-safe code.
+   (--enable-thread-safety) */
+#define ENABLE_THREAD_SAFETY 1
+
+/* Define to nothing if C supports flexible array members, and to 1 if it does
+   not. That way, with a declaration like `struct s { int n; double
+   d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99
+   compilers. When computing the size of such an object, don't use 'sizeof
+   (struct s)' as it overestimates the size. Use 'offsetof (struct s, d)'
+   instead. Don't use 'offsetof (struct s, d[0])', as this doesn't work with
+   MSVC and with C++ compilers. */
+#define FLEXIBLE_ARRAY_MEMBER /**/
+
+/* float4 values are passed by value if 'true', by reference if 'false' */
+#define FLOAT4PASSBYVAL true
+
+/* float8, int8, and related values are passed by value if 'true', by
+   reference if 'false' */
+#define FLOAT8PASSBYVAL false
+
+/* Define to 1 if getpwuid_r() takes a 5th argument. */
+/* #undef GETPWUID_R_5ARG */
+
+/* Define to 1 if gettimeofday() takes only 1 argument. */
+/* #undef GETTIMEOFDAY_1ARG */
+
+#ifdef GETTIMEOFDAY_1ARG
+# define gettimeofday(a,b) gettimeofday(a)
+#endif
+
+/* Define to 1 if you have the `append_history' function. */
+/* #undef HAVE_APPEND_HISTORY */
+
+/* Define to 1 if you have the `cbrt' function. */
+#define HAVE_CBRT 1
+
+/* Define to 1 if you have the `class' function. */
+/* #undef HAVE_CLASS */
+
+/* Define to 1 if you have the <crtdefs.h> header file. */
+#define HAVE_CRTDEFS_H 1
+
+/* Define to 1 if you have the `crypt' function. */
+/* #undef HAVE_CRYPT */
+
+/* Define to 1 if you have the <crypt.h> header file. */
+/* #undef HAVE_CRYPT_H */
+
+/* Define to 1 if you have the declaration of `fdatasync', and to 0 if you
+   don't. */
+#define HAVE_DECL_FDATASYNC 0
+
+/* Define to 1 if you have the declaration of `F_FULLFSYNC', and to 0 if you
+   don't. */
+#define HAVE_DECL_F_FULLFSYNC 0
+
+/* Define to 1 if you have the declaration of `posix_fadvise', and to 0 if you
+   don't. */
+#define HAVE_DECL_POSIX_FADVISE 0
+
+/* Define to 1 if you have the declaration of `snprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL_SNPRINTF 1
+
+/* Define to 1 if you have the declaration of `strlcat', and to 0 if you
+   don't. */
+#define HAVE_DECL_STRLCAT 0
+
+/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you
+   don't. */
+#define HAVE_DECL_STRLCPY 0
+
+/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you
+   don't. */
+#define HAVE_DECL_SYS_SIGLIST 0
+
+/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL_VSNPRINTF 1
+
+/* Define to 1 if you have the <dld.h> header file. */
+/* #undef HAVE_DLD_H */
+
+/* Define to 1 if you have the `dlopen' function. */
+/* #undef HAVE_DLOPEN */
+
+/* Define to 1 if you have the <editline/history.h> header file. */
+/* #undef HAVE_EDITLINE_HISTORY_H */
+
+/* Define to 1 if you have the <editline/readline.h> header file. */
+/* #undef HAVE_EDITLINE_READLINE_H */
+
+/* Define to 1 if you have the `fdatasync' function. */
+/* #undef HAVE_FDATASYNC */
+
+/* Define to 1 if you have the `fls' function. */
+/* #undef HAVE_FLS */
+
+/* Define to 1 if you have the `fpclass' function. */
+/* #undef HAVE_FPCLASS */
+
+/* Define to 1 if you have the `fp_class' function. */
+/* #undef HAVE_FP_CLASS */
+
+/* Define to 1 if you have the `fp_class_d' function. */
+/* #undef HAVE_FP_CLASS_D */
+
+/* Define to 1 if you have the <fp_class.h> header file. */
+/* #undef HAVE_FP_CLASS_H */
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#define HAVE_FSEEKO 1
+
+/* Define to 1 if your compiler understands __func__. */
+#define HAVE_FUNCNAME__FUNC 1
+
+/* Define to 1 if your compiler understands __FUNCTION__. */
+/* #undef HAVE_FUNCNAME__FUNCTION */
+
+/* Define to 1 if you have __sync_lock_test_and_set(int *) and friends. */
+#define HAVE_GCC_INT_ATOMICS 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+/* #undef HAVE_GETADDRINFO */
+
+/* Define to 1 if you have the `gethostbyname_r' function. */
+/* #undef HAVE_GETHOSTBYNAME_R */
+
+/* Define to 1 if you have the `getifaddrs' function. */
+/* #undef HAVE_GETIFADDRS */
+
+/* Define to 1 if you have the `getopt' function. */
+#define HAVE_GETOPT 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define to 1 if you have the `getpeereid' function. */
+#define HAVE_GETPEEREID 1
+
+/* Define to 1 if you have the `getpeerucred' function. */
+/* #undef HAVE_GETPEERUCRED */
+
+/* Define to 1 if you have the `getpwuid_r' function. */
+/* #undef HAVE_GETPWUID_R */
+
+/* Define to 1 if you have the `getrlimit' function. */
+/* #undef HAVE_GETRLIMIT */
+
+/* Define to 1 if you have the `getrusage' function. */
+/* #undef HAVE_GETRUSAGE */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_H */
+
+/* Define to 1 if you have the <history.h> header file. */
+/* #undef HAVE_HISTORY_H */
+
+/* Define to 1 if you have the `history_truncate_file' function. */
+/* #undef HAVE_HISTORY_TRUNCATE_FILE */
+
+/* Define to 1 if you have the <ieeefp.h> header file. */
+/* #undef HAVE_IEEEFP_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+/* #undef HAVE_IFADDRS_H */
+
+/* Define to 1 if you have the `inet_aton' function. */
+/* #undef HAVE_INET_ATON */
+
+/* Define to 1 if the system has the type `int64'. */
+/* #undef HAVE_INT64 */
+
+/* Define to 1 if the system has the type `int8'. */
+/* #undef HAVE_INT8 */
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#define HAVE_INTPTR_T 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the global variable 'int opterr'. */
+#define HAVE_INT_OPTERR 1
+
+/* Define to 1 if you have the global variable 'int optreset'. */
+#define HAVE_INT_OPTRESET 1
+
+/* Define to 1 if you have the global variable 'int timezone'. */
+#define HAVE_INT_TIMEZONE 1
+
+/* Define to 1 if you have support for IPv6. */
+#define HAVE_IPV6 1
+
+/* Define to 1 if you have isinf(). */
+#define HAVE_ISINF 1
+
+/* Define to 1 if you have the <langinfo.h> header file. */
+/* #undef HAVE_LANGINFO_H */
+
+/* Define to 1 if you have the <ldap.h> header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+/* #undef HAVE_LIBCRYPTO */
+
+/* Define to 1 if you have the `ldap' library (-lldap). */
+/* #undef HAVE_LIBLDAP */
+
+/* Define to 1 if you have the `ldap_r' library (-lldap_r). */
+/* #undef HAVE_LIBLDAP_R */
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Define to 1 if you have the `pam' library (-lpam). */
+/* #undef HAVE_LIBPAM */
+
+/* Define if you have a function readline library */
+/* #undef HAVE_LIBREADLINE */
+
+/* Define to 1 if you have the `selinux' library (-lselinux). */
+/* #undef HAVE_LIBSELINUX */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* Define to 1 if you have the `wldap32' library (-lwldap32). */
+/* #undef HAVE_LIBWLDAP32 */
+
+/* Define to 1 if you have the `xml2' library (-lxml2). */
+/* #undef HAVE_LIBXML2 */
+
+/* Define to 1 if you have the `xslt' library (-lxslt). */
+/* #undef HAVE_LIBXSLT */
+
+/* Define to 1 if you have the `z' library (-lz). */
+/* #undef HAVE_LIBZ */
+
+/* Define to 1 if constants of type 'long long int' should have the suffix LL.
+   */
+#define HAVE_LL_CONSTANTS 1
+
+/* Define to 1 if the system has the type `locale_t'. */
+/* #undef HAVE_LOCALE_T */
+
+/* Define to 1 if `long int' works and is 64 bits. */
+/* #undef HAVE_LONG_INT_64 */
+
+/* Define to 1 if the system has the type `long long int'. */
+#define HAVE_LONG_LONG_INT 1
+
+/* Define to 1 if `long long int' works and is 64 bits. */
+#define HAVE_LONG_LONG_INT_64 1
+
+/* Define to 1 if you have the `mbstowcs_l' function. */
+/* #undef HAVE_MBSTOWCS_L */
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if the system has the type `MINIDUMP_TYPE'. */
+#define HAVE_MINIDUMP_TYPE 1
+
+/* Define to 1 if you have the `mkdtemp' function. */
+/* #undef HAVE_MKDTEMP */
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+/* #undef HAVE_NETINET_TCP_H */
+
+/* Define to 1 if you have the <net/if.h> header file. */
+/* #undef HAVE_NET_IF_H */
+
+/* Define to 1 if you have the <ossp/uuid.h> header file. */
+/* #undef HAVE_OSSP_UUID_H */
+
+/* Define to 1 if you have the <pam/pam_appl.h> header file. */
+/* #undef HAVE_PAM_PAM_APPL_H */
+
+/* Define to 1 if you have the `poll' function. */
+/* #undef HAVE_POLL */
+
+/* Define to 1 if you have the <poll.h> header file. */
+/* #undef HAVE_POLL_H */
+
+/* Define to 1 if you have the `posix_fadvise' function. */
+/* #undef HAVE_POSIX_FADVISE */
+
+/* Define to 1 if you have the POSIX signal interface. */
+/* #undef HAVE_POSIX_SIGNALS */
+
+/* Define to 1 if the assembler supports PPC's LWARX mutex hint bit. */
+/* #undef HAVE_PPC_LWARX_MUTEX_HINT */
+
+/* Define to 1 if you have the `pstat' function. */
+/* #undef HAVE_PSTAT */
+
+/* Define to 1 if the PS_STRINGS thing exists. */
+/* #undef HAVE_PS_STRINGS */
+
+/* Define if you have POSIX threads libraries and header files. */
+/* #undef HAVE_PTHREAD */
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `random' function. */
+/* #undef HAVE_RANDOM */
+
+/* Define to 1 if you have the <readline.h> header file. */
+/* #undef HAVE_READLINE_H */
+
+/* Define to 1 if you have the <readline/history.h> header file. */
+/* #undef HAVE_READLINE_HISTORY_H */
+
+/* Define to 1 if you have the <readline/readline.h> header file. */
+/* #undef HAVE_READLINE_READLINE_H */
+
+/* Define to 1 if you have the `readlink' function. */
+/* #undef HAVE_READLINK */
+
+/* Define to 1 if you have the `rint' function. */
+#define HAVE_RINT 1
+
+/* Define to 1 if you have the global variable
+   'rl_completion_append_character'. */
+/* #undef HAVE_RL_COMPLETION_APPEND_CHARACTER */
+
+/* Define to 1 if you have the `rl_completion_matches' function. */
+/* #undef HAVE_RL_COMPLETION_MATCHES */
+
+/* Define to 1 if you have the `rl_filename_completion_function' function. */
+/* #undef HAVE_RL_FILENAME_COMPLETION_FUNCTION */
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+/* #undef HAVE_SECURITY_PAM_APPL_H */
+
+/* Define to 1 if you have the `setproctitle' function. */
+/* #undef HAVE_SETPROCTITLE */
+
+/* Define to 1 if you have the `setsid' function. */
+/* #undef HAVE_SETSID */
+
+/* Define to 1 if you have the `shm_open' function. */
+/* #undef HAVE_SHM_OPEN */
+
+/* Define to 1 if you have the `sigprocmask' function. */
+/* #undef HAVE_SIGPROCMASK */
+
+/* Define to 1 if you have sigsetjmp(). */
+/* #undef HAVE_SIGSETJMP */
+
+/* Define to 1 if the system has the type `sig_atomic_t'. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if you have the `snprintf' function. */
+/* #undef HAVE_SNPRINTF */
+
+/* Define to 1 if you have spinlocks. */
+#define HAVE_SPINLOCKS 1
+
+/* Define to 1 if you have the `srandom' function. */
+/* #undef HAVE_SRANDOM */
+
+/* Define to 1 if you have the `SSL_get_current_compression' function. */
+/* #undef HAVE_SSL_GET_CURRENT_COMPRESSION */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+/* #undef HAVE_STRERROR_R */
+
+/* Define to 1 if you have the <strings.h> header file. */
+/* #undef HAVE_STRINGS_H */
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+/* #undef HAVE_STRLCAT */
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if you have the `strtoq' function. */
+/* #undef HAVE_STRTOQ */
+
+/* Define to 1 if you have the `strtoull' function. */
+#define HAVE_STRTOULL 1
+
+/* Define to 1 if you have the `strtouq' function. */
+/* #undef HAVE_STRTOUQ */
+
+/* Define to 1 if the system has the type `struct addrinfo'. */
+#define HAVE_STRUCT_ADDRINFO 1
+
+/* Define to 1 if the system has the type `struct cmsgcred'. */
+/* #undef HAVE_STRUCT_CMSGCRED */
+
+/* Define to 1 if the system has the type `struct option'. */
+#define HAVE_STRUCT_OPTION 1
+
+/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */
+/* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */
+
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
+#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1
+
+/* Define to 1 if `ss_len' is a member of `struct sockaddr_storage'. */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */
+
+/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY */
+
+/* Define to 1 if `__ss_len' is a member of `struct sockaddr_storage'. */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN */
+
+/* Define to 1 if `tm_zone' is a member of `struct tm'. */
+/* #undef HAVE_STRUCT_TM_TM_ZONE */
+
+/* Define to 1 if you have the `symlink' function. */
+#define HAVE_SYMLINK 1
+
+/* Define to 1 if you have the `sync_file_range' function. */
+/* #undef HAVE_SYNC_FILE_RANGE */
+
+/* Define to 1 if you have the syslog interface. */
+/* #undef HAVE_SYSLOG */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+/* #undef HAVE_SYS_IOCTL_H */
+
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+/* #undef HAVE_SYS_IPC_H */
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+/* #undef HAVE_SYS_POLL_H */
+
+/* Define to 1 if you have the <sys/pstat.h> header file. */
+/* #undef HAVE_SYS_PSTAT_H */
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+/* #undef HAVE_SYS_RESOURCE_H */
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+/* #undef HAVE_SYS_SELECT_H */
+
+/* Define to 1 if you have the <sys/sem.h> header file. */
+/* #undef HAVE_SYS_SEM_H */
+
+/* Define to 1 if you have the <sys/shm.h> header file. */
+/* #undef HAVE_SYS_SHM_H */
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/tas.h> header file. */
+/* #undef HAVE_SYS_TAS_H */
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/ucred.h> header file. */
+/* #undef HAVE_SYS_UCRED_H */
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+/* #undef HAVE_SYS_UN_H */
+
+/* Define to 1 if you have the <termios.h> header file. */
+/* #undef HAVE_TERMIOS_H */
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+   `HAVE_STRUCT_TM_TM_ZONE' instead. */
+/* #undef HAVE_TM_ZONE */
+
+/* Define to 1 if you have the `towlower' function. */
+#define HAVE_TOWLOWER 1
+
+/* Define to 1 if you have the external array `tzname'. */
+/* #undef HAVE_TZNAME */
+
+/* Define to 1 if you have the <ucred.h> header file. */
+/* #undef HAVE_UCRED_H */
+
+/* Define to 1 if the system has the type `uint64'. */
+/* #undef HAVE_UINT64 */
+
+/* Define to 1 if the system has the type `uint8'. */
+/* #undef HAVE_UINT8 */
+
+/* Define to 1 if the system has the type `uintptr_t'. */
+#define HAVE_UINTPTR_T 1
+
+/* Define to 1 if the system has the type `union semun'. */
+/* #undef HAVE_UNION_SEMUN */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have unix sockets. */
+/* #undef HAVE_UNIX_SOCKETS */
+
+/* Define to 1 if you have the `unsetenv' function. */
+#define HAVE_UNSETENV 1
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+/* #undef HAVE_UTIMES */
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have BSD UUID support. */
+/* #undef HAVE_UUID_BSD */
+
+/* Define to 1 if you have E2FS UUID support. */
+/* #undef HAVE_UUID_E2FS */
+
+/* Define to 1 if you have the <uuid.h> header file. */
+/* #undef HAVE_UUID_H */
+
+/* Define to 1 if you have OSSP UUID support. */
+/* #undef HAVE_UUID_OSSP */
+
+/* Define to 1 if you have the <uuid/uuid.h> header file. */
+/* #undef HAVE_UUID_UUID_H */
+
+/* Define to 1 if you have the `vsnprintf' function. */
+/* #undef HAVE_VSNPRINTF */
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the `wcstombs' function. */
+#define HAVE_WCSTOMBS 1
+
+/* Define to 1 if you have the `wcstombs_l' function. */
+/* #undef HAVE_WCSTOMBS_L */
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define to 1 if you have the <winldap.h> header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if your compiler understands __builtin_constant_p. */
+#define HAVE__BUILTIN_CONSTANT_P 1
+
+/* Define to 1 if your compiler understands __builtin_types_compatible_p. */
+#define HAVE__BUILTIN_TYPES_COMPATIBLE_P 1
+
+/* Define to 1 if your compiler understands __builtin_unreachable. */
+#define HAVE__BUILTIN_UNREACHABLE 1
+
+/* Define to 1 if your compiler understands _Static_assert. */
+#define HAVE__STATIC_ASSERT 1
+
+/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
+#define HAVE__VA_ARGS 1
+
+/* Define to the appropriate snprintf format for 64-bit ints. */
+#define INT64_FORMAT "%lld"
+
+/* Define to 1 if `locale_t' requires <xlocale.h>. */
+/* #undef LOCALE_T_IN_XLOCALE */
+
+/* Define as the maximum alignment requirement of any C data type. */
+#define MAXIMUM_ALIGNOF 8
+
+/* Define bytes to use libc memset(). */
+#define MEMSET_LOOP_LIMIT 1024
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "pgsql-bugs@postgresql.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "PostgreSQL"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "PostgreSQL 9.4.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "postgresql"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "9.4.0"
+
+/* Define to the name of a signed 64-bit integer type. */
+#define PG_INT64_TYPE long long int
+
+/* Define to the name of the default PostgreSQL service principal in Kerberos
+   (GSSAPI). (--with-krb-srvnam=NAME) */
+#define PG_KRB_SRVNAM "postgres"
+
+/* PostgreSQL major version as a string */
+#define PG_MAJORVERSION "9.4"
+
+/* Define to 1 if "static inline" works without unwanted warnings from
+   compilations where static inline functions are defined but not called. */
+#define PG_USE_INLINE 1
+
+/* PostgreSQL version as a string */
+#define PG_VERSION "9.4.0"
+
+/* PostgreSQL version as a number */
+#define PG_VERSION_NUM 90400
+
+/* A string containing the version number, platform, and C compiler */
+#define PG_VERSION_STR "PostgreSQL 9.4.0 on i686-w64-mingw32, compiled by i686-w64-mingw32-gcc (GCC) 4.6.3, 32-bit"
+
+/* Define to 1 to allow profiling output to be saved separately for each
+   process. */
+/* #undef PROFILE_PID_DIR */
+
+/* Define to the necessary symbol if this constant uses a non-standard name on
+   your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* RELSEG_SIZE is the maximum number of blocks allowed in one disk file. Thus,
+   the maximum size of a single file is RELSEG_SIZE * BLCKSZ; relations bigger
+   than that are divided into multiple files. RELSEG_SIZE * BLCKSZ must be
+   less than your OS' limit on file size. This is often 2 GB or 4GB in a
+   32-bit operating system, unless you have large file support enabled. By
+   default, we make the limit 1 GB to avoid any possible integer-overflow
+   problems within the OS. A limit smaller than necessary only means we divide
+   a large relation into more chunks than necessary, so it seems best to err
+   in the direction of a small limit. A power-of-2 value is recommended to
+   save a few cycles in md.c, but is not absolutely required. Changing
+   RELSEG_SIZE requires an initdb. */
+#define RELSEG_SIZE 131072
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 4
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if strerror_r() returns a int. */
+/* #undef STRERROR_R_INT */
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define to the appropriate snprintf format for unsigned 64-bit ints. */
+#define UINT64_FORMAT "%llu"
+
+/* Define to 1 to build with assertion checks. (--enable-cassert) */
+/* #undef USE_ASSERT_CHECKING */
+
+/* Define to 1 to build with Bonjour support. (--with-bonjour) */
+/* #undef USE_BONJOUR */
+
+/* Define to 1 if you want float4 values to be passed by value.
+   (--enable-float4-byval) */
+#define USE_FLOAT4_BYVAL 1
+
+/* Define to 1 if you want float8, int8, etc values to be passed by value.
+   (--enable-float8-byval) */
+/* #undef USE_FLOAT8_BYVAL */
+
+/* Define to 1 if you want 64-bit integer timestamp and interval support.
+   (--enable-integer-datetimes) */
+#define USE_INTEGER_DATETIMES 1
+
+/* Define to 1 to build with LDAP support. (--with-ldap) */
+/* #undef USE_LDAP */
+
+/* Define to 1 to build with XML support. (--with-libxml) */
+/* #undef USE_LIBXML */
+
+/* Define to 1 to use XSLT support when building contrib/xml2.
+   (--with-libxslt) */
+/* #undef USE_LIBXSLT */
+
+/* Define to select named POSIX semaphores. */
+/* #undef USE_NAMED_POSIX_SEMAPHORES */
+
+/* Define to 1 to build with PAM support. (--with-pam) */
+/* #undef USE_PAM */
+
+/* Use replacement snprintf() functions. */
+#define USE_REPL_SNPRINTF 1
+
+/* Define to build with (Open)SSL support. (--with-openssl) */
+/* #undef USE_SSL */
+
+/* Define to select SysV-style semaphores. */
+/* #undef USE_SYSV_SEMAPHORES */
+
+/* Define to select SysV-style shared memory. */
+/* #undef USE_SYSV_SHARED_MEMORY */
+
+/* Define to select unnamed POSIX semaphores. */
+/* #undef USE_UNNAMED_POSIX_SEMAPHORES */
+
+/* Define to select Win32-style semaphores. */
+#define USE_WIN32_SEMAPHORES 1
+
+/* Define to select Win32-style shared memory. */
+#define USE_WIN32_SHARED_MEMORY 1
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* #  undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Size of a WAL file block. This need have no particular relation to BLCKSZ.
+   XLOG_BLCKSZ must be a power of 2, and if your system supports O_DIRECT I/O,
+   XLOG_BLCKSZ must be a multiple of the alignment requirement for direct-I/O
+   buffers, else direct I/O may fail. Changing XLOG_BLCKSZ requires an initdb.
+   */
+#define XLOG_BLCKSZ 8192
+
+/* XLOG_SEG_SIZE is the size of a single WAL file. This must be a power of 2
+   and larger than XLOG_BLCKSZ (preferably, a great deal larger than
+   XLOG_BLCKSZ). Changing XLOG_SEG_SIZE requires an initdb. */
+#define XLOG_SEG_SIZE (16 * 1024 * 1024)
+
+
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to the type of a signed integer type wide enough to hold a pointer,
+   if such a type exists, and if the system does not define it. */
+/* #undef intptr_t */
+
+/* Define to empty if the C compiler does not understand signed types. */
+/* #undef signed */
+
+/* Define to the type of an unsigned integer type wide enough to hold a
+   pointer, if such a type exists, and if the system does not define it. */
+/* #undef uintptr_t */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Platforms/pg_config_ext.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,8 @@
+/*
+ * src/include/pg_config_ext.h.in.  This is generated manually, not by
+ * autoheader, since we want to limit which symbols get defined here.
+ */
+
+/* Define to the name of a signed 64-bit integer type. */
+#include <stdint.h>
+#define PG_INT64_TYPE int64_t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/VersionScript.map	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,12 @@
+# This is a version-script for Orthanc plugins
+
+{
+global:
+  OrthancPluginInitialize;
+  OrthancPluginFinalize;
+  OrthancPluginGetName;
+  OrthancPluginGetVersion;
+
+local:
+  *;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/StoragePlugin/Plugin.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,155 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include <orthanc/OrthancCPlugin.h>
+
+#include "PostgreSQLStorageArea.h"
+#include "../Core/PostgreSQLException.h"
+#include "../Core/Configuration.h"
+
+
+static OrthancPluginContext* context_ = NULL;
+static OrthancPlugins::PostgreSQLStorageArea* storage_ = NULL;
+
+
+static int32_t StorageCreate(const char* uuid,
+                             const void* content,
+                             int64_t size,
+                             OrthancPluginContentType type)
+{
+  try
+  {
+    storage_->Create(uuid, content, static_cast<size_t>(size), type);
+    return 0;
+  }
+  catch (std::runtime_error& e)
+  {
+    OrthancPluginLogError(context_, e.what());
+    return -1;
+  }
+}
+
+
+static int32_t StorageRead(void** content,
+                           int64_t* size,
+                           const char* uuid,
+                           OrthancPluginContentType type)
+{
+  try
+  {
+    size_t tmp;
+    storage_->Read(*content, tmp, uuid, type);
+    *size = static_cast<int64_t>(tmp);
+    return 0;
+  }
+  catch (std::runtime_error& e)
+  {
+    OrthancPluginLogError(context_, e.what());
+    return -1;
+  }
+}
+
+
+static int32_t StorageRemove(const char* uuid,
+                             OrthancPluginContentType type)
+{
+  try
+  {
+    storage_->Remove(uuid, type);
+    return 0;
+  }
+  catch (std::runtime_error& e)
+  {
+    OrthancPluginLogError(context_, e.what());
+    return -1;
+  }
+}
+
+
+
+extern "C"
+{
+  ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)
+  {
+    context_ = context;
+    OrthancPluginLogWarning(context, "Using PostgreSQL storage area");
+
+    /* Check the version of the Orthanc core */
+    if (OrthancPluginCheckVersion(context_) == 0)
+    {
+      char info[1024];
+      sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin",
+              context_->orthancVersion,
+              ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER,
+              ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER,
+              ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER);
+      OrthancPluginLogError(context, info);
+      return -1;
+    }
+
+    bool allowUnlock = OrthancPlugins::IsFlagInCommandLineArguments(context_, FLAG_UNLOCK);
+
+    OrthancPluginSetDescription(context_, "Stores the files received by Orthanc into a PostgreSQL database.");
+
+    try
+    {
+      /* Create the connection to PostgreSQL */
+      std::auto_ptr<OrthancPlugins::PostgreSQLConnection> pg(OrthancPlugins::CreateConnection(context_));
+      pg->Open();
+    
+      /* Create the storage area back-end */
+      storage_ = new OrthancPlugins::PostgreSQLStorageArea(pg.release(), allowUnlock);
+
+      /* Register the storage area into Orthanc */
+      OrthancPluginRegisterStorageArea(context, StorageCreate, StorageRead, StorageRemove);
+    }
+    catch (std::runtime_error& e)
+    {
+      OrthancPluginLogError(context_, e.what());
+      return -1;
+    }
+
+    return 0;
+  }
+
+
+  ORTHANC_PLUGINS_API void OrthancPluginFinalize()
+  {
+    OrthancPluginLogWarning(context_, "Storage plugin is finalizing");
+
+    if (storage_ != NULL)
+    {
+      delete storage_;
+      storage_ = NULL;
+    }
+  }
+
+
+  ORTHANC_PLUGINS_API const char* OrthancPluginGetName()
+  {
+    return "postgresql-storage";
+  }
+
+
+  ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion()
+  {
+    return "1.0";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/StoragePlugin/PostgreSQLStorageArea.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,169 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "PostgreSQLStorageArea.h"
+
+#include "../Core/PostgreSQLTransaction.h"
+#include "../Core/PostgreSQLResult.h"
+#include "../Core/PostgreSQLException.h"
+#include "../Core/Configuration.h"
+
+namespace OrthancPlugins
+{  
+  PostgreSQLStorageArea::PostgreSQLStorageArea(PostgreSQLConnection* db,
+                                               bool allowUnlock) : 
+    db_(db),
+    globalProperties_(*db, GlobalProperty_StorageLock)
+  {
+    globalProperties_.Lock(allowUnlock);
+
+    Prepare();
+  }
+
+
+  void PostgreSQLStorageArea::Prepare()
+  {
+    PostgreSQLTransaction transaction(*db_);
+
+    db_->Execute("CREATE TABLE IF NOT EXISTS StorageArea("
+                 "uuid VARCHAR NOT NULL PRIMARY KEY,"
+                 "content OID NOT NULL,"
+                 "type INTEGER NOT NULL)");
+
+    // Automatically remove the large objects associated with the table
+    db_->Execute("CREATE OR REPLACE RULE StorageAreaDelete AS ON DELETE TO StorageArea DO SELECT lo_unlink(old.content);");
+
+    create_.reset(new PostgreSQLStatement(*db_, "INSERT INTO StorageArea VALUES ($1,$2,$3)"));
+    create_->DeclareInputString(0);
+    create_->DeclareInputLargeObject(1);
+    create_->DeclareInputInteger(2);
+
+    read_.reset(new PostgreSQLStatement(*db_, "SELECT content FROM StorageArea WHERE uuid=$1 AND type=$2"));
+    read_->DeclareInputString(0);
+    read_->DeclareInputInteger(1);
+
+    remove_.reset(new PostgreSQLStatement(*db_, "DELETE FROM StorageArea WHERE uuid=$1 AND type=$2"));
+    remove_->DeclareInputString(0);
+    remove_->DeclareInputInteger(1);
+
+    transaction.Commit();
+  }
+
+
+  PostgreSQLStorageArea::~PostgreSQLStorageArea()
+  {
+    globalProperties_.Unlock();
+  }
+
+
+  void  PostgreSQLStorageArea::Create(const std::string& uuid,
+                                      const void* content,
+                                      size_t size,
+                                      OrthancPluginContentType type)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+    PostgreSQLTransaction transaction(*db_);
+
+    PostgreSQLLargeObject obj(*db_, content, size);
+    create_->BindString(0, uuid);
+    create_->BindLargeObject(1, obj);    
+    create_->BindInteger(2, static_cast<int>(type));    
+    create_->Run();
+
+    transaction.Commit();
+  }
+
+
+  void  PostgreSQLStorageArea::Read(void*& content,
+                                    size_t& size,
+                                    const std::string& uuid,
+                                    OrthancPluginContentType type) 
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+    PostgreSQLTransaction transaction(*db_);
+
+    read_->BindString(0, uuid);
+    read_->BindInteger(1, static_cast<int>(type));
+    PostgreSQLResult result(*read_);
+
+    if (result.IsDone())
+    {
+      throw PostgreSQLException();
+    }
+
+    result.GetLargeObject(content, size, 0);
+
+    transaction.Commit();
+  }
+
+
+  void  PostgreSQLStorageArea::Read(std::string& content,
+                                    const std::string& uuid,
+                                    OrthancPluginContentType type) 
+  {
+    void* tmp = NULL; 
+    size_t size;
+    Read(tmp, size, uuid, type);
+
+    try
+    {
+      content.resize(size);
+    }
+    catch (std::bad_alloc&)
+    {
+      free(tmp);
+      throw;
+    }
+
+    if (size != 0)
+    {
+      assert(tmp != NULL);
+      memcpy(&content[0], tmp, size);
+    }
+
+    free(tmp);
+  }
+
+
+  void  PostgreSQLStorageArea::Remove(const std::string& uuid,
+                                      OrthancPluginContentType type)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+    PostgreSQLTransaction transaction(*db_);
+
+    remove_->BindString(0, uuid);
+    remove_->BindInteger(1, static_cast<int>(type));
+    remove_->Run();
+
+    transaction.Commit();
+  }
+
+
+  void PostgreSQLStorageArea::Clear()
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+    PostgreSQLTransaction transaction(*db_);
+
+    db_->Execute("DELETE FROM StorageArea");
+
+    transaction.Commit();
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/StoragePlugin/PostgreSQLStorageArea.h	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,77 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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 "../Core/GlobalProperties.h"
+#include "../Core/PostgreSQLConnection.h"
+#include "../Core/PostgreSQLStatement.h"
+
+#include <orthanc/OrthancCPlugin.h>
+#include <memory>
+#include <boost/thread/mutex.hpp>
+
+namespace OrthancPlugins
+{  
+  class PostgreSQLStorageArea
+  {
+  private:
+    std::auto_ptr<PostgreSQLConnection>  db_;
+    GlobalProperties globalProperties_;
+
+    boost::mutex mutex_;
+    std::auto_ptr<PostgreSQLStatement>  create_;
+    std::auto_ptr<PostgreSQLStatement>  read_;
+    std::auto_ptr<PostgreSQLStatement>  remove_;
+
+    void Prepare();
+
+  public:
+    PostgreSQLStorageArea(PostgreSQLConnection* db,
+                          bool allowUnlock);   // Takes the ownership
+
+    ~PostgreSQLStorageArea();
+
+    void Create(const std::string& uuid,
+                const void* content,
+                size_t size,
+                OrthancPluginContentType type);
+
+    void Read(std::string& content,
+              const std::string& uuid,
+              OrthancPluginContentType type);
+
+    void Read(void*& content,
+              size_t& size,
+              const std::string& uuid,
+              OrthancPluginContentType type);
+
+    void Remove(const std::string& uuid,
+                OrthancPluginContentType type);
+
+    void Clear();
+
+    // For unit tests only (not thread-safe)!
+    PostgreSQLConnection& GetConnection()
+    {
+      return *db_;
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UnitTestsSources/PostgreSQLTests.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,352 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include <gtest/gtest.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include "../Core/PostgreSQLTransaction.h"
+#include "../Core/PostgreSQLResult.h"
+#include "../Core/PostgreSQLLargeObject.h"
+#include "../Core/PostgreSQLException.h"
+#include "../StoragePlugin/PostgreSQLStorageArea.h"
+
+using namespace OrthancPlugins;
+
+extern PostgreSQLConnection* CreateTestConnection();
+
+
+static int64_t CountLargeObjects(PostgreSQLConnection& db)
+{
+  // Count the number of large objects in the DB
+  PostgreSQLTransaction t(db);
+  PostgreSQLStatement s(db, "SELECT COUNT(*) FROM pg_catalog.pg_largeobject");
+  PostgreSQLResult r(s);
+  return r.GetInteger64(0);
+}
+
+
+TEST(PostgreSQL, Basic)
+{
+  std::auto_ptr<PostgreSQLConnection> pg(CreateTestConnection());
+
+  ASSERT_FALSE(pg->DoesTableExist("Test"));
+  pg->Execute("CREATE TABLE Test(name INTEGER, value BIGINT)");
+  ASSERT_TRUE(pg->DoesTableExist("Test"));
+
+  PostgreSQLStatement s(*pg, "INSERT INTO Test VALUES ($1,$2)");
+  s.DeclareInputInteger(0);
+  s.DeclareInputInteger64(1);
+
+  s.BindInteger(0, 43);
+  s.BindNull(0);
+  s.BindInteger(0, 42);
+  s.BindInteger64(1, -4242);
+  s.Run();
+
+  s.BindInteger(0, 43);
+  s.BindNull(1);
+  s.Run();
+
+  s.BindNull(0);
+  s.BindInteger64(1, 4444);
+  s.Run();
+
+  {
+    PostgreSQLStatement t(*pg, "SELECT name, value FROM Test ORDER BY name");
+    PostgreSQLResult r(t);
+
+    ASSERT_FALSE(r.IsDone());
+    ASSERT_FALSE(r.IsNull(0)); ASSERT_EQ(42, r.GetInteger(0));
+    ASSERT_FALSE(r.IsNull(1)); ASSERT_EQ(-4242, r.GetInteger64(1));
+
+    r.Step();
+    ASSERT_FALSE(r.IsDone());
+    ASSERT_FALSE(r.IsNull(0)); ASSERT_EQ(43, r.GetInteger(0));
+    ASSERT_TRUE(r.IsNull(1));
+
+    r.Step();
+    ASSERT_FALSE(r.IsDone());
+    ASSERT_TRUE(r.IsNull(0));
+    ASSERT_FALSE(r.IsNull(1)); ASSERT_EQ(4444, r.GetInteger64(1));
+
+    r.Step();
+    ASSERT_TRUE(r.IsDone());
+  }
+
+  {
+    PostgreSQLStatement t(*pg, "SELECT name, value FROM Test WHERE name=$1");
+    t.DeclareInputInteger(0);
+
+    {
+      t.BindInteger(0, 42);
+      PostgreSQLResult r(t);
+      ASSERT_FALSE(r.IsDone());
+      ASSERT_FALSE(r.IsNull(0)); ASSERT_EQ(42, r.GetInteger(0));
+      ASSERT_FALSE(r.IsNull(1)); ASSERT_EQ(-4242, r.GetInteger64(1));
+
+      r.Step();
+      ASSERT_TRUE(r.IsDone());
+    }
+
+    {
+      t.BindInteger(0, 40);
+      PostgreSQLResult r(t);
+      ASSERT_TRUE(r.IsDone());
+    }
+  }
+  
+}
+
+
+TEST(PostgreSQL, String)
+{
+  std::auto_ptr<PostgreSQLConnection> pg(CreateTestConnection());
+
+  pg->Execute("CREATE TABLE Test(name INTEGER, value VARCHAR(40))");
+
+  PostgreSQLStatement s(*pg, "INSERT INTO Test VALUES ($1,$2)");
+  s.DeclareInputInteger(0);
+  s.DeclareInputString(1);
+
+  s.BindInteger(0, 42);
+  s.BindString(1, "Hello");
+  s.Run();
+
+  s.BindInteger(0, 43);
+  s.BindNull(1);
+  s.Run();
+
+  s.BindNull(0);
+  s.BindString(1, "");
+  s.Run();
+
+  {
+    PostgreSQLStatement t(*pg, "SELECT name, value FROM Test ORDER BY name");
+    PostgreSQLResult r(t);
+
+    ASSERT_FALSE(r.IsDone());
+    ASSERT_FALSE(r.IsNull(0)); ASSERT_EQ(42, r.GetInteger(0));
+    ASSERT_FALSE(r.IsNull(1)); ASSERT_EQ("Hello", r.GetString(1));
+
+    r.Step();
+    ASSERT_FALSE(r.IsDone());
+    ASSERT_FALSE(r.IsNull(0)); ASSERT_EQ(43, r.GetInteger(0));
+    ASSERT_TRUE(r.IsNull(1));
+
+    r.Step();
+    ASSERT_FALSE(r.IsDone());
+    ASSERT_TRUE(r.IsNull(0));
+    ASSERT_FALSE(r.IsNull(1)); ASSERT_EQ("", r.GetString(1));
+
+    r.Step();
+    ASSERT_TRUE(r.IsDone());
+  }
+}
+
+
+TEST(PostgreSQL, Transaction)
+{
+  std::auto_ptr<PostgreSQLConnection> pg(CreateTestConnection());
+
+  pg->Execute("CREATE TABLE Test(name INTEGER, value INTEGER)");
+
+  {
+    PostgreSQLStatement s(*pg, "INSERT INTO Test VALUES ($1,$2)");
+    s.DeclareInputInteger(0);
+    s.DeclareInputInteger(1);
+    s.BindInteger(0, 42);
+    s.BindInteger(1, 4242);
+    s.Run();
+
+    {
+      PostgreSQLTransaction t(*pg);
+      s.BindInteger(0, 43);
+      s.BindInteger(1, 4343);
+      s.Run();
+      s.BindInteger(0, 44);
+      s.BindInteger(1, 4444);
+      s.Run();
+
+      PostgreSQLStatement u(*pg, "SELECT COUNT(*) FROM Test");
+      PostgreSQLResult r(u);
+      ASSERT_EQ(3, r.GetInteger64(0));
+
+      // No commit
+    }
+
+    {
+      PostgreSQLStatement u(*pg, "SELECT COUNT(*) FROM Test");
+      PostgreSQLResult r(u);
+      ASSERT_EQ(1, r.GetInteger64(0));  // Just "1" because of implicit rollback
+    }
+    
+    {
+      PostgreSQLTransaction t(*pg);
+      s.BindInteger(0, 43);
+      s.BindInteger(1, 4343);
+      s.Run();
+      s.BindInteger(0, 44);
+      s.BindInteger(1, 4444);
+      s.Run();
+
+      {
+        PostgreSQLStatement u(*pg, "SELECT COUNT(*) FROM Test");
+        PostgreSQLResult r(u);
+        ASSERT_EQ(3, r.GetInteger64(0));
+
+        t.Commit();
+        ASSERT_THROW(t.Rollback(), PostgreSQLException);
+        ASSERT_THROW(t.Commit(), PostgreSQLException);
+      }
+    }
+
+    {
+      PostgreSQLStatement u(*pg, "SELECT COUNT(*) FROM Test");
+      PostgreSQLResult r(u);
+      ASSERT_EQ(3, r.GetInteger64(0));
+    }
+  }
+}
+
+
+
+
+
+TEST(PostgreSQL, LargeObject)
+{
+  std::auto_ptr<PostgreSQLConnection> pg(CreateTestConnection());
+  ASSERT_EQ(0, CountLargeObjects(*pg));
+
+  pg->Execute("CREATE TABLE Test(name VARCHAR, value OID)");
+
+  // Automatically remove the large objects associated with the table
+  pg->Execute("CREATE RULE TestDelete AS ON DELETE TO Test DO SELECT lo_unlink(old.value);");
+
+  {
+    PostgreSQLStatement s(*pg, "INSERT INTO Test VALUES ($1,$2)");
+    s.DeclareInputString(0);
+    s.DeclareInputLargeObject(1);
+    
+    for (int i = 0; i < 10; i++)
+    {
+      PostgreSQLTransaction t(*pg);
+
+      std::string value = "Value " + boost::lexical_cast<std::string>(i * 2);
+      PostgreSQLLargeObject obj(*pg, value);
+
+      s.BindString(0, "Index " + boost::lexical_cast<std::string>(i));
+      s.BindLargeObject(1, obj);
+      s.Run();
+
+      std::string tmp;
+      PostgreSQLLargeObject::Read(tmp, *pg, obj.GetOid());
+      ASSERT_EQ(value, tmp);
+
+      t.Commit();
+    }
+  }
+
+
+  ASSERT_EQ(10, CountLargeObjects(*pg));
+
+  {
+    PostgreSQLTransaction t(*pg);
+    PostgreSQLStatement s(*pg, "SELECT * FROM Test ORDER BY name DESC");
+    PostgreSQLResult r(s);
+
+    ASSERT_FALSE(r.IsDone());
+
+    ASSERT_FALSE(r.IsNull(0));
+    ASSERT_EQ("Index 9", r.GetString(0));
+
+    std::string data;
+    r.GetLargeObject(data, 1);
+    ASSERT_EQ("Value 18", data);    
+
+    r.Step();
+    ASSERT_FALSE(r.IsDone());
+
+    //ASSERT_TRUE(r.IsString(0));
+  }
+
+
+  {
+    PostgreSQLTransaction t(*pg);
+    PostgreSQLStatement s(*pg, "DELETE FROM Test WHERE name='Index 9'");
+    s.Run();
+    t.Commit();
+  }
+
+
+  {
+    // Count the number of items in the DB
+    PostgreSQLTransaction t(*pg);
+    PostgreSQLStatement s(*pg, "SELECT COUNT(*) FROM Test");
+    PostgreSQLResult r(s);
+    ASSERT_EQ(9, r.GetInteger64(0));
+  }
+
+  ASSERT_EQ(9, CountLargeObjects(*pg));
+}
+
+
+
+TEST(PostgreSQL, StorageArea)
+{
+  std::auto_ptr<PostgreSQLConnection> pg(CreateTestConnection());
+  PostgreSQLStorageArea s(pg.release(), true);
+
+  ASSERT_EQ(0, CountLargeObjects(s.GetConnection()));
+  
+  for (int i = 0; i < 10; i++)
+  {
+    std::string uuid = boost::lexical_cast<std::string>(i);
+    std::string value = "Value " + boost::lexical_cast<std::string>(i * 2);
+    s.Create(uuid, value.c_str(), value.size(), OrthancPluginContentType_Unknown);
+  }
+
+  std::string tmp;
+  ASSERT_THROW(s.Read(tmp, "nope", OrthancPluginContentType_Unknown), PostgreSQLException);
+  
+  ASSERT_EQ(10, CountLargeObjects(s.GetConnection()));
+  s.Remove("5", OrthancPluginContentType_Unknown);
+  ASSERT_EQ(9, CountLargeObjects(s.GetConnection()));
+
+  for (int i = 0; i < 10; i++)
+  {
+    std::string uuid = boost::lexical_cast<std::string>(i);
+    std::string expected = "Value " + boost::lexical_cast<std::string>(i * 2);
+    std::string content;
+
+    if (i == 5)
+    {
+      ASSERT_THROW(s.Read(content, uuid, OrthancPluginContentType_Unknown), PostgreSQLException);
+    }
+    else
+    {
+      s.Read(content, uuid, OrthancPluginContentType_Unknown);
+      ASSERT_EQ(expected, content);
+    }
+  }
+
+  s.Clear();
+  ASSERT_EQ(0, CountLargeObjects(s.GetConnection()));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UnitTestsSources/PostgreSQLWrapperTests.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,411 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "EmbeddedResources.h"
+
+#include <gtest/gtest.h>
+
+#include "../Core/PostgreSQLTransaction.h"
+#include "../Core/PostgreSQLResult.h"
+#include "../IndexPlugin/PostgreSQLWrapper.h"
+
+using namespace OrthancPlugins;
+
+extern PostgreSQLConnection* CreateTestConnection();
+
+
+// From Orthanc enumerations 
+static const int32_t  GlobalProperty_DatabaseSchemaVersion = 1;
+static const int32_t  GlobalProperty_AnonymizationSequence = 3;
+static const int32_t  MetadataType_ModifiedFrom = 5;
+static const int32_t  MetadataType_LastUpdate = 7;
+static const int32_t  FileContentType_Dicom = 1;
+static const int32_t  FileContentType_DicomAsJson = 2;
+static const int32_t  CompressionType_None = 1;
+static const int32_t  CompressionType_Zlib = 2;
+
+
+static std::auto_ptr<OrthancPluginAttachment>  expectedAttachment;
+static std::list<OrthancPluginDicomTag>  expectedDicomTags;
+static std::auto_ptr<OrthancPluginExportedResource>  expectedExported;
+
+static void CheckAttachment(const OrthancPluginAttachment& attachment)
+{
+  ASSERT_STREQ(expectedAttachment->uuid, attachment.uuid);
+  ASSERT_EQ(expectedAttachment->contentType, attachment.contentType);
+  ASSERT_EQ(expectedAttachment->uncompressedSize, attachment.uncompressedSize);
+  ASSERT_STREQ(expectedAttachment->uncompressedHash, attachment.uncompressedHash);
+  ASSERT_EQ(expectedAttachment->compressionType, attachment.compressionType);
+  ASSERT_EQ(expectedAttachment->compressedSize, attachment.compressedSize);
+  ASSERT_STREQ(expectedAttachment->compressedHash, attachment.compressedHash);
+}
+
+static void CheckExportedResource(const OrthancPluginExportedResource& exported)
+{
+  ASSERT_EQ(expectedExported->seq, exported.seq);
+  ASSERT_EQ(expectedExported->resourceType, exported.resourceType);
+  ASSERT_STREQ(expectedExported->publicId, exported.publicId);
+  ASSERT_STREQ(expectedExported->modality, exported.modality);
+  ASSERT_STREQ(expectedExported->date, exported.date);
+  ASSERT_STREQ(expectedExported->patientId, exported.patientId);
+  ASSERT_STREQ(expectedExported->studyInstanceUid, exported.studyInstanceUid);
+  ASSERT_STREQ(expectedExported->seriesInstanceUid, exported.seriesInstanceUid);
+  ASSERT_STREQ(expectedExported->sopInstanceUid, exported.sopInstanceUid);
+}
+
+static void CheckDicomTag(const OrthancPluginDicomTag& tag)
+{
+  for (std::list<OrthancPluginDicomTag>::const_iterator
+         it = expectedDicomTags.begin(); it != expectedDicomTags.end(); it++)
+  {
+    if (it->group == tag.group &&
+        it->element == tag.element &&
+        !strcmp(it->value, tag.value))
+    {
+      // OK, match
+      return;
+    }
+  }
+
+  ASSERT_TRUE(0);  // Error
+}
+
+static int32_t InvokeService(struct _OrthancPluginContext_t* context,
+                             _OrthancPluginService service,
+                             const void* params)
+{
+  if (service == _OrthancPluginService_DatabaseAnswer)
+  {
+    const _OrthancPluginDatabaseAnswer& answer = 
+      *reinterpret_cast<const _OrthancPluginDatabaseAnswer*>(params);
+
+    switch (answer.type)
+    {
+      case _OrthancPluginDatabaseAnswerType_Attachment:
+      {
+        const OrthancPluginAttachment& attachment = 
+          *reinterpret_cast<const OrthancPluginAttachment*>(answer.valueGeneric);
+        CheckAttachment(attachment);
+        break;
+      }
+
+      case _OrthancPluginDatabaseAnswerType_ExportedResource:
+      {
+        const OrthancPluginExportedResource& attachment = 
+          *reinterpret_cast<const OrthancPluginExportedResource*>(answer.valueGeneric);
+        CheckExportedResource(attachment);
+        break;
+      }
+
+      case _OrthancPluginDatabaseAnswerType_DicomTag:
+      {
+        const OrthancPluginDicomTag& tag = 
+          *reinterpret_cast<const OrthancPluginDicomTag*>(answer.valueGeneric);
+        CheckDicomTag(tag);
+        break;
+      }
+
+      default:
+        printf("Unhandled message: %d\n", answer.type);
+        break;
+    }
+  }
+
+  return 0;
+}
+
+
+TEST(PostgreSQLWrapper, Basic)
+{
+  std::auto_ptr<PostgreSQLConnection> pg(CreateTestConnection());
+
+  OrthancPluginContext context;
+  context.pluginsManager = NULL;
+  context.orthancVersion = "mainline";
+  context.Free = ::free;
+  context.InvokeService = InvokeService;
+
+  PostgreSQLWrapper db(pg.release(), true);
+  db.RegisterOutput(new DatabaseBackendOutput(&context, NULL));
+
+  std::string s;
+  ASSERT_TRUE(db.LookupGlobalProperty(s, GlobalProperty_DatabaseSchemaVersion));
+  ASSERT_EQ("5", s);
+
+  ASSERT_FALSE(db.LookupGlobalProperty(s, GlobalProperty_AnonymizationSequence));
+  db.SetGlobalProperty(GlobalProperty_AnonymizationSequence, "Hello");
+  ASSERT_TRUE(db.LookupGlobalProperty(s, GlobalProperty_AnonymizationSequence));
+  ASSERT_EQ("Hello", s);
+
+  int64_t a = db.CreateResource("study", OrthancPluginResourceType_Study);
+  ASSERT_TRUE(db.IsExistingResource(a));
+  ASSERT_FALSE(db.IsExistingResource(a + 1));
+
+  int64_t b;
+  OrthancPluginResourceType t;
+  ASSERT_FALSE(db.LookupResource(b, t, "world"));
+  ASSERT_TRUE(db.LookupResource(b, t, "study"));
+  ASSERT_EQ(a, b);
+  ASSERT_EQ(OrthancPluginResourceType_Study, t);
+  
+  b = db.CreateResource("series", OrthancPluginResourceType_Series);
+  ASSERT_NE(a, b);
+
+  ASSERT_EQ("study", db.GetPublicId(a));
+  ASSERT_EQ("series", db.GetPublicId(b));
+  ASSERT_EQ(OrthancPluginResourceType_Study, db.GetResourceType(a));
+  ASSERT_EQ(OrthancPluginResourceType_Series, db.GetResourceType(b));
+
+  db.AttachChild(a, b);
+
+  int64_t c;
+  ASSERT_FALSE(db.LookupParent(c, a));
+  ASSERT_TRUE(db.LookupParent(c, b));
+  ASSERT_EQ(a, c);
+
+  c = db.CreateResource("series2", OrthancPluginResourceType_Series);
+  db.AttachChild(a, c);
+
+  ASSERT_EQ(3, db.GetTableRecordCount("Resources"));
+  ASSERT_EQ(0, db.GetResourceCount(OrthancPluginResourceType_Patient));
+  ASSERT_EQ(1, db.GetResourceCount(OrthancPluginResourceType_Study));
+  ASSERT_EQ(2, db.GetResourceCount(OrthancPluginResourceType_Series));
+
+  ASSERT_FALSE(db.GetParentPublicId(s, a));
+  ASSERT_TRUE(db.GetParentPublicId(s, b));  ASSERT_EQ("study", s);
+  ASSERT_TRUE(db.GetParentPublicId(s, c));  ASSERT_EQ("study", s);
+
+  std::list<std::string> children;
+  db.GetChildren(children, a);
+  ASSERT_EQ(2u, children.size());
+  db.GetChildren(children, b);
+  ASSERT_EQ(0u, children.size());
+  db.GetChildren(children, c);
+  ASSERT_EQ(0u, children.size());
+
+  std::list<std::string> cp;
+  db.GetChildrenPublicId(cp, a);
+  ASSERT_EQ(2, cp.size());
+  ASSERT_TRUE(cp.front() == "series" || cp.front() == "series2");
+  ASSERT_TRUE(cp.back() == "series" || cp.back() == "series2");
+  ASSERT_NE(cp.front(), cp.back());
+
+  std::list<std::string> pub;
+  db.GetAllPublicIds(pub, OrthancPluginResourceType_Patient);
+  ASSERT_EQ(0, pub.size());
+  db.GetAllPublicIds(pub, OrthancPluginResourceType_Study);
+  ASSERT_EQ(1, pub.size());
+  ASSERT_EQ("study", pub.front());
+  db.GetAllPublicIds(pub, OrthancPluginResourceType_Series);
+  ASSERT_EQ(2, pub.size());
+  ASSERT_TRUE(pub.front() == "series" || pub.front() == "series2");
+  ASSERT_TRUE(pub.back() == "series" || pub.back() == "series2");
+  ASSERT_NE(pub.front(), pub.back());
+
+  std::list<int64_t> ci;
+  db.GetChildrenInternalId(ci, a);
+  ASSERT_EQ(2, ci.size());
+  ASSERT_TRUE(ci.front() == b || ci.front() == c);
+  ASSERT_TRUE(ci.back() == b || ci.back() == c);
+  ASSERT_NE(ci.front(), ci.back());
+
+  db.SetMetadata(a, MetadataType_ModifiedFrom, "modified");
+  db.SetMetadata(a, MetadataType_LastUpdate, "update");
+  ASSERT_FALSE(db.LookupMetadata(s, b, MetadataType_LastUpdate));
+  ASSERT_TRUE(db.LookupMetadata(s, a, MetadataType_LastUpdate));
+  ASSERT_EQ("update", s);
+
+  std::list<int32_t> md;
+  db.ListAvailableMetadata(md, a);
+  ASSERT_EQ(2, md.size());
+  ASSERT_TRUE(md.front() == MetadataType_ModifiedFrom || md.back() == MetadataType_ModifiedFrom);
+  ASSERT_TRUE(md.front() == MetadataType_LastUpdate || md.back() == MetadataType_LastUpdate);
+  std::string mdd;
+  ASSERT_TRUE(db.LookupMetadata(mdd, a, MetadataType_ModifiedFrom));
+  ASSERT_EQ("modified", mdd);
+  ASSERT_TRUE(db.LookupMetadata(mdd, a, MetadataType_LastUpdate));
+  ASSERT_EQ("update", mdd);
+
+  db.ListAvailableMetadata(md, b);
+  ASSERT_EQ(0, md.size());
+
+  db.DeleteMetadata(a, MetadataType_LastUpdate);
+  db.DeleteMetadata(b, MetadataType_LastUpdate);
+  ASSERT_FALSE(db.LookupMetadata(s, a, MetadataType_LastUpdate));
+
+  db.ListAvailableMetadata(md, a);
+  ASSERT_EQ(1, md.size());
+  ASSERT_EQ(MetadataType_ModifiedFrom, md.front());
+
+  ASSERT_EQ(0, db.GetTotalCompressedSize());
+  ASSERT_EQ(0, db.GetTotalUncompressedSize());
+
+
+  std::list<int32_t> fc;
+
+  OrthancPluginAttachment a1;
+  a1.uuid = "uuid1";
+  a1.contentType = FileContentType_Dicom;
+  a1.uncompressedSize = 42;
+  a1.uncompressedHash = "md5_1";
+  a1.compressionType = CompressionType_None;
+  a1.compressedSize = 42;
+  a1.compressedHash = "md5_1";
+    
+  OrthancPluginAttachment a2;
+  a2.uuid = "uuid2";
+  a2.contentType = FileContentType_DicomAsJson;
+  a2.uncompressedSize = 4242;
+  a2.uncompressedHash = "md5_2";
+  a2.compressionType = CompressionType_None;
+  a2.compressedSize = 4242;
+  a2.compressedHash = "md5_2";
+    
+  db.AddAttachment(a, a1);
+  db.ListAvailableAttachments(fc, a);
+  ASSERT_EQ(1, fc.size());
+  ASSERT_EQ(FileContentType_Dicom, fc.front());
+  db.AddAttachment(a, a2);
+  db.ListAvailableAttachments(fc, a);
+  ASSERT_EQ(2, fc.size());
+  ASSERT_FALSE(db.LookupAttachment(b, FileContentType_Dicom));
+
+  ASSERT_EQ(4284, db.GetTotalCompressedSize());
+  ASSERT_EQ(4284, db.GetTotalUncompressedSize());
+
+  expectedAttachment.reset(new OrthancPluginAttachment);
+  expectedAttachment->uuid = "uuid1";
+  expectedAttachment->contentType = FileContentType_Dicom;
+  expectedAttachment->uncompressedSize = 42;
+  expectedAttachment->uncompressedHash = "md5_1";
+  expectedAttachment->compressionType = CompressionType_None;
+  expectedAttachment->compressedSize = 42;
+  expectedAttachment->compressedHash = "md5_1";
+  ASSERT_TRUE(db.LookupAttachment(a, FileContentType_Dicom));
+
+  expectedAttachment.reset(new OrthancPluginAttachment);
+  expectedAttachment->uuid = "uuid2";
+  expectedAttachment->contentType = FileContentType_DicomAsJson;
+  expectedAttachment->uncompressedSize = 4242;
+  expectedAttachment->uncompressedHash = "md5_2";
+  expectedAttachment->compressionType = CompressionType_None;
+  expectedAttachment->compressedSize = 4242;
+  expectedAttachment->compressedHash = "md5_2";
+  ASSERT_TRUE(db.LookupAttachment(a, FileContentType_DicomAsJson));
+
+  db.ListAvailableAttachments(fc, b);
+  ASSERT_EQ(0, fc.size());
+  db.DeleteAttachment(a, FileContentType_Dicom);
+  db.ListAvailableAttachments(fc, a);
+  ASSERT_EQ(1, fc.size());
+  ASSERT_EQ(FileContentType_DicomAsJson, fc.front());
+  db.DeleteAttachment(a, FileContentType_DicomAsJson);
+  db.ListAvailableAttachments(fc, a);
+  ASSERT_EQ(0, fc.size());
+
+
+  db.SetIdentifierTag(a, 0x0010, 0x0020, "patient");
+  db.SetIdentifierTag(a, 0x0020, 0x000d, "study");
+
+  expectedDicomTags.clear();
+  expectedDicomTags.push_back(OrthancPluginDicomTag());
+  expectedDicomTags.push_back(OrthancPluginDicomTag());
+  expectedDicomTags.front().group = 0x0010;
+  expectedDicomTags.front().element = 0x0020;
+  expectedDicomTags.front().value = "patient";
+  expectedDicomTags.back().group = 0x0020;
+  expectedDicomTags.back().element = 0x000d;
+  expectedDicomTags.back().value = "study";
+  db.GetMainDicomTags(a);
+
+
+  db.LookupIdentifier(ci, 0x0010, 0x0020, "patient");
+  ASSERT_EQ(1, ci.size());
+  ASSERT_EQ(a, ci.front());
+  db.LookupIdentifier(ci, 0x0010, 0x0020, "study");
+  ASSERT_EQ(0, ci.size());
+  db.LookupIdentifier(ci, "study");
+  ASSERT_EQ(1, ci.size());
+  ASSERT_EQ(a, ci.front());
+
+
+  OrthancPluginExportedResource exp;
+  exp.seq = -1;
+  exp.resourceType = OrthancPluginResourceType_Study;
+  exp.publicId = "id";
+  exp.modality = "remote";
+  exp.date = "date";
+  exp.patientId = "patient";
+  exp.studyInstanceUid = "study";
+  exp.seriesInstanceUid = "series";
+  exp.sopInstanceUid = "instance";
+  db.LogExportedResource(exp);
+    
+  expectedExported.reset(new OrthancPluginExportedResource());
+  *expectedExported = exp;
+  expectedExported->seq = 1;
+
+  bool done;
+  db.GetExportedResources(done, 0, 10);
+  
+
+  db.GetAllPublicIds(pub, OrthancPluginResourceType_Patient); ASSERT_EQ(0, pub.size());
+  db.GetAllPublicIds(pub, OrthancPluginResourceType_Study); ASSERT_EQ(1, pub.size());
+  db.GetAllPublicIds(pub, OrthancPluginResourceType_Series); ASSERT_EQ(2, pub.size());
+  db.GetAllPublicIds(pub, OrthancPluginResourceType_Instance); ASSERT_EQ(0, pub.size());
+  ASSERT_EQ(3, db.GetTableRecordCount("Resources"));
+
+  ASSERT_EQ(0, db.GetTableRecordCount("PatientRecyclingOrder"));  // No patient was inserted
+  ASSERT_TRUE(db.IsExistingResource(c));
+  db.DeleteResource(c);
+  ASSERT_FALSE(db.IsExistingResource(c));
+  ASSERT_TRUE(db.IsExistingResource(a));
+  ASSERT_TRUE(db.IsExistingResource(b));
+  ASSERT_EQ(2, db.GetTableRecordCount("Resources"));
+  db.DeleteResource(a);
+  ASSERT_EQ(0, db.GetTableRecordCount("Resources"));
+  ASSERT_FALSE(db.IsExistingResource(a));
+  ASSERT_FALSE(db.IsExistingResource(b));
+  ASSERT_FALSE(db.IsExistingResource(c));
+
+  ASSERT_EQ(0, db.GetTableRecordCount("Resources"));
+  ASSERT_EQ(0, db.GetTableRecordCount("PatientRecyclingOrder"));
+  int64_t p1 = db.CreateResource("patient1", OrthancPluginResourceType_Patient);
+  int64_t p2 = db.CreateResource("patient2", OrthancPluginResourceType_Patient);
+  int64_t p3 = db.CreateResource("patient3", OrthancPluginResourceType_Patient);
+  ASSERT_EQ(3, db.GetTableRecordCount("PatientRecyclingOrder"));
+  int64_t r;
+  ASSERT_TRUE(db.SelectPatientToRecycle(r));
+  ASSERT_EQ(p1, r);
+  ASSERT_TRUE(db.SelectPatientToRecycle(r, p1));
+  ASSERT_EQ(p2, r);
+  ASSERT_FALSE(db.IsProtectedPatient(p1));
+  db.SetProtectedPatient(p1, true);
+  ASSERT_TRUE(db.IsProtectedPatient(p1));
+  ASSERT_TRUE(db.SelectPatientToRecycle(r));
+  ASSERT_EQ(p2, r);
+  db.SetProtectedPatient(p1, false);
+  ASSERT_FALSE(db.IsProtectedPatient(p1));
+  ASSERT_TRUE(db.SelectPatientToRecycle(r));
+  ASSERT_EQ(p2, r);
+  db.DeleteResource(p2);
+  ASSERT_TRUE(db.SelectPatientToRecycle(r, p3));
+  ASSERT_EQ(p1, r);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UnitTestsSources/UnitTestsMain.cpp	Thu Feb 12 16:05:39 2015 +0100
@@ -0,0 +1,65 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, 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/>.
+ **/
+
+
+#include "../Core/PostgreSQLConnection.h"
+
+#include <gtest/gtest.h>
+#include <memory>
+#include <boost/lexical_cast.hpp>
+
+static int argc_;
+static char** argv_;
+
+OrthancPlugins::PostgreSQLConnection* CreateTestConnection()
+{
+  std::auto_ptr<OrthancPlugins::PostgreSQLConnection> pg(new OrthancPlugins::PostgreSQLConnection);
+
+  pg->SetHost(argv_[1]);
+  pg->SetPortNumber(boost::lexical_cast<uint16_t>(argv_[2]));
+  pg->SetUsername(argv_[3]);
+  pg->SetPassword(argv_[4]);
+  pg->SetDatabase(argv_[5]);
+  
+  pg->Open();
+  pg->ClearAll();
+
+  return pg.release();
+}
+
+
+
+int main(int argc, char **argv)
+{
+  if (argc != 6)
+  {
+    std::cerr << "Usage: " << argv[0] << " <host> <port> <username> <password> <database>"
+              << std::endl << std::endl
+              << "Example: " << argv[0] << " localhost 5432 postgres postgres orthanctests"
+              << std::endl << std::endl;
+    return -1;
+  }
+
+  argc_ = argc;
+  argv_ = argv;  
+
+  ::testing::InitGoogleTest(&argc, argv);
+
+  return RUN_ALL_TESTS();
+}