Skip to content
Browse files

Branch pgAgent 3.0.0

git-svn-id: svn://svn.pgadmin.org/branches/REL-3_0_0_PATCHES@7698 a7884b65-44f6-0310-8a51-81a127f17b15
  • Loading branch information...
0 parents commit ca980a64df1ac616e9ef69e49906824b67a4023f @dpage dpage committed Mar 13, 2009
180 CMakeLists.txt
@@ -0,0 +1,180 @@
+#######################################################################
+#
+# pgAgent - PostgreSQL tools
+# Copyright (C) 2002 - 2008, The pgAdmin Development Team
+# This software is released under the Artistic Licence
+#
+# CMakeLists.txt - CMake build configuration
+#
+#######################################################################
+
+################################################################################
+# Initial setup
+################################################################################
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+IF(COMMAND cmake_policy)
+ CMAKE_POLICY(SET CMP0003 NEW)
+ENDIF(COMMAND cmake_policy)
+
+SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
+
+SET(CMAKE_FIND_LIBRARY_PREFIXES "")
+SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
+
+SET(STATIC_BUILD YES CACHE BOOL "Statically link the executable?")
+
+################################################################################
+# Apple stuff
+################################################################################
+IF(APPLE)
+ # Setup default values
+ IF(NOT HAVE_CACHED_VALUES)
+ IF(EXISTS /Developer/SDKs/MacOSX10.5.sdk)
+ SET(CMAKE_OSX_ARCHITECTURES "ppc;i386" CACHE STRING "Build architectures for OSX" FORCE)
+ SET(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.5.sdk" CACHE FILEPATH "isysroot used for universal binary support" FORCE)
+ ELSE()
+ IF(EXISTS /Developer/SDKs/MacOSX10.4u.sdk)
+ SET(CMAKE_OSX_ARCHITECTURES "ppc;i386" CACHE STRING "Build architectures for OSX" FORCE)
+ SET(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.4u.sdk" CACHE FILEPATH "isysroot used for universal binary support" FORCE)
+ ELSE()
+ MESSAGE(FATAL_ERROR "No supported SDK could be found!")
+ ENDIF(EXISTS /Developer/SDKs/MacOSX10.4u.sdk)
+ ENDIF(EXISTS /Developer/SDKs/MacOSX10.5.sdk)
+ ENDIF(NOT HAVE_CACHED_VALUES)
+
+ # Target Tiger
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.4")
+ENDIF(APPLE)
+
+################################################################################
+# Project config
+################################################################################
+PROJECT(pgagent)
+
+# If changing the version number, remember to change here and under the CPack
+# settings in this file, as well as the definition for pgagent_schema_version()
+# in pgagent.sql and upgrade_pgagent.sql if the major version number is
+# changed. The full version number also needs to be included in pgAgent.rc and
+# pgaevent/pgamsgevent.rc at present.
+SET(VERSION 3.0.0)
+
+# CPack stuff
+SET(CPACK_PACKAGE_VERSION_MAJOR 3)
+SET(CPACK_PACKAGE_VERSION_MINOR 0)
+SET(CPACK_PACKAGE_VERSION_PATCH 0)
+SET(CPACK_PACKAGE_NAME "pgAgent")
+SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "pgAgent is a job scheduling engine for PostgreSQL")
+SET(CPACK_PACKAGE_VENDOR "the pgAdmin Development Team")
+IF(WIN32)
+ SET(CPACK_GENERATOR ZIP)
+ELSE(WIN32)
+ SET(CPACK_GENERATOR TGZ)
+ENDIF(WIN32)
+SET(CPACK_SOURCE_GENERATOR TGZ)
+SET(CPACK_SOURCE_IGNORE_FILES "\\\\.DS_Store;/CVS/;/\\\\.svn/;\\\\.swp$;\\\\.#;/#;.*~;cscope.*")
+
+ADD_DEFINITIONS(-DPGAGENT_VERSION_MAJOR=${CPACK_PACKAGE_VERSION_MAJOR})
+
+# This must come after we set the CPACK variables!!
+INCLUDE(CPack)
+
+################################################################################
+# Find wxWidgets
+################################################################################
+SET(WX_DEBUG NO CACHE BOOL "Use the debug build of wxWidgets?")
+SET(WX_STATIC ${STATIC_BUILD})
+SET(WX_VERSION "2.8")
+SET(WX_UNICODE YES)
+SET(WX_MODULES "base")
+
+FIND_PACKAGE(WX REQUIRED)
+
+INCLUDE_DIRECTORIES(${WX_INCLUDE_DIRS})
+ADD_DEFINITIONS(${WX_DEFINITIONS})
+LINK_DIRECTORIES(${WX_LIBRARY_DIRS})
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WX_CXX_FLAGS}")
+
+################################################################################
+# Find PostgreSQL
+################################################################################
+SET(PG_STATIC ${WX_STATIC})
+
+FIND_PACKAGE(PG REQUIRED)
+
+INCLUDE_DIRECTORIES(${PG_INCLUDE_DIRS})
+LINK_DIRECTORIES(${PG_LIBRARY_DIRS})
+
+################################################################################
+# Let's rock!
+################################################################################
+INCLUDE_DIRECTORIES(${pgagent_SOURCE_DIR}
+ ${pgagent_SOURCE_DIR}/include)
+
+FILE(GLOB _cpp_files *.cpp)
+FILE(GLOB _h_files include/*.h)
+
+SET(_srcs ${_cpp_files} ${_h_files})
+
+IF(WIN32)
+ SET(_srcs ${_srcs} pgagent.rc)
+ENDIF(WIN32)
+
+ADD_EXECUTABLE(pgagent ${_srcs})
+TARGET_LINK_LIBRARIES(pgagent ${PG_LIBRARIES} ${WX_LIBRARIES})
+
+# Installation
+IF (WIN32)
+ INSTALL(TARGETS pgagent DESTINATION .)
+ INSTALL(FILES ${pgagent_SOURCE_DIR}/pgagent.sql DESTINATION .)
+ INSTALL(FILES ${pgagent_SOURCE_DIR}/pgagent_upgrade.sql DESTINATION .)
+ELSE(WIN32)
+ INSTALL(TARGETS pgagent DESTINATION bin)
+ INSTALL(FILES ${pgagent_SOURCE_DIR}/pgagent.sql DESTINATION share)
+ INSTALL(FILES ${pgagent_SOURCE_DIR}/pgagent_upgrade.sql DESTINATION share)
+ENDIF(WIN32)
+
+INSTALL(FILES ${pgagent_SOURCE_DIR}/README DESTINATION .)
+INSTALL(FILES ${pgagent_SOURCE_DIR}/LICENSE DESTINATION .)
+
+################################################################################
+# pgaevent
+################################################################################
+IF(WIN32)
+ ADD_SUBDIRECTORY(pgaevent)
+ENDIF(WIN32)
+
+################################################################################
+# Build summary
+################################################################################
+MESSAGE(STATUS " ")
+
+MESSAGE(STATUS "================================================================================")
+MESSAGE(STATUS "Configuration summary:")
+MESSAGE(STATUS " ")
+MESSAGE(STATUS " Project : ${PROJECT_NAME}")
+MESSAGE(STATUS " Description : ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
+MESSAGE(STATUS " Version : ${VERSION}")
+MESSAGE(STATUS " ")
+MESSAGE(STATUS " PostgreSQL version : ${PG_VERSION_STRING}")
+MESSAGE(STATUS " PostgreSQL path : ${PG_ROOT_DIR}")
+MESSAGE(STATUS " PostgreSQL config binary : ${PG_CONFIG_PATH}")
+MESSAGE(STATUS " PostgreSQL include path : ${PG_INCLUDE_DIRS}")
+MESSAGE(STATUS " PostgreSQL library path : ${PG_LIBRARY_DIRS}")
+MESSAGE(STATUS " ")
+MESSAGE(STATUS " wxWidgets version : ${WX_VERSION_STRING}")
+MESSAGE(STATUS " wxWidgets path : ${WX_ROOT_DIR}")
+MESSAGE(STATUS " wxWidgets config binary : ${WX_CONFIG_PATH}")
+MESSAGE(STATUS " wxWidgets Static linking : ${WX_STATIC}")
+MESSAGE(STATUS " wxWidgets Debug? : ${WX_DEBUG}")
+MESSAGE(STATUS "================================================================================")
+MESSAGE(STATUS " ")
+
+################################################################################
+# Give ourselves a hint that we have cached values - must be last!
+################################################################################
+IF(NOT HAVE_CACHED_VALUES)
+ SET(HAVE_CACHED_VALUES 1 CACHE INTERNAL "Flag to indicate that we have cached values")
+ENDIF(NOT HAVE_CACHED_VALUES)
+
+
119 LICENSE
@@ -0,0 +1,119 @@
+BY INSTALLING OR DISTRIBUTING PGADMIN AND RELATED SOFTWARE, YOU AGREE WITH
+THE FOLLOWING DISCLAIMER:
+
+PGADMIN AND RELATED SOFTWARE IS PROVIDED WITHOUT GUARANTEE OR WARRANTY OF
+ANY KIND. TO THE FULLEST EXTENT ALLOWED BY LAW YOU AGREE THAT THE PGADMIN
+DEVELOPMENT TEAM MEMBERS, CONTRIBUTERS OR DISTRIBUTORS OF THE SOFTWARE CANNOT
+AND WILL NOT BE HELD LIABLE FOR ANY DIRECT OR INDIRECT DAMAGE OR LOSSES CAUSED
+WHOLLY OR IN PART BY THE SOFTWARE.
+
+IN COUNTRIES WHERE THE ABSENCE OF LIABILITY MAY NOT EXIST OR BE RESTRICTED
+BY LAW, PGADMIN DEVELOPMENT TEAM MEMBERS, CONTRIBUTORS AND DISTRIBUTORS
+LIABILITY SHALL BE LIMITED TO ONE EURO.
+
+The Artistic License
+====================
+
+Preamble
+
+The intent of this document is to state the conditions under which a Package
+may be copied, such that the Copyright Holder maintains some semblance of
+artistic control over the development of the package, while giving the users
+of the package the right to use and distribute the Package in a more-or-less
+customary fashion, plus the right to make reasonable modifications.
+
+Definitions:
+
+"Package" refers to the collection of files distributed by the Copyright
+Holder, and derivatives of that collection of files created through textual
+modification.
+
+"Standard Version" refers to such a Package if it has not been modified, or
+has been modified in accordance with the wishes of the Copyright Holder.
+
+"Copyright Holder" is whoever is named in the copyright or copyrights for the
+package.
+
+"You" is you, if you're thinking about copying or distributing this Package.
+
+"Reasonable copying fee" is whatever you can justify on the basis of media
+cost, duplication charges, time of people involved, and so on. (You will not
+be required to justify it to the Copyright Holder, but only to the computing
+community at large as a market that must bear the fee.)
+
+"Freely Available" means that no fee is charged for the item itself, though
+there may be fees involved in handling the item. It also means that recipients
+of the item may redistribute it under the same conditions they received it.
+
+1. You may make and give away verbatim copies of the source form of the
+ Standard Version of this Package without restriction, provided that you
+ duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications derived
+ from the Public Domain or from the Copyright Holder. A Package modified in
+ such a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided that
+ you insert a prominent notice in each changed file stating how and when you
+ changed that file, and provided that you do at least ONE of the following:
+
+ a) place your modifications in the Public Domain or otherwise make them
+ Freely Available, such as by posting said modifications to Usenet or an
+ equivalent medium, or placing the modifications on a major archive site
+ such as ftp.uu.net, or by allowing the Copyright Holder to include your
+ modifications in the Standard Version of the Package.
+
+ b) use the modified Package only within your corporation or organization.
+
+ c) rename any non-standard executables so the names do not conflict with
+ standard executables, which must also be provided, and provide a separate
+ manual page for each non-standard executable that clearly documents how
+ it differs from the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or executable
+ form, provided that you do at least ONE of the following:
+
+ a) distribute a Standard Version of the executables and library files,
+ together with instructions (in the manual page or equivalent) on where
+ to get the Standard Version.
+
+ b) accompany the distribution with the machine-readable source of the
+ Package with your modifications.
+
+ c) accompany any non-standard executables with their corresponding Standard
+ Version executables, giving the non-standard executables non-standard
+ names, and clearly documenting the differences in manual pages (or
+ equivalent), together with instructions on where to get the Standard
+ Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+ Package. You may charge any fee you choose for support of this Package. You
+ may not charge a fee for this Package itself. However, you may distribute
+ this Package in aggregate with other (possibly commercial) programs as part
+ of a larger (possibly commercial) software distribution provided that you do
+ not advertise this Package as a product of your own.
+
+6. The scripts and library files supplied as input to or produced as output
+ from the programs of this Package do not automatically fall under the
+ copyright of this Package, but belong to whomever generated them, and may be
+ sold commercially, and may be aggregated with this Package.
+
+7. C or perl subroutines supplied by you and linked into this Package shall not
+ be considered part of this Package.
+
+8. The name of the Copyright Holder may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+The End
+
+
+
51 README
@@ -0,0 +1,51 @@
+pgAgent
+=======
+
+This document describes the compilation of pgAgent, a job scheduler for
+PostgreSQL.
+
+pgAgent is managed using pgAdmin (http://www.pgadmin.org). The pgAdmin
+documentation contains details of the setup and use of pgAgent with your
+PostgreSQL system. The latest build of the documentation can be found at
+http://www.pgadmin.org/docs/dev/pgagent.html.
+
+Building pgAgent
+----------------
+
+You will need:
+
+- A C/C++ compiler, such as GCC or Microsoft Visual C++ on Windows.
+- CMake 2.6 (from www.cmake.org)
+- A wxWidgets 2.8.x installation, configured per the requirements for
+ pgAdmin:
+ http://svn.pgadmin.org/cgi-bin/viewcvs.cgi/*checkout*/trunk/pgadmin3/INSTALL
+- A PostgreSQL 8.3 or higher installation
+
+1) Unpack the pgAgent source code
+2) Create a build directory in which the code will be built.
+3) Run ccmake from the build directory (on Windows, use the CMake graphical
+ interface). By default, ccmake will generate Unix Makefiles - consult the
+ documentation if you wish to generate other types of output:
+
+$ ccmake /path/to/pgagent
+
+4) If required, press 'c' to generate a default configuration:
+
+CMAKE_BUILD_TYPE Release
+CMAKE_INSTALL_PREFIX /usr/local
+CMAKE_OSX_ARCHITECTURES ppc;i386
+CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk
+PostgreSQL_CONFIG_EXECUTABLE /usr/local/pgsql/bin/pg_config
+wxWidgets_CONFIG_EXECUTABLE /usr/local/bin/wx-config
+wxWidgets_USE_DEBUG OFF
+wxWidgets_USE_STATIC ON
+wxWidgets_USE_UNICODE ON
+wxWidgets_wxrc_EXECUTABLE /usr/bin/wxrc
+
+5) Use the ccmake interface to adjust any settings as required. When configured
+ as required, press 'c' to re-configure (if required) and 'g' to generate the
+ build files and exit.
+
+6) Run 'make' to build pgAgent on Mac or Unix, or open the generated project
+ files in VC++ on Windows and build the solution in the desired configuration.
+
114 cmake/FindPG.cmake
@@ -0,0 +1,114 @@
+#######################################################################
+#
+# FindPg.cmake - A CMake module for locating PostgreSQL
+#
+# Dave Page, EnterpriseDB UK Ltd.
+# This code is released under the BSD Licence
+#
+#######################################################################
+
+# To use this module, simply include it in your CMake project.
+# If set, PostgreSQL will be assumed to be in the location specified
+# by the PGDIR environment variable. Otherwise, it will be searched
+# for in a number of standard locations.
+#
+# For statically linked builds, the PG_STATIC variable can be set to
+# true.
+#
+# The following CMake variable will be set:
+#
+# PG_FOUND - Set to TRUE if PostgreSQL is located
+# PG_CONFIG_PATH - The pg_config executable path
+# PG_ROOT_DIR - The base install directory for PostgreSQL
+# PG_INCLUDE_DIRS - The directory containing the PostgreSQL headers.
+# PG_LIBRARIES - The PostgreSQL client libraries.
+# PG_LIBRARY_DIRS - The directory containing the PostgreSQL client libraries.
+# PG_PKG_LIBRARY_DIRS - The directory containing the PostgreSQL package libraries.
+# PG_VERSION_STRING - The PostgreSQL version number.
+
+IF(NOT PG_STATIC OR PG_STATIC STREQUAL "")
+ SET(_static "no")
+ELSE(NOT PG_STATIC OR PG_STATIC STREQUAL "")
+ IF(PG_STATIC)
+ SET(_static "yes")
+ ELSE(PG_STATIC)
+ SET(_static "no")
+ ENDIF(PG_STATIC)
+ENDIF(NOT PG_STATIC OR PG_STATIC STREQUAL "")
+
+IF(NOT $ENV{PGDIR} STREQUAL "")
+ FIND_PROGRAM(PG_CONFIG_PATH pg_config
+ PATH $ENV{PGDIR}/bin
+ DOC "Path to the pg_config executable"
+ NO_DEFAULT_PATH)
+ELSE(NOT $ENV{PGDIR} STREQUAL "")
+ FIND_PROGRAM(PG_CONFIG_PATH pg_config
+ PATH /usr/local/pgsql/bin
+ /opt/PostgreSQL/*/bin
+ /Library/PostgreSQL/*/bin
+ $ENV{ProgramFiles}/PostgreSQL/*/bin
+ $ENV{SystemDrive}/PostgreSQL/*/bin
+ DOC "Path to the pg_config executable")
+
+ENDIF(NOT $ENV{PGDIR} STREQUAL "")
+
+EXEC_PROGRAM(${PG_CONFIG_PATH} ARGS --version OUTPUT_VARIABLE PG_VERSION_STRING RETURN_VALUE _retval)
+
+IF(NOT _retval)
+
+ SET(PG_FOUND TRUE)
+
+ # Strip the bin and pg_config from the path
+ GET_FILENAME_COMPONENT(PG_ROOT_DIR ${PG_CONFIG_PATH} PATH)
+ GET_FILENAME_COMPONENT(PG_ROOT_DIR ${PG_ROOT_DIR} PATH)
+
+ IF(WIN32 AND NOT CYGWIN AND NOT MSYS)
+
+ SET(PG_INCLUDE_DIRS "${PG_ROOT_DIR}/include")
+ SET(PG_LIBRARY_DIRS "${PG_ROOT_DIR}/lib")
+ SET(PG_PKG_LIBRARY_DIRS "${PG_ROOT_DIR}/lib")
+
+ # There iare no static libraries on VC++ builds of PG.
+ LIST(APPEND PG_LIBRARIES libpq.lib)
+
+ ELSE(WIN32 AND NOT CYGWIN AND NOT MSYS)
+
+ EXEC_PROGRAM(${PG_CONFIG_PATH} ARGS --includedir OUTPUT_VARIABLE PG_INCLUDE_DIRS)
+ EXEC_PROGRAM(${PG_CONFIG_PATH} ARGS --libdir OUTPUT_VARIABLE PG_LIBRARY_DIRS)
+ EXEC_PROGRAM(${PG_CONFIG_PATH} ARGS --pkglibdir OUTPUT_VARIABLE PG_PKG_LIBRARY_DIRS)
+
+ IF(_static)
+ LIST(APPEND PG_LIBRARIES ${PG_LIBRARY_DIRS}/libpq.a)
+
+ # Check for SSL and Kerberos
+ EXEC_PROGRAM("nm" ARGS ${PG_LIBRARY_DIRS}/libpq.a OUTPUT_VARIABLE _op)
+
+ IF(_op MATCHES "SSL_connect")
+ LIST(APPEND PG_LIBRARIES "ssl")
+ ENDIF(_op MATCHES "SSL_connect")
+
+ IF(_op MATCHES "krb5_free_principal")
+ LIST(APPEND PG_LIBRARIES "krb5")
+ ENDIF(_op MATCHES "krb5_free_principal")
+
+ LIST(APPEND PG_LIBRARIES "crypto")
+
+ IF(NOT APPLE)
+ LIST(APPEND PG_LIBRARIES "crypt")
+ ENDIF(NOT APPLE)
+
+ ELSE(_static)
+ LIST(APPEND PG_LIBRARIES pq)
+ ENDIF(_static)
+ ENDIF(WIN32 AND NOT CYGWIN AND NOT MSYS)
+
+ELSE(NOT _retval)
+ SET(PG_FOUND FALSE)
+ SET(PG_ROOT_DIR PG_ROOT_DIR-NO_FOUND)
+ IF(PG_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "No PostgreSQL installation could be found.")
+ ELSE(PG_FIND_REQUIRED)
+ MESSAGE(STATUS "No PostgreSQL installation could be found.")
+ ENDIF(PG_FIND_REQUIRED)
+ENDIF(NOT _retval)
+
323 cmake/FindWX.cmake
@@ -0,0 +1,323 @@
+#######################################################################
+#
+# FindPg.cmake - A CMake module for locating wxWidgets
+#
+# Dave Page, EnterpriseDB UK Ltd.
+# This code is released under the BSD Licence
+#
+#######################################################################
+
+# To use this module, simply include it in your CMake project.
+# If set, wxWidgets will be assumed to be in the location specified
+# by the WXWIN environment variable. Otherwise, it will be searched
+# for in a number of standard locations.
+#
+# The following CMake variables can be set to control the build type.
+# If not set, the default values shown will be used. Booleans must
+# be either YES or NO:
+#
+# WX_VERSION = "2.8"
+# WX_DEBUG = NO
+# WX_STATIC = NO
+# WX_UNICODE = YES
+# WX_MODULES = "base" (a list).
+#
+# The following CMake variable will be set:
+#
+# WX_FOUND - Set to TRUE if wxWidgets is located
+# WX_ROOT_DIR - The base install directory for wxWidgets
+# WX_VERSION_STRING - The wxWidgets version number.
+#
+# Unix only:
+# WX_CONFIG_PATH - The wx-config executable path
+#
+# Unix & Win32:
+# WX_INCLUDE_DIRS - The wxWidgets header directories.
+# WX_DEFINITIONS - The wxWidgets preprocessor definitions
+# WX_LIBRARIES - The wxWidgets libraries
+# WX_LIBRARY_DIRS - The wxWidgets library directories.
+
+
+###############################################################################
+# Macros
+###############################################################################
+
+# Check for a library on Windows
+MACRO(WIN32_CHECK_LIB M_LIB_NAME M_LIB_REL_FILENAME M_LIB_DBG_FILENAME M_LIB_PATH)
+
+ LIST(FIND WX_MODULES ${M_LIB_NAME} _pos)
+ IF(NOT _pos EQUAL -1)
+
+ SET(_tmp CACHE INTERNAL "_tmp-NOTFOUND")
+ FIND_FILE(_tmp NAMES ${M_LIB_REL_FILENAME} PATHS ${M_LIB_PATH} NO_DEFAULT_PATH)
+ IF(_tmp STREQUAL "_tmp-NOTFOUND")
+ SET(_error TRUE)
+ ELSE(_tmp STREQUAL "_tmp-NOTFOUND")
+ LIST(APPEND WX_LIBRARIES "optimized;${M_LIB_REL_FILENAME}")
+ ENDIF(_tmp STREQUAL "_tmp-NOTFOUND")
+
+ SET(_tmp CACHE INTERNAL "_tmp-NOTFOUND")
+ FIND_FILE(_tmp NAMES ${M_LIB_DBG_FILENAME} PATHS ${M_LIB_PATH} NO_DEFAULT_PATH)
+ IF(_tmp STREQUAL "_tmp-NOTFOUND")
+ SET(_error TRUE)
+ ELSE(_tmp STREQUAL "_tmp-NOTFOUND")
+ LIST(APPEND WX_LIBRARIES "debug;${M_LIB_DBG_FILENAME}")
+ ENDIF(_tmp STREQUAL "_tmp-NOTFOUND")
+
+ ENDIF(NOT _pos EQUAL -1)
+
+ENDMACRO(WIN32_CHECK_LIB)
+
+###############################################################################
+# Arguments
+###############################################################################
+
+IF(NOT WX_VERSION OR WX_VERSION STREQUAL "")
+ SET(_version "2.8")
+ELSE(NOT WX_VERSION OR WX_VERSION STREQUAL "")
+ SET(_version ${WX_VERSION})
+ENDIF(NOT WX_VERSION OR WX_VERSION STREQUAL "")
+
+IF(NOT WX_DEBUG OR WX_DEBUG STREQUAL "")
+ SET(_debug "no")
+ELSE(NOT WX_DEBUG OR WX_DEBUG STREQUAL "")
+ IF(WX_DEBUG)
+ SET(_debug "yes")
+ ELSE(WX_DEBUG)
+ SET(_debug "no")
+ ENDIF(WX_DEBUG)
+ENDIF(NOT WX_DEBUG OR WX_DEBUG STREQUAL "")
+
+IF(NOT WX_STATIC OR WX_STATIC STREQUAL "")
+ SET(_static "no")
+ELSE(NOT WX_STATIC OR WX_STATIC STREQUAL "")
+ IF(WX_STATIC)
+ SET(_static "yes")
+ ELSE(WX_STATIC)
+ SET(_static "no")
+ ENDIF(WX_STATIC)
+ENDIF(NOT WX_STATIC OR WX_STATIC STREQUAL "")
+
+IF(NOT WX_UNICODE OR WX_UNICODE STREQUAL "")
+ SET(_unicode "yes")
+ELSE(NOT WX_UNICODE OR WX_UNICODE STREQUAL "")
+ IF(WX_UNICODE)
+ SET(_unicode "yes")
+ ELSE(WX_UNICODE)
+ SET(_unicode "no")
+ ENDIF(WX_UNICODE)
+ENDIF(NOT WX_UNICODE OR WX_UNICODE STREQUAL "")
+
+IF(NOT WX_MODULES OR WX_MODULES STREQUAL "")
+ SET(_modules "base")
+ELSE(NOT WX_MODULES OR WX_MODULES STREQUAL "")
+ SET(_modules ${WX_MODULES})
+ENDIF(NOT WX_MODULES OR WX_MODULES STREQUAL "")
+
+SET(_build_desc "version: ${_version}, debug: ${_debug}, static: ${_static}, unicode: ${_unicode}, modules: ${_modules}")
+
+###############################################################################
+# Here we go...
+###############################################################################
+
+# MSVC++
+IF(WIN32 AND NOT CYGWIN AND NOT MSYS)
+ # The VC++ libraries are found in an entirely different way than
+ # the *nix libraries because we don't have a wx-config file.
+
+ # Figure out the build suffix
+ SET(_suffix "") # Possibly-unicode libraries
+
+ IF(_unicode)
+ SET(_suffix "${_suffix}u")
+ ENDIF(_unicode)
+
+ # Figure out the build prefix directory
+ IF(_static)
+ SET(_prefix "vc_lib")
+ ELSE(_static)
+ SET(_prefix "vc_dll")
+ ENDIF(_static)
+
+ # Find the Unix configure script. We'll attempt to extract a version number from it.
+ IF(NOT $ENV{WXWIN} STREQUAL "")
+ FIND_PATH(WX_ROOT_DIR NAMES configure
+ PATHS $ENV{WXWIN}
+ DOC "Path to the wxWidgets installation"
+ NO_DEFAULT_PATH)
+ ELSE(NOT $ENV{WXWIN} STREQUAL "")
+ FIND_PATH(WX_ROOT_DIR NAMES configure
+ PATHS $ENV{ProgramFiles}/wxWidgets-*
+ $ENV{SystemDrive}/wxWidgets-*
+ DOC "Path to the wxWidgets installation")
+ ENDIF(NOT $ENV{WXWIN} STREQUAL "")
+
+ # Attempt to read the version number from the configure script
+ FILE(STRINGS ${WX_ROOT_DIR}/configure _line REGEX "PACKAGE_VERSION=")
+ STRING(REGEX REPLACE "PACKAGE_VERSION='([0-9]+\\.[0-9]+\\.[0-9]+)'" "\\1" WX_VERSION_STRING "${_line}")
+
+ IF(NOT ${WX_VERSION_STRING} STREQUAL "")
+
+ SET(WX_FOUND TRUE)
+
+ LIST(APPEND WX_INCLUDE_DIRS "${WX_ROOT_DIR}/include" "${WX_ROOT_DIR}/contrib/include")
+ LIST(APPEND WX_LIBRARY_DIRS "${WX_ROOT_DIR}/lib/${_prefix}")
+
+ # Got through the modules list and add libraries for those requested.
+ # If any of them don't seem to exist, throw an error, or got to not found mode
+ STRING(REGEX REPLACE "^([0-9])+\\.([0-9])+\\.[0-9]+" "\\1\\2" _shortver "${WX_VERSION_STRING}")
+
+ SET(_error FALSE)
+
+ SET(_libpath ${WX_ROOT_DIR}/lib/${_prefix})
+
+ WIN32_CHECK_LIB("adv" wxmsw${_shortver}${_suffix}_adv.lib wxmsw${_shortver}${_suffix}d_adv.lib ${_libpath})
+ WIN32_CHECK_LIB("aui" wxmsw${_shortver}${_suffix}_aui.lib wxmsw${_shortver}${_suffix}d_aui.lib ${_libpath})
+ WIN32_CHECK_LIB("base" wxbase${_shortver}${_suffix}.lib wxbase${_shortver}${_suffix}d.lib ${_libpath})
+ WIN32_CHECK_LIB("core" wxmsw${_shortver}${_suffix}_core.lib wxmsw${_shortver}${_suffix}d_core.lib ${_libpath})
+ WIN32_CHECK_LIB("dbgrid" wxmsw${_shortver}${_suffix}_dbgrid.lib wxmsw${_shortver}${_suffix}d_dbgrid.lib ${_libpath})
+ WIN32_CHECK_LIB("gl" wxmsw${_shortver}${_suffix}_gl.lib wxmsw${_shortver}${_suffix}d_gl.lib ${_libpath})
+ WIN32_CHECK_LIB("html" wxmsw${_shortver}${_suffix}_html.lib wxmsw${_shortver}${_suffix}d_html.lib ${_libpath})
+ WIN32_CHECK_LIB("media" wxmsw${_shortver}${_suffix}_media.lib wxmsw${_shortver}${_suffix}d_media.lib ${_libpath})
+ WIN32_CHECK_LIB("net" wxbase${_shortver}${_suffix}_net.lib wxbase${_shortver}${_suffix}d_net.lib ${_libpath})
+ WIN32_CHECK_LIB("odbc" wxbase${_shortver}${_suffix}_odbc.lib wxbase${_shortver}${_suffix}d_odbc.lib ${_libpath})
+ WIN32_CHECK_LIB("qa" wxmsw${_shortver}${_suffix}_qa.lib wxmsw${_shortver}${_suffix}d_qa.lib ${_libpath})
+ WIN32_CHECK_LIB("richtext" wxmsw${_shortver}${_suffix}_richtext.lib wxmsw${_shortver}${_suffix}d_richtext.lib ${_libpath})
+ WIN32_CHECK_LIB("xml" wxbase${_shortver}${_suffix}_xml.lib wxbase${_shortver}${_suffix}d_xml.lib ${_libpath})
+ WIN32_CHECK_LIB("xrc" wxmsw${_shortver}${_suffix}_xrc.lib wxmsw${_shortver}${_suffix}d_xrc.lib ${_libpath})
+
+ # Contribs
+ WIN32_CHECK_LIB("fl" wxmsw${_shortver}${_suffix}_fl.lib wxmsw${_shortver}${_suffix}d_fl.lib ${_libpath})
+ WIN32_CHECK_LIB("foldbar" wxmsw${_shortver}${_suffix}_foldbar.lib wxmsw${_shortver}${_suffix}d_foldbar.lib ${_libpath})
+ WIN32_CHECK_LIB("gizmos" wxmsw${_shortver}${_suffix}_gizmos.lib wxmsw${_shortver}${_suffix}d_gizmos.lib ${_libpath})
+ WIN32_CHECK_LIB("gizmos_xrc" wxmsw${_shortver}${_suffix}_gizmos_xrc.lib wxmsw${_shortver}${_suffix}d_gizmos_xrc.lib ${_libpath})
+ WIN32_CHECK_LIB("mmedia" wxmsw${_shortver}${_suffix}_mmedia.lib wxmsw${_shortver}${_suffix}d_mmedia.lib ${_libpath})
+ WIN32_CHECK_LIB("netutils" wxmsw${_shortver}${_suffix}_netutils.lib wxmsw${_shortver}${_suffix}d_netutils.lib ${_libpath})
+ WIN32_CHECK_LIB("ogl" wxmsw${_shortver}${_suffix}_ogl.lib wxmsw${_shortver}${_suffix}d_ogl.lib ${_libpath})
+ WIN32_CHECK_LIB("plot" wxmsw${_shortver}${_suffix}_plot.lib wxmsw${_shortver}${_suffix}d_plot.lib ${_libpath})
+ WIN32_CHECK_LIB("stc" wxmsw${_shortver}${_suffix}_stc.lib wxmsw${_shortver}${_suffix}d_stc.lib ${_libpath})
+ WIN32_CHECK_LIB("svg" wxmsw${_shortver}${_suffix}_svg.lib wxmsw${_shortver}${_suffix}d_svg.lib ${_libpath})
+
+ # Add some default libraries we'll need
+ LIST(APPEND WX_LIBRARIES "debug;wxexpatd.lib" "optimized;wxexpat.lib"
+ "debug;wxjpegd.lib" "optimized;wxjpeg.lib"
+ "debug;wxpngd.lib" "optimized;wxpng.lib"
+ "debug;wxregex${_suffix}d.lib" "optimized;wxregex${_suffix}.lib"
+ "debug;wxtiffd.lib" "optimized;wxtiff.lib"
+ "debug;wxzlibd.lib" "optimized;wxzlib.lib")
+ LIST(APPEND WX_LIBRARIES winmm comctl32 rpcrt4 wsock32)
+
+ # Preprocessor definitions
+ SET(${WX_DEFINITIONS} "-D__WXMSW__")
+
+ IF(_unicode)
+ SET(WX_DEFINITIONS "${WX_DEFINITIONS};-DUNICODE")
+ ENDIF(_unicode)
+
+ IF(NOT _static)
+ SET(WX_DEFINITIONS "${WX_DEFINITIONS};-DWXUSINGDLL")
+ ENDIF(NOT _static)
+
+ # Bail out if there was an error
+ IF(_error)
+ SET(WX_FOUND FALSE)
+ SET(WX_ROOT_DIR WX_ROOT_DIR-NO_FOUND)
+ SET(WX_VERSION_STRING "")
+ SET(WX_INCLUDE_DIRS "")
+ SET(WX_DEFINITIONS "")
+ SET(WX_LIBRARIES "")
+ SET(WX_LIBRARY_DIRS "")
+ IF(WX_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "The selected wxWidgets configuration (${_build_desc}) is not available.")
+ ELSE(WX_FIND_REQUIRED)
+ MESSAGE(STATUS "The selected wxWidgets configuration (${_build_desc}) is not available.")
+ ENDIF(WX_FIND_REQUIRED)
+ ENDIF(_error)
+
+ ELSE(NOT ${WX_VERSION_STRING} STREQUAL "")
+ SET(WX_FOUND FALSE)
+ SET(WX_ROOT_DIR WX_ROOT_DIR-NO_FOUND)
+ SET(WX_VERSION_STRING "")
+ IF(WX_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "No wxWidgets installation could be found.")
+ ELSE(WX_FIND_REQUIRED)
+ MESSAGE(STATUS "No wxWidgets installation could be found.")
+ ENDIF(WX_FIND_REQUIRED)
+ ENDIF(NOT ${WX_VERSION_STRING} STREQUAL "")
+
+# Unix-style
+ELSE(WIN32 AND NOT CYGWIN AND NOT MSYS)
+
+ # Set up the wx-config command line
+ SET(_args "--version=${_version} --debug=${_debug} --static=${_static} --unicode=${_unicode} ${_modules}")
+
+ IF(NOT $ENV{WXWIN} STREQUAL "")
+ FIND_PROGRAM(WX_CONFIG_PATH wx-config
+ PATH $ENV{WXWIN}/bin
+ DOC "Path to the wx-config executable"
+ NO_DEFAULT_PATH)
+ ELSE(NOT $ENV{WXWIN} STREQUAL "")
+ FIND_PROGRAM(WX_CONFIG_PATH wx-config
+ DOC "Path to the wx-config executable")
+ ENDIF(NOT $ENV{WXWIN} STREQUAL "")
+
+ EXEC_PROGRAM(${WX_CONFIG_PATH} ARGS ${_args} --version OUTPUT_VARIABLE WX_VERSION_STRING RETURN_VALUE _retval)
+
+ IF(_retval EQUAL 1)
+ SET(WX_FOUND FALSE)
+ SET(WX_ROOT_DIR WX_ROOT_DIR-NO_FOUND)
+ SET(WX_VERSION_STRING "")
+ IF(WX_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "The selected wxWidgets configuration (${_build_desc}) is not available.")
+ ELSE(WX_FIND_REQUIRED)
+ MESSAGE(STATUS "The selected wxWidgets configuration (${_build_desc}) is not available.")
+ ENDIF(WX_FIND_REQUIRED)
+ ENDIF(_retval EQUAL 1)
+
+ IF(NOT _retval)
+
+ SET(WX_FOUND TRUE)
+
+ # Strip the bin and pg_config from the path
+ GET_FILENAME_COMPONENT(WX_ROOT_DIR ${WX_CONFIG_PATH} PATH)
+ GET_FILENAME_COMPONENT(WX_ROOT_DIR ${WX_ROOT_DIR} PATH)
+
+ EXEC_PROGRAM(${WX_CONFIG_PATH} ARGS ${_args} --cppflags OUTPUT_VARIABLE _cppflags)
+ EXEC_PROGRAM(${WX_CONFIG_PATH} ARGS ${_args} --libs OUTPUT_VARIABLE _ldflags)
+
+ # Parse the compiler options
+ STRING(STRIP "${_cppflags}" WX_CPPFLAGS)
+ SEPARATE_ARGUMENTS(WX_CPPFLAGS)
+
+ # Get the definitions, and drop them from the flags
+ STRING(REGEX MATCHALL "-D[^;]+" WX_DEFINITIONS "${WX_CPPFLAGS}")
+ STRING(REGEX REPLACE "-D[^;]+(;|$)" "" WX_CPPFLAGS "${WX_CPPFLAGS}")
+
+ # Get the include dirs.
+ STRING(REGEX MATCHALL "-I[^;]+" WX_INCLUDE_DIRS "${WX_CPPFLAGS}")
+ STRING(REPLACE "-I" "" WX_INCLUDE_DIRS "${WX_INCLUDE_DIRS}")
+ STRING(REGEX REPLACE "-I[^;]+(;|$)" "" WX_CPPFLAGS "${WX_CPPFLAGS}")
+
+ # Parse the libraries
+ STRING(STRIP "${_ldflags}" WX_LIBRARIES)
+ SEPARATE_ARGUMENTS(WX_LIBRARIES)
+ STRING(REPLACE "-framework;" "-framework " WX_LIBRARIES "${WX_LIBRARIES}")
+ STRING(REPLACE "-arch;" "-arch " WX_LIBRARIES "${WX_LIBRARIES}")
+ STRING(REPLACE "-isysroot;" "-isysroot " WX_LIBRARIES "${WX_LIBRARIES}")
+
+ # extract linkdirs (-L) for rpath (i.e., LINK_DIRECTORIES)
+ STRING(REGEX MATCHALL "-L[^;]+" WX_LIBRARY_DIRS "${WX_LIBRARIES}")
+ STRING(REPLACE "-L" "" WX_LIBRARY_DIRS "${WX_LIBRARY_DIRS}")
+
+ ELSE(NOT _retval)
+ SET(WX_FOUND FALSE)
+ SET(WX_ROOT_DIR WX_ROOT_DIR-NO_FOUND)
+ SET(WX_VERSION_STRING "")
+ IF(WX_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "No wxWidgets installation could be found.")
+ ELSE(WX_FIND_REQUIRED)
+ MESSAGE(STATUS "No wxWidgets installation could be found.")
+ ENDIF(WX_FIND_REQUIRED)
+ ENDIF(NOT _retval)
+
+ENDIF(WIN32 AND NOT CYGWIN AND NOT MSYS)
553 connection.cpp
@@ -0,0 +1,553 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAgent - PostgreSQL Tools
+// $Id: connection.cpp 4875 2006-01-06 21:06:46Z dpage $
+// Copyright (C) 2002 - 2008, The pgAdmin Development Team
+// This software is released under the Artistic Licence
+//
+// connection.cpp - database connection
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "pgAgent.h"
+
+#include <wx/regex.h>
+#include <wx/tokenzr.h>
+
+DBconn *DBconn::primaryConn = NULL;
+wxString DBconn::basicConnectString;
+static wxMutex s_PoolLock;
+
+
+DBconn::DBconn(const wxString &connectString, const wxString &db)
+{
+ inUse = false;
+ next=0;
+ prev=0;
+ majorVersion=0;
+ minorVersion=0;
+ dbname = db;
+ connStr = connectString;
+
+ if (connectString.IsEmpty())
+ {
+ // This is a sql call to a local database.
+ // No connection string found. Use basicConnectString.
+ Connect(basicConnectString + wxT(" dbname=") + dbname);
+ }
+ else
+ {
+ Connect(connectString);
+ }
+}
+
+
+bool DBconn::Connect(const wxString &connectString)
+{
+ LogMessage(wxString::Format(_("Creating DB connection: %s"), connectString.c_str()), LOG_DEBUG);
+ wxCharBuffer cstrUTF=connectString.mb_str(wxConvUTF8);
+ conn=PQconnectdb(cstrUTF);
+ if (PQstatus(conn) != CONNECTION_OK)
+ {
+ lastError = wxString::FromAscii(PQerrorMessage(conn));
+ PQfinish(conn);
+ conn=0;
+ }
+ return IsValid();
+}
+
+
+DBconn::~DBconn()
+{
+ // clear a single connection
+ if (conn)
+ {
+ PQfinish(conn);
+ conn=0;
+ }
+}
+
+
+wxString DBconn::qtDbString(const wxString& value)
+{
+ wxString result = value;
+
+ result.Replace(wxT("\\"), wxT("\\\\"));
+ result.Replace(wxT("'"), wxT("''"));
+ result.Append(wxT("'"));
+
+ if (BackendMinimumVersion(8, 1))
+ {
+ if (result.Contains(wxT("\\")))
+ result.Prepend(wxT("E'"));
+ else
+ result.Prepend(wxT("'"));
+ }
+ else
+ result.Prepend(wxT("'"));
+
+ return result;
+}
+
+
+bool DBconn::BackendMinimumVersion(int major, int minor)
+{
+ if (!majorVersion)
+ {
+ wxString version=ExecuteScalar(wxT("SELECT version();")) ;
+ sscanf(version.ToAscii(), "%*s %d.%d", &majorVersion, &minorVersion);
+ }
+ return majorVersion > major || (majorVersion == major && minorVersion >= minor);
+}
+
+
+DBconn *DBconn::InitConnection(const wxString &connectString)
+{
+ wxMutexLocker lock(s_PoolLock);
+
+ basicConnectString=connectString;
+ wxString dbname;
+
+ connInfo cnInfo = connInfo::getConnectionInfo(connectString);
+ if (cnInfo.isValid)
+ {
+ dbname = cnInfo.dbname;
+ basicConnectString = cnInfo.getConnectionString();
+ primaryConn = new DBconn(cnInfo.getConnectionString(), dbname);
+
+ if (!primaryConn)
+ LogMessage(_("Failed to create primary connection!"), LOG_ERROR);
+ primaryConn->dbname = dbname;
+ primaryConn->inUse = true;
+ }
+ else
+ {
+ primaryConn = NULL;
+ LogMessage(wxT("Primary connection string is not valid!"), LOG_ERROR);
+ }
+
+ return primaryConn;
+}
+
+
+DBconn *DBconn::Get(const wxString &connStr, const wxString &db)
+{
+ if (db.IsEmpty() && connStr.IsEmpty())
+ {
+ LogMessage(_("Cannot allocate connection - no database or connection string specified!"), LOG_WARNING);
+ return NULL;
+ }
+
+ wxMutexLocker lock(s_PoolLock);
+
+ DBconn *thisConn = primaryConn, *lastConn;
+
+ // find an existing connection
+ do
+ {
+ if (thisConn && ((!db.IsEmpty() && db == thisConn->dbname && connStr.IsEmpty()) || (!connStr.IsEmpty() && connStr == thisConn->connStr)) && !thisConn->inUse)
+ {
+ LogMessage(wxString::Format(_("Allocating existing connection to database %s"), thisConn->dbname.c_str()), LOG_DEBUG);
+ thisConn->inUse = true;
+ return thisConn;
+ }
+
+ lastConn = thisConn;
+ thisConn = thisConn->next;
+
+ } while (thisConn != 0);
+
+
+ // No suitable connection was found, so create a new one.
+ DBconn *newConn = NULL;
+ newConn = new DBconn(connStr, db);
+
+ if (newConn->conn)
+ {
+ LogMessage(wxString::Format(_("Allocating new connection to database %s"), newConn->dbname.c_str()), LOG_DEBUG);
+ newConn->inUse = true;
+ newConn->prev = lastConn;
+ lastConn->next = newConn;
+ }
+ else
+ {
+ wxString warnMsg;
+ if (connStr.IsEmpty())
+ warnMsg = wxString::Format(_("Failed to create new connection to database '%s':'%s'"),
+ db.c_str(), newConn->GetLastError().c_str());
+ else
+ warnMsg = wxString::Format(_("Failed to create new connection for connection string '%s':%s"),
+ connStr.c_str(), newConn->GetLastError().c_str());
+ LogMessage(warnMsg, LOG_STARTUP);
+ return NULL;
+ }
+
+ return newConn;
+}
+
+
+void DBconn::Return()
+{
+ wxMutexLocker lock(s_PoolLock);
+
+ // Cleanup
+ this->ExecuteVoid(wxT("RESET ALL"));
+ this->lastError.Empty();
+
+ LogMessage(wxString::Format(_("Returning connection to database %s"), dbname.c_str()), LOG_DEBUG);
+ inUse = false;
+}
+
+
+void DBconn::ClearConnections(bool all)
+{
+ wxMutexLocker lock(s_PoolLock);
+
+ if (all)
+ LogMessage(_("Clearing all connections"), LOG_DEBUG);
+ else
+ LogMessage(_("Clearing inactive connections"), LOG_DEBUG);
+
+ DBconn *thisConn=primaryConn, *deleteConn;
+ int total=0, free=0, deleted=0;
+
+ if (thisConn)
+ {
+
+ total++;
+
+ // Find the last connection
+ while (thisConn->next != 0)
+ {
+ total++;
+
+ if (!thisConn->inUse)
+ free++;
+
+ thisConn = thisConn->next;
+ }
+ if (!thisConn->inUse)
+ free++;
+
+ // Delete connections as required
+ // If a connection is not in use, delete it, and reset the next and previous
+ // pointers appropriately. If it is in use, don't touch it.
+ while (thisConn->prev != 0)
+ {
+ if ((!thisConn->inUse) || all)
+ {
+ deleteConn = thisConn;
+ thisConn = deleteConn->prev;
+ thisConn->next = deleteConn->next;
+ if (deleteConn->next)
+ deleteConn->next->prev = deleteConn->prev;
+ delete deleteConn;
+ deleted++;
+ }
+ else
+ {
+ thisConn = thisConn->prev;
+ }
+ }
+
+ if (all)
+ {
+ delete thisConn;
+ deleted++;
+ }
+
+ wxString tmp;
+ tmp.Printf(_("Connection stats: total - %d, free - %d, deleted - %d"), total, free, deleted);
+ LogMessage(tmp, LOG_DEBUG);
+
+ }
+ else
+ LogMessage(_("No connections found!"), LOG_DEBUG);
+
+}
+
+
+DBresult *DBconn::Execute(const wxString &query)
+{
+ DBresult *res=new DBresult(this, query);
+ if (!res->IsValid())
+ {
+ // error handling here
+
+ delete res;
+ return 0;
+ }
+ return res;
+}
+
+
+wxString DBconn::ExecuteScalar(const wxString& query)
+{
+ int rows=-1;
+ DBresult *res=Execute(query);
+ wxString data;
+ if (res)
+ {
+ data=res->GetString(0);
+ rows = res->RowsAffected();
+ delete res;
+ return data;
+ }
+ return wxEmptyString;
+}
+
+
+int DBconn::ExecuteVoid(const wxString &query)
+{
+ int rows=-1;
+ DBresult *res=Execute(query);
+ if (res)
+ {
+ rows = res->RowsAffected();
+ delete res;
+ }
+ return rows;
+}
+
+
+wxString DBconn::GetLastError()
+{
+ // Return the last error message, minus any trailing line ends
+ if (lastError.substr(lastError.length()-2, 2) == wxT("\r\n")) // DOS
+ return lastError.substr(0, lastError.length()-2);
+ else if (lastError.substr(lastError.length()-1, 1) == wxT("\n")) // Unix
+ return lastError.substr(0, lastError.length()-1);
+ else if (lastError.substr(lastError.length()-1, 1) == wxT("\r")) // Mac
+ return lastError.substr(0, lastError.length()-1);
+ else
+ return lastError;
+}
+
+///////////////////////////////////////////////////////7
+
+DBresult::DBresult(DBconn *conn, const wxString &query)
+{
+ wxCharBuffer cstrUTF=query.mb_str(wxConvUTF8);
+ result=PQexec(conn->conn, cstrUTF);
+ currentRow=0;
+ maxRows=0;
+
+ if (result)
+ {
+ int rc=PQresultStatus(result);
+ if (rc == PGRES_TUPLES_OK)
+ maxRows = PQntuples(result);
+ else if (rc != PGRES_COMMAND_OK)
+ {
+ conn->lastError = wxString::FromAscii(PQerrorMessage(conn->conn));
+ LogMessage(wxT("Query error: ") + conn->lastError, LOG_WARNING);
+ PQclear(result);
+ result=0;
+ }
+ }
+ else
+ conn->lastError = wxString::FromAscii(PQerrorMessage(conn->conn));
+
+}
+
+
+DBresult::~DBresult()
+{
+ if (result)
+ PQclear(result);
+}
+
+
+wxString DBresult::GetString(int col) const
+{
+ wxString str;
+
+ if (result && currentRow < maxRows && col >= 0)
+ {
+ str = wxString::FromAscii(PQgetvalue(result, currentRow, col));
+ }
+ return str;
+}
+
+
+wxString DBresult::GetString(const wxString &colname) const
+{
+ wxCharBuffer cstrUTF=colname.mb_str(wxConvUTF8);
+ int col=PQfnumber(result, cstrUTF);
+ if (col < 0)
+ {
+ // fatal: not found
+ return wxT("");
+ }
+ return GetString(col);
+}
+
+///////////////////////////////////////////////////////7
+
+bool connInfo::IsValidIP()
+{
+ if (host.IsEmpty())
+ return false;
+
+ // check for IPv4 format
+ wxStringTokenizer tkip4(host, wxT("."));
+ int count = 0;
+
+ while (tkip4.HasMoreTokens())
+ {
+ unsigned long val = 0;
+ if (!tkip4.GetNextToken().ToULong(&val))
+ break;
+ if (count == 0 || count == 3)
+ if (val > 0 && val < 255)
+ count++;
+ else
+ break;
+ else if (val >= 0 && val < 255)
+ count++;
+ else
+ break;
+ }
+
+ if (count == 4)
+ return true;
+
+ // check for IPv6 format
+ wxStringTokenizer tkip6(host, wxT(":"));
+ count = 0;
+
+ while (tkip6.HasMoreTokens())
+ {
+ unsigned long val = 0;
+ wxString strVal = tkip6.GetNextToken();
+ if (strVal.Length() > 4 || !strVal.ToULong(&val, 16))
+ return false;
+ count++;
+ }
+ if (count <= 8)
+ return true;
+
+ // TODO:: We're not supporting mix mode (x:x:x:x:x:x:d.d.d.d)
+ // i.e. ::ffff:12.34.56.78
+ return false;
+}
+
+
+wxString connInfo::getConnectionString()
+{
+ wxString connStr;
+
+ // Check if it has valid connection info
+ if (!isValid)
+ return connStr;
+
+ // User
+ connStr = wxT("user=") + user;
+
+ // Port
+ if (port != 0)
+ {
+ wxString portStr;
+ portStr.Printf(wxT("%ld"), port);
+ connStr += wxT(" port=") + portStr;
+ }
+
+ // host or hostaddr
+ if (!host.IsEmpty())
+ if (IsValidIP())
+ connStr += wxT(" hostaddr=") + host;
+ else
+ connStr += wxT(" host=") + host;
+
+ // connection timeout
+ if (connection_timeout != 0)
+ {
+ wxString val;
+ val.Printf(wxT("%ld"), connection_timeout);
+ connStr += wxT(" connection_timeout=") + val;
+ }
+
+ // password
+ if (!password.IsEmpty())
+ connStr += wxT(" password=") + password;
+
+ if (!dbname.IsEmpty())
+ connStr += wxT(" dbname=") + dbname;
+
+ LogMessage(wxString::Format(_("Connection Information:")), LOG_DEBUG);
+ LogMessage(wxString::Format(_(" user : %s"), user.c_str()), LOG_DEBUG);
+ LogMessage(wxString::Format(_(" port : %ld"), port), LOG_DEBUG);
+ LogMessage(wxString::Format(_(" host : %s"), host.c_str()), LOG_DEBUG);
+ LogMessage(wxString::Format(_(" dbname : %s"), dbname.c_str()), LOG_DEBUG);
+ LogMessage(wxString::Format(_(" password : %s"), password.c_str()), LOG_DEBUG);
+ LogMessage(wxString::Format(_(" conn timeout : %ld"), connection_timeout), LOG_DEBUG);
+
+ return connStr;
+}
+
+
+connInfo connInfo::getConnectionInfo(wxString connStr)
+{
+ connInfo cnInfo;
+
+ wxRegEx propertyExp;
+
+ // Remove the white-space(s) to match the following format
+ // i.e. prop=value
+ bool res = propertyExp.Compile(wxT("(([ ]*[\t]*)+)="));
+
+ propertyExp.ReplaceAll(&connStr, wxT("="));
+
+ res = propertyExp.Compile(wxT("=(([ ]*[\t]*)+)"));
+ propertyExp.ReplaceAll(&connStr, wxT("="));
+
+ // Seperate all the prop=value patterns
+ wxArrayString tokens = wxStringTokenize(connStr, wxT("\t \n\r"));
+
+ unsigned int index = 0;
+ while (index < tokens.Count())
+ {
+ wxString prop, value;
+
+ wxArrayString pairs = wxStringTokenize(tokens[index++], wxT("="));
+
+ if (pairs.GetCount()!= 2)
+ return cnInfo;
+
+ prop=pairs[0];
+ value=pairs[1];
+
+ if (prop.CmpNoCase(wxT("user")) == 0)
+ cnInfo.user = value;
+ else if (prop.CmpNoCase(wxT("host")) == 0 || prop.CmpNoCase(wxT("hostAddr")) == 0)
+ cnInfo.host = value;
+ else if (prop.CmpNoCase(wxT("port")) == 0)
+ {
+ if (!value.ToULong(&cnInfo.port))
+ // port must be an unsigned integer
+ return cnInfo;
+ }
+ else if (prop.CmpNoCase(wxT("password")) == 0)
+ cnInfo.password = value;
+ else if (prop.CmpNoCase(wxT("connection_timeout")) == 0)
+ {
+ if (!value.ToULong(&cnInfo.connection_timeout))
+ // connection timeout must be an unsigned interger
+ return cnInfo;
+ }
+ else if (prop.CmpNoCase(wxT("dbname")) == 0)
+ cnInfo.dbname = value;
+ else
+ // Not valid property found
+ return cnInfo;
+ }
+
+ // If user, dbname & host all are blank than we will consider this an invalid connection string
+ if (cnInfo.user.IsEmpty() && cnInfo.dbname.IsEmpty() && cnInfo.host.IsEmpty())
+ cnInfo.isValid = false;
+ else
+ cnInfo.isValid = true;
+
+ return cnInfo;
+}
+
115 include/connection.h
@@ -0,0 +1,115 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAgent - PostgreSQL Tools
+// $Id$
+// Copyright (C) 2002 - 2008, The pgAdmin Development Team
+// This software is released under the Artistic Licence
+//
+// connection.h - database connection
+//
+//////////////////////////////////////////////////////////////////////////
+
+
+#ifndef CONNECTION_H
+#define CONNECTION_H
+
+#include <libpq-fe.h>
+
+class DBresult;
+
+
+class DBconn
+{
+protected:
+ DBconn(const wxString &, const wxString&);
+ ~DBconn();
+
+public:
+ wxString qtDbString(const wxString& value);
+
+ bool BackendMinimumVersion(int major, int minor);
+
+ static DBconn *Get(const wxString &connStr, const wxString &db);
+ static DBconn *InitConnection(const wxString &connectString);
+
+ static void ClearConnections(bool allIncludingPrimary=false);
+ static void SetBasicConnectString(const wxString &bcs) { basicConnectString = bcs; }
+ static const wxString& GetBasicConnectString() { return basicConnectString; }
+
+ wxString GetLastError();
+ wxString GetDBname() { return dbname; }
+ bool IsValid() { return conn != 0; }
+
+ DBresult *Execute(const wxString &query);
+ wxString ExecuteScalar(const wxString &query);
+ int ExecuteVoid(const wxString &query);
+ void Return();
+
+private:
+ bool Connect(const wxString &connectString);
+
+ int minorVersion, majorVersion;
+
+protected:
+ static wxString basicConnectString;
+ static DBconn *primaryConn;
+
+ wxString dbname, lastError, connStr;
+ PGconn *conn;
+ DBconn *next, *prev;
+ bool inUse;
+
+ friend class DBresult;
+
+};
+
+
+class DBresult
+{
+protected:
+ DBresult(DBconn *conn, const wxString &query);
+
+public:
+ ~DBresult();
+
+ wxString GetString(int col) const;
+ wxString GetString(const wxString &colname) const;
+
+ bool IsValid() const { return result != NULL; }
+ bool HasData() const { return currentRow < maxRows; }
+ void MoveNext() { if (currentRow < maxRows) currentRow++; }
+
+ long RowsAffected() const { return atol(PQcmdTuples(result)); }
+
+protected:
+ PGresult *result;
+ int currentRow, maxRows;
+
+ friend class DBconn;
+};
+
+
+class connInfo
+{
+public:
+ connInfo() { isValid = false; connection_timeout = 0; port = 0; }
+
+private:
+ wxString user;
+ unsigned long port;
+ wxString host;
+ wxString dbname;
+ unsigned long connection_timeout;
+ wxString password;
+ bool isValid;
+
+ wxString getConnectionString();
+ static connInfo getConnectionInfo(wxString connStr);
+
+protected:
+ bool IsValidIP();
+ friend class DBconn;
+};
+
+#endif // CONNECTION_H
+
51 include/job.h
@@ -0,0 +1,51 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAgent - PostgreSQL Tools
+// $Id$
+// Copyright (C) 2002 - 2009, The pgAdmin Development Team
+// This software is released under the Artistic Licence
+//
+// job.h - agent job
+//
+//////////////////////////////////////////////////////////////////////////
+
+
+#ifndef JOB_H
+#define JOB_H
+
+#include <wx/wx.h>
+
+
+class Job
+{
+public:
+ Job(DBconn *conn, const wxString &jid);
+ ~Job();
+
+ int Execute();
+ bool Runnable() { return status == wxT("r"); }
+
+protected:
+ DBconn *threadConn;
+ wxString jobid, logid;
+ wxString status;
+};
+
+
+class JobThread : public wxThread
+{
+public:
+ JobThread(const wxString &jid);
+ ~JobThread();
+ bool Runnable() { return runnable; }
+
+ virtual void *Entry();
+
+private:
+ wxString jobid;
+ bool runnable;
+ Job *job;
+};
+
+#endif // JOB_H
+
23 include/misc.h
@@ -0,0 +1,23 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAgent - PostgreSQL Tools
+// $Id$
+// Copyright (C) 2002 - 2008, The pgAdmin Development Team
+// This software is released under the Artistic Licence
+//
+// misc.h - misc functions
+//
+//////////////////////////////////////////////////////////////////////////
+
+
+#ifndef MISC_H
+#define MISC_H
+
+
+void WaitAWhile(const bool waitLong=false);
+void setOptions(int argc, char **argv, const wxString& executable);
+wxString getArg(int &argc, char** &argv);
+wxString NumToStr(const long l);
+
+#endif // MISC_H
+
61 include/pgAgent.h
@@ -0,0 +1,61 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAgent - PostgreSQL Tools
+// $Id$
+// Copyright (C) 2002 - 2008, The pgAdmin Development Team
+// This software is released under the Artistic Licence
+//
+// pgAgent.h - main include
+//
+//////////////////////////////////////////////////////////////////////////
+
+
+#ifndef PGAGENT_H
+#define PGAGENT_H
+
+// Disable all the GUI classes that might get pulled in through the headers
+#define wxUSE_GUI 0
+
+#include <wx/wx.h>
+
+#include "misc.h"
+#include "connection.h"
+#include "job.h"
+
+extern long longWait;
+extern long shortWait;
+extern long minLogLevel;
+extern wxString connectString;
+extern wxString serviceDBname;
+extern wxString backendPid;
+
+#ifndef __WXMSW__
+extern bool runInForeground;
+extern wxString logFile;
+#endif
+
+// Log levels
+enum
+{
+ LOG_ERROR = 0,
+ LOG_WARNING,
+ LOG_DEBUG,
+ // NOTE:
+ // "STARTUP" will be used to log messages for any LogLevel
+ // Use it for logging database connection errors which we
+ // don't want to abort the whole shebang.
+ LOG_STARTUP = 15
+};
+
+// Prototypes
+void LogMessage(wxString msg, int level);
+void MainLoop();
+
+#ifdef __WIN32__
+#include <windows.h>
+void CheckForInterrupt();
+HANDLE win32_popen_r(const TCHAR *command);
+#endif
+
+#endif // PGAGENT_H
+
BIN include/pgAgent.ico
Binary file not shown.
374 job.cpp
@@ -0,0 +1,374 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAgent - PostgreSQL Tools
+// $Id: job.cpp 4875 2006-01-06 21:06:46Z dpage $
+// Copyright (C) 2002 - 2009 The pgAdmin Development Team
+// This software is released under the Artistic Licence
+//
+// job.cpp - pgAgent job
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "pgAgent.h"
+
+#include <wx/file.h>
+#include <wx/filefn.h>
+#include <wx/filename.h>
+#include <wx/process.h>
+
+#ifndef __WIN32__
+#include <errno.h>
+#endif
+
+Job::Job(DBconn *conn, const wxString &jid)
+{
+ threadConn=conn;
+ jobid=jid;
+ status=wxT("");
+
+ LogMessage(wxString::Format(_("Starting job: %s"), jobid.c_str()), LOG_DEBUG);
+
+ int rc=threadConn->ExecuteVoid(
+ wxT("UPDATE pgagent.pga_job SET jobagentid=") + backendPid + wxT(", joblastrun=now() ")
+ wxT(" WHERE jobagentid IS NULL AND jobid=") + jobid);
+
+ if (rc == 1)
+ {
+ DBresult *id=threadConn->Execute(
+ wxT("SELECT nextval('pgagent.pga_joblog_jlgid_seq') AS id"));
+ if (id)
+ {
+ logid=id->GetString(wxT("id"));
+
+ DBresult *res=threadConn->Execute(
+ wxT("INSERT INTO pgagent.pga_joblog(jlgid, jlgjobid, jlgstatus) ")
+ wxT("VALUES (") + logid + wxT(", ") + jobid + wxT(", 'r')"));
+ if (res)
+ {
+ status=wxT("r");
+ delete res;
+ }
+ delete id;
+ }
+ }
+}
+
+
+Job::~Job()
+{
+ if (status != wxT(""))
+ {
+ threadConn->ExecuteVoid(
+ wxT("UPDATE pgagent.pga_joblog ")
+ wxT(" SET jlgstatus='") + status + wxT("', jlgduration=now() - jlgstart ")
+ wxT(" WHERE jlgid=") + logid + wxT(";\n")
+
+ wxT("UPDATE pgagent.pga_job ")
+ wxT(" SET jobagentid=NULL, jobnextrun=NULL ")
+ wxT(" WHERE jobid=") + jobid
+ );
+ }
+ threadConn->Return();
+
+ LogMessage(wxString::Format(_("Completed job: %s"), jobid.c_str()), LOG_DEBUG);
+}
+
+
+int Job::Execute()
+{
+ int rc=0;
+ DBresult *steps=threadConn->Execute(
+ wxT("SELECT * ")
+ wxT(" FROM pgagent.pga_jobstep ")
+ wxT(" WHERE jstenabled ")
+ wxT(" AND jstjobid=") + jobid +
+ wxT(" ORDER BY jstname, jstid"));
+
+ if (!steps)
+ {
+ status=wxT("i");
+ return -1;
+ }
+
+ while (steps->HasData())
+ {
+ DBconn *stepConn;
+ wxString jslid, stepid, jpecode, output;
+
+ stepid = steps->GetString(wxT("jstid"));
+
+ DBresult *id=threadConn->Execute(
+ wxT("SELECT nextval('pgagent.pga_jobsteplog_jslid_seq') AS id"));
+ if (id)
+ {
+ jslid=id->GetString(wxT("id"));
+ DBresult *res=threadConn->Execute(
+ wxT("INSERT INTO pgagent.pga_jobsteplog(jslid, jsljlgid, jsljstid, jslstatus) ")
+ wxT("SELECT ") + jslid + wxT(", ") + logid + wxT(", ") + stepid + wxT(", 'r'")
+ wxT(" FROM pgagent.pga_jobstep WHERE jstid=") + stepid);
+
+ if (res)
+ {
+ rc=res->RowsAffected();
+ delete res;
+ }
+ else
+ rc = -1;
+ }
+ delete id;
+
+ if (rc != 1)
+ {
+ status=wxT("i");
+ return -1;
+ }
+
+ switch ((int) steps->GetString(wxT("jstkind"))[0])
+ {
+ case 's':
+ {
+ wxString jstdbname = steps->GetString(wxT("jstdbname"));
+ wxString jstconnstr = steps->GetString(wxT("jstconnstr"));
+
+ stepConn=DBconn::Get(jstconnstr, jstdbname);
+ if (stepConn)
+ {
+ LogMessage(wxString::Format(_("Executing SQL step %s (part of job %s)"), stepid.c_str(), jobid.c_str()), LOG_DEBUG);
+ rc=stepConn->ExecuteVoid(steps->GetString(wxT("jstcode")));
+ output = stepConn->GetLastError();
+ stepConn->Return();
+ }
+ else
+ {
+ output = _("Couldn't get a connection to the database!");
+ rc=-1;
+ }
+
+
+ break;
+ }
+ case 'b':
+ {
+ // Batch jobs are more complex thank SQL, for obvious reasons...
+ LogMessage(wxString::Format(_("Executing batch step %s (part of job %s)"), stepid.c_str(), jobid.c_str()), LOG_DEBUG);
+
+ // Get a temporary filename, then reuse it to create an empty directory.
+ wxString dirname = wxFileName::CreateTempFileName(wxT("pga_"));
+ if (dirname.Length() == 0)
+ {
+ output = _("Couldn't get a temporary filename!");
+ LogMessage(_("Couldn't get a temporary filename!"), LOG_WARNING);
+ rc=-1;
+ break;
+ }
+
+ ;
+ if (!wxRemoveFile(dirname))
+ {
+ output.Printf(_("Couldn't remove temporary file: %s"), dirname.c_str());
+ LogMessage(output, LOG_WARNING);
+ rc=-1;
+ break;
+ }
+
+ if (!wxMkdir(dirname, 0700))
+ {
+ output.Printf(_("Couldn't create temporary directory: %s"), dirname.c_str());
+ LogMessage(output, LOG_WARNING);
+ rc=-1;
+ break;
+ }
+
+#ifdef __WIN32__
+ wxString filename = dirname + wxT("\\") + jobid + wxT("_") + stepid + wxT(".bat");
+#else
+ wxString filename = dirname + wxT("/") + jobid + wxT("_") + stepid + wxT(".scr");
+#endif
+
+ // Write the script
+ wxFile *file = new wxFile();
+
+ if (!file->Create(filename, true, wxS_IRUSR | wxS_IWUSR | wxS_IXUSR))
+ {
+ output.Printf(_("Couldn't create temporary script file: %s"), filename.c_str());
+ LogMessage(output, LOG_WARNING);
+ rc=-1;
+ break;
+ }
+
+ if (!file->Open(filename, wxFile::write))
+ {
+ output.Printf(_("Couldn't open temporary script file: %s"), filename.c_str());
+ LogMessage(output, LOG_WARNING);
+ wxRemoveFile(filename);
+ wxRmdir(dirname);
+ rc=-1;
+ break;
+ }
+
+ wxString code = steps->GetString(wxT("jstcode"));
+
+ // Cleanup the code. If we're on Windows, we need to make all line ends \r\n,
+ // If we're on Unix, we need \n
+ code.Replace(wxT("\r\n"), wxT("\n"));
+#ifdef __WIN32__
+ code.Replace(wxT("\n"), wxT("\r\n"));
+#endif
+
+ if (!file->Write(code))
+ {
+ output.Printf(_("Couldn't write to temporary script file: %s"), filename.c_str());
+ LogMessage(output, LOG_WARNING);
+ wxRemoveFile(filename);
+ wxRmdir(dirname);
+ rc=-1;
+ break;
+ }
+
+ file->Close();
+ LogMessage(wxString::Format(_("Executing script file: %s"), filename.c_str()), LOG_DEBUG);
+
+ // Execute the file and capture the output
+#ifdef __WIN32__
+ // The Windows way
+ HANDLE h_script;
+ DWORD dwRead;
+ char chBuf[4098];
+
+ h_script = win32_popen_r(filename.wc_str());
+ if (!h_script)
+ {
+ output.Printf(_("Couldn't execute script: %s, GetLastError() returned %d, errno = %d"), filename.c_str(), GetLastError(), errno);
+ LogMessage(output, LOG_WARNING);
+ rc=-1;
+ break;
+ }
+
+
+ // Read output from the child process
+ if (h_script)
+ {
+ for (;;)
+ {
+ if(!ReadFile(h_script, chBuf, 4096, &dwRead, NULL) || dwRead == 0)
+ break;
+
+ chBuf[dwRead] = 0;
+ output += wxString::FromAscii(chBuf);
+ }
+ }
+
+
+ CloseHandle(h_script);
+ rc=1;
+
+#else
+ // The *nix way.
+ FILE *fp_script;
+ char buf[4098];
+
+ fp_script = popen(filename.mb_str(wxConvUTF8), "r");
+ if (!fp_script)
+ {
+ output.Printf(_("Couldn't execute script: %s, errno = %d"), filename.c_str(), errno);
+ LogMessage(output, LOG_WARNING);
+ rc=-1;
+ break;
+ }
+
+
+ while(!feof(fp_script))
+ {
+ if (fgets(buf, 4096, fp_script) != NULL)
+ output += wxString::FromAscii(buf);
+ }
+
+ rc=pclose(fp_script);
+ rc = (unsigned char)(rc >> 8); // The exit code is in the top 8 bits
+ rc = (signed char)rc;
+#endif
+
+ // Delete the file/directory. If we fail, don't overwrite the script output in the log, just throw warnings.
+ if (!wxRemoveFile(filename))
+ {
+ LogMessage(wxString::Format(_("Couldn't remove temporary script file: %s"), filename.c_str()), LOG_WARNING);
+ wxRmdir(dirname);
+ break;
+ }
+
+ if (!wxRmdir(dirname))
+ {
+ LogMessage(wxString::Format(_("Couldn't remove temporary directory: "), dirname.c_str()), LOG_WARNING);
+ break;
+ }
+
+ break;
+ }
+ default:
+ {
+ output = _("Invalid step type!");
+ status=wxT("i");
+ return -1;
+ }
+ }
+
+ wxString stepstatus;
+ if (rc >= 0)
+ stepstatus = wxT("s");
+ else
+ stepstatus = steps->GetString(wxT("jstonerror"));
+
+ rc=threadConn->ExecuteVoid(
+ wxT("UPDATE pgagent.pga_jobsteplog ")
+ wxT(" SET jslduration = now() - jslstart, ")
+ wxT(" jslresult = ") + NumToStr(rc) + wxT(", jslstatus = '") + stepstatus + wxT("', ")
+ wxT(" jsloutput = ") + threadConn->qtDbString(output) + wxT(" ")
+ wxT(" WHERE jslid=") + jslid);
+ if (rc != 1 || stepstatus == wxT("f"))
+ {
+ status = wxT("f");
+ return -1;
+ }
+ steps->MoveNext();
+ }
+ delete steps;
+
+ status = wxT("s");
+ return 0;
+}
+
+
+
+JobThread::JobThread(const wxString &jid)
+: wxThread(wxTHREAD_DETACHED)
+{
+ LogMessage(wxString::Format(_("Creating job thread for job %s"), jid.c_str()), LOG_DEBUG);
+
+ runnable = false;
+ jobid = jid;
+
+ DBconn *threadConn=DBconn::Get(DBconn::GetBasicConnectString(), serviceDBname);
+ job = new Job(threadConn, jobid);
+
+ if (job->Runnable())
+ runnable = true;
+
+}
+
+
+JobThread::~JobThread()
+{
+ LogMessage(wxString::Format(_("Destroying job thread for job %s"), jobid.c_str()), LOG_DEBUG);
+}
+
+
+void *JobThread::Entry()
+{
+ if (runnable)
+ {
+ job->Execute();
+ delete job;
+ }
+
+ return(NULL);
+}
134 misc.cpp
@@ -0,0 +1,134 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAgent - PostgreSQL Tools
+// $Id: misc.cpp 5013 2006-02-21 09:39:15Z dpage $
+// Copyright (C) 2002 - 2008 The pgAdmin Development Team
+// This software is released under the Artistic Licence
+//
+// misc.cpp - misc functions
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "pgAgent.h"
+#include "connection.h"
+
+#ifndef __WXMSW__
+#include <unistd.h>
+#endif
+
+// In unix.c or win32.c
+void usage(const wxString& executable);
+
+wxString getArg(int &argc, char** &argv)
+{
+ wxString s;
+ if (argv[0][2])
+ s = wxString::FromAscii(argv[0] +2);
+ else
+ {
+ if (argc >= 1)
+ {
+ argc--;
+ argv++;
+ s = wxString::FromAscii(argv[0]);
+ }
+ else
+ {
+ // very bad!
+ LogMessage(_("Invalid command line argument"), LOG_ERROR);
+ }
+ }
+
+ return s;
+}
+
+
+void setOptions(int argc, char **argv, const wxString& executable)
+{
+ while (argc-- > 0)
+ {
+ if (argv[0][0] == '-')
+ {
+ switch (argv[0][1])
+ {
+ case 't':
+ {
+ int val = atoi(getArg(argc, argv).mb_str(wxConvUTF8));
+ if (val > 0)
+ shortWait = val;
+ break;
+ }
+ case 'r':
+ {
+ int val = atoi(getArg(argc, argv).mb_str(wxConvUTF8));
+ if (val >= 10)
+ longWait = val;
+ break;
+ }
+ case 'l':
+ {
+ int val = atoi(getArg(argc, argv).mb_str(wxConvUTF8));
+ if (val >= 0 && val <= 2)
+ minLogLevel = val;
+ break;
+ }
+#ifndef __WXMSW__
+ case 'f':
+ {
+ runInForeground = true;
+ break;
+ }
+ case 's':
+ {
+ logFile = getArg(argc, argv);
+ break;
+ }
+#endif
+ default:
+ {
+ usage(executable);
+ exit(1);
+ }
+ }
+ }
+ else
+ {
+ if (connectString != wxT(""))
+ connectString += wxT(" ");
+ connectString += wxString::FromAscii(*argv);
+ if (**argv == '"')
+ connectString = connectString.substr(1, connectString.length()-2);
+ }
+ argv++;
+ }
+}
+
+
+void WaitAWhile(const bool waitLong)
+{
+ int count;
+ if (waitLong)
+ count=longWait;
+ else
+ count=shortWait;
+
+ while (count--)
+ {
+#ifdef WIN32
+ CheckForInterrupt();
+ Sleep(1000);
+#else
+ sleep(1);
+#endif
+ }
+}
+
+
+
+wxString NumToStr(const long l)
+{
+ wxString buf;
+ buf.Printf(wxT("%ld"), l);
+ return buf;
+}
+
219 pgAgent.cpp
@@ -0,0 +1,219 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAgent - PostgreSQL Tools
+// $Id: pgAgent.cpp 4875 2006-01-06 21:06:46Z dpage $
+// Copyright (C) 2002 - 2008, The pgAdmin Development Team
+// This software is released under the Artistic Licence
+//
+// pgAgent.cpp - pgAgent main entry
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "pgAgent.h"
+
+#ifndef __WXMSW__
+#include <unistd.h>
+#endif
+
+wxString connectString;
+wxString serviceDBname;
+wxString backendPid;
+long longWait=30;
+long shortWait=5;
+long minLogLevel=LOG_ERROR;
+
+#define MAXATTEMPTS 10
+
+#ifndef __WXMSW__
+bool runInForeground = false;
+wxString logFile = wxEmptyString;
+#else
+//pgAgent Initialized
+void Initialized();
+#endif
+
+int MainRestartLoop(DBconn *serviceConn)
+{
+ // clean up old jobs
+
+ int rc;
+
+ LogMessage(_("Clearing zombies"), LOG_DEBUG);
+ rc=serviceConn->ExecuteVoid(wxT("CREATE TEMP TABLE pga_tmp_zombies(jagpid int4)"));
+
+ rc = serviceConn->ExecuteVoid(
+ wxT("INSERT INTO pga_tmp_zombies (jagpid) ")
+ wxT("SELECT jagpid ")
+ wxT(" FROM pgagent.pga_jobagent AG ")
+ wxT(" LEFT JOIN pg_stat_activity PA ON jagpid=procpid ")
+ wxT(" WHERE procpid IS NULL")
+ );
+
+ if (rc > 0)
+ {
+ // There are orphaned agent entries
+ // mark the jobs as aborted
+ rc=serviceConn->ExecuteVoid(
+ wxT("UPDATE pgagent.pga_joblog SET jlgstatus='d' WHERE jlgid IN (")
+ wxT("SELECT jlgid ")
+ wxT("FROM pga_tmp_zombies z, pgagent.pga_job j, pgagent.pga_joblog l ")
+ wxT("WHERE z.jagpid=j.jobagentid AND j.jobid = l.jlgjobid AND l.jlgstatus='r');\n")
+
+ wxT("UPDATE pgagent.pga_jobsteplog SET jslstatus='d' WHERE jslid IN ( ")
+ wxT("SELECT jslid ")
+ wxT("FROM pga_tmp_zombies z, pgagent.pga_job j, pgagent.pga_joblog l, pgagent.pga_jobsteplog s ")
+ wxT("WHERE z.jagpid=j.jobagentid AND j.jobid = l.jlgjobid AND l.jlgid = s.jsljlgid AND s.jslstatus='r');\n")
+
+ wxT("UPDATE pgagent.pga_job SET jobagentid=NULL, jobnextrun=NULL ")
+ wxT(" WHERE jobagentid IN (SELECT jagpid FROM pga_tmp_zombies);\n")
+
+ wxT("DELETE FROM pgagent.pga_jobagent ")
+ wxT(" WHERE jagpid IN (SELECT jagpid FROM pga_tmp_zombies);\n")
+ );
+ }
+
+ rc=serviceConn->ExecuteVoid(wxT("DROP TABLE pga_tmp_zombies"));
+
+ wxString hostname = wxGetFullHostName();
+
+ rc=serviceConn->ExecuteVoid(
+ wxT("INSERT INTO pgagent.pga_jobagent (jagpid, jagstation) SELECT pg_backend_pid(), '") + hostname + wxT("'"));
+ if (rc < 0)
+ return rc;
+
+ while (1)
+ {
+ bool foundJobToExecute=false;
+
+ LogMessage(_("Checking for jobs to run"), LOG_DEBUG);
+ DBresult *res=serviceConn->Execute(
+ wxT("SELECT J.jobid ")
+ wxT(" FROM pgagent.pga_job J ")
+ wxT(" WHERE jobenabled ")
+ wxT(" AND jobagentid IS NULL ")
+ wxT(" AND jobnextrun <= now() ")
+ wxT(" AND (jobhostagent = '' OR jobhostagent = '") + hostname + wxT("')")
+ wxT(" ORDER BY jobnextrun"));
+
+ if (res)
+ {
+ while(res->HasData())
+ {
+ wxString jobid=res->GetString(wxT("jobid"));
+
+ JobThread *jt = new JobThread(jobid);
+
+ if (jt->Runnable())
+ {
+ jt->Create();
+ jt->Run();
+ foundJobToExecute = true;
+ }
+ res->MoveNext();
+
+ }
+
+ delete res;
+ LogMessage(_("Sleeping..."), LOG_DEBUG);
+ WaitAWhile();
+ }
+ else
+ {
+ LogMessage(_("Failed to query jobs table!"), LOG_ERROR);
+ }
+ if (!foundJobToExecute)
+ DBconn::ClearConnections();
+ }
+ return 0;
+}
+
+
+void MainLoop()
+{
+ int attemptCount = 1;
+
+ // OK, let's get down to business
+ do
+ {
+ LogMessage(_("Creating primary connection"), LOG_DEBUG);
+ DBconn *serviceConn=DBconn::InitConnection(connectString);
+
+ if (serviceConn && serviceConn->IsValid())
+ {
+ serviceDBname = serviceConn->GetDBname();
+
+ // Basic sanity check, and a chance to get the serviceConn's PID
+ LogMessage(_("Database sanity check"), LOG_DEBUG);
+ DBresult *res=serviceConn->Execute(wxT("SELECT count(*) As count, pg_backend_pid() AS pid FROM pg_class cl JOIN pg_namespace ns ON ns.oid=relnamespace WHERE relname='pga_job' AND nspname='pgagent'"));
+ if (res)
+ {
+ wxString val=res->GetString(wxT("count"));
+
+ if (val == wxT("0"))
+ LogMessage(_("Could not find the table 'pgagent.pga_job'. Have you run pgagent.sql on this database?"), LOG_ERROR);
+
+ backendPid=res->GetString(wxT("pid"));
+
+ delete res;
+ res = NULL;
+ }
+
+ // Check for particular version
+
+ bool hasSchemaVerFunc = false;
+ wxString sqlCheckSchemaVersion
+ = wxT("SELECT COUNT(*) ")\
+ wxT("FROM pg_proc ")\
+ wxT("WHERE proname = 'pgagent_schema_version' AND ")\
+ wxT(" pronamespace = (SELECT oid ")\
+ wxT(" FROM pg_namespace ")\
+ wxT(" WHERE nspname = 'pgagent') AND ")\
+ wxT(" prorettype = (SELECT oid ")\
+ wxT(" FROM pg_type ")\
+ wxT(" WHERE typname = 'int2') AND ")\
+ wxT(" proargtypes = '' ");
+
+ res = serviceConn->Execute(sqlCheckSchemaVersion);
+
+ if (res)
+ {
+ if (res->IsValid() && res->GetString(0) == wxT("1"))
+ hasSchemaVerFunc = true;
+ delete res;
+ res = NULL;
+ }
+
+ if (!hasSchemaVerFunc)
+ {
+ LogMessage(_("Couldn't find the function 'pgagent_schema_version' - please run pgagent_upgrade.sql."), LOG_ERROR);
+ }
+
+ wxString strPgAgentSchemaVer= serviceConn->ExecuteScalar(wxT("SELECT pgagent.pgagent_schema_version()"));
+ wxString currentPgAgentVersion;
+ currentPgAgentVersion.Printf(_("%d"), PGAGENT_VERSION_MAJOR);
+ if (strPgAgentSchemaVer != currentPgAgentVersion)
+ {
+ wxString strSchemaVerMisMatch;
+ strSchemaVerMisMatch.Printf(_("Unsupported schema version: %d. Version %d is required - please run pgagent_upgrade.sql."), strPgAgentSchemaVer.c_str(), currentPgAgentVersion.c_str());
+ LogMessage(strSchemaVerMisMatch, LOG_ERROR);
+ }
+
+#ifdef WIN32
+ Initialized();
+#endif
+ MainRestartLoop(serviceConn);
+ }
+
+ LogMessage(wxString::Format(_("Couldn't create the primary connection (attempt %d): %s"), attemptCount, serviceConn->GetLastError().c_str()), LOG_STARTUP);
+ DBconn::ClearConnections(true);
+
+ // Try establishing primary connection upto MAXATTEMPTS times
+ if (attemptCount++ >= (int)MAXATTEMPTS)
+ {
+ LogMessage(wxString::Format(_("Stopping pgAgent: Couldn't establish the primary connection with the database server.")), LOG_ERROR);
+ }
+ WaitAWhile();
+ }
+ while (1);
+}
+
45 pgAgent.rc
@@ -0,0 +1,45 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAgent - PostgreSQL Tools
+// $Id$
+// Copyright (C) 2002 - 2009, The pgAdmin Development Team
+// This software is released under the Artistic Licence
+//
+// pgAgent.rc - win32 Resources
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include <winver.h>
+
+// Icon (Don't remove the aaa prefix - it makes it the default icon)
+aaaPGAGENT ICON DISCARDABLE "include/pgAgent.ico"
+
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION 3,0,0,0
+PRODUCTVERSION 3,0,0,0
+FILEOS VOS__WINDOWS32
+FILETYPE VFT_APP
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "FileVersion", "3.0.0", "\0"
+ VALUE "File Version", "3.0.0", "\0"
+ VALUE "FileDescription", "pgAgent - PostgreSQL Scheduling Agent", "\0"
+ VALUE "LegalCopyright", "\251 2002 - 2009, The pgAdmin Development Team", "\0"
+ VALUE "LegalTrademarks", "This software is released under the Artistic License.", "\0"
+ VALUE "InternalName", "pgAgent", "\0"
+ VALUE "OriginalFilename","pgagent.exe", "\0"
+ VALUE "ProductName", "pgAgent", "\0"
+ VALUE "ProductVersion", "3.0.0", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 0x04E4
+ END
+END
+
+
22 pgaevent/CMakeLists.txt
@@ -0,0 +1,22 @@
+#######################################################################
+#
+# pgAgent - PostgreSQL tools
+# Copyright (C) 2002 - 2009, The pgAdmin Development Team
+# This software is released under the Artistic Licence
+#
+# pgaevent/CMakeLists.txt - CMake build configuration
+#
+#######################################################################
+
+################################################################################
+# Let's rock!
+################################################################################
+IF(WIN32)
+ SET(_srcs pgaevent.c pgaevent.def pgamsgevent.rc)
+
+ ADD_LIBRARY(pgaevent MODULE ${_srcs})
+
+ INSTALL(TARGETS pgaevent DESTINATION .)
+ENDIF(WIN32)
+
+
BIN pgaevent/MSG00001.bin
Binary file not shown.
17 pgaevent/README
@@ -0,0 +1,17 @@
+This whole directory is shamelessly adapted from PostgreSQL's src/bin/pgevent
+
+Note that to get the version resources etc. into the DLL, the only file
+generated by MC that we actually use is MSG00001.bin.
+
+-------------------------------------------------------------------------------
+
+MSG000001.bin is a binary file, result of Microsoft MC compiler. MC compiler
+can be downloaded for free with MS Core SDK but it is not included with MSYS
+tools and I didn't find an alternative way to compile MC file.
+
+To summarize: the command "MC pgmsgevent.mc" generates pgmsgevent.h,
+pgmsgevent.rc, and MSG00001.bin files. In MC file, we declare a string
+with %s format, so we can write anything we want in the future without
+needing to change the definition of this string.
+
+Laurent Ballester
29 pgaevent/pgaevent.c
@@ -0,0 +1,29 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAgent - PostgreSQL Tools
+// RCS-ID: $Id: pgaevent.c 4875 2006-01-06 21:06:46Z dpage $
+// Copyright (C) 2002 - 2009, The pgAdmin Development Team
+// This software is released under the Artistic Licence
+//
+// pgaevent.c - win32 message format dll
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include <windows.h>
+#include <olectl.h>
+#include <string.h>
+
+HANDLE g_module = NULL;
+
+BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved);
+
+//
+// DllMain --- is an optional entry point into a DLL.
+//
+BOOL WINAPI
+DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
+{
+ if (ul_reason_for_call == DLL_PROCESS_ATTACH)
+ g_module = hModule;
+ return TRUE;
+}