pax_global_header00006660000000000000000000000064141200617420014507gustar00rootroot0000000000000052 comment=40cfda95b3a8768ba96cbb86ef00a6a45097726f pgagent-REL-4_2_2/000077500000000000000000000000001412006174200137235ustar00rootroot00000000000000pgagent-REL-4_2_2/.gitignore000066400000000000000000000006171412006174200157170ustar00rootroot00000000000000.idea CMakeCache.txt CMakeFiles/ CPackConfig.cmake CPackSourceConfig.cmake /Makefile cmake_install.cmake install_manifest.txt # Ignore 'pgagent' & 'pgagent.control' in root directory only. /pgagent !/*/pgagent /pgagent.control !/*/pgagent.control *.log # Ignore '*.sql' files in root directory only. /*.sql !/*/*.sql /results/init.out /results/job.out /regression.diffs /regression.out /pgagent.out pgagent-REL-4_2_2/CMakeLists.txt000077500000000000000000000213201412006174200164640ustar00rootroot00000000000000####################################################################### # # pgAgent - PostgreSQL tools # Copyright (C) 2002 - 2021, The pgAdmin Development Team # This software is released under the PostgreSQL Licence # # CMakeLists.txt - CMake build configuration # ####################################################################### ################################################################################ # Initial setup ################################################################################ IF(APPLE) CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8) ELSE() CMAKE_MINIMUM_REQUIRED(VERSION 2.6) ENDIF(APPLE) 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 NO CACHE BOOL "Statically link the executable?") SET(BOOST_MULTITHREADED_BUILD YES CACHE BOOL "Build multithreaded executable?") SET(BOOST_STATIC_BUILD NO CACHE BOOL "Statically link the executable?") ################################################################################ # Apple stuff ################################################################################ IF(APPLE) # Setup default values IF(NOT HAVE_CACHED_VALUES) IF(EXISTS ${CMAKE_OSX_SYSROOT}) SET(CMAKE_OSX_SYSROOT ${CMAKE_OSX_SYSROOT} CACHE FILEPATH "isysroot used for universal binary support" FORCE) ENDIF(EXISTS ${CMAKE_OSX_SYSROOT}) IF(NOT "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "") SET(CMAKE_OSX_ARCHITECTURES ${CMAKE_OSX_ARCHITECTURES} CACHE STRING "Build architectures for OSX" FORCE) ELSE() SET(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "Build architectures for OSX" FORCE) ENDIF(NOT ${CMAKE_OSX_ARCHITECTURES} STREQUAL "") ENDIF(NOT HAVE_CACHED_VALUES) # Target Tiger SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.9") 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 "4.2.2") # CPack stuff SET(CPACK_PACKAGE_VERSION_MAJOR 4) SET(CPACK_PACKAGE_VERSION_MINOR 2) SET(CPACK_PACKAGE_VERSION_PATCH 2) 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}) ADD_DEFINITIONS(-DPGAGENT_VERSION="${VERSION}") IF(WIN32) SET(BOOST_WIN_VERSION 0x0501) ADD_DEFINITIONS(-D_WIN32_WINNT=${BOOST_WIN_VERSION} -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) ENDIF(WIN32) # This must come after we set the CPACK variables!! INCLUDE(CPack) ################################################################################ # Find PostgreSQL ################################################################################ SET(PG_STATIC ${STATIC_BUILD}) FIND_PACKAGE(PG REQUIRED) INCLUDE_DIRECTORIES(${PG_INCLUDE_DIRS}) LINK_DIRECTORIES(${PG_LIBRARY_DIRS}) ################################################################################ # Find Boost Libraries ################################################################################ SET (Boost_FIND_REQUIRED TRUE) SET (Boost_FIND_QUIETLY FALSE) SET (Boost_DEBUG FALSE) SET (Boost_USE_MULTITHREADED ${BOOST_MULTITHREADED_BUILD}) SET (Boost_USE_STATIC_LIBS ${BOOST_STATIC_BUILD}) FIND_PACKAGE(Boost COMPONENTS filesystem regex date_time thread system) if(Boost_FOUND) INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) ELSE() MESSAGE(FATAL_ERROR "Boost library not found.") endif() ################################################################################ # 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}) IF(UNIX AND NOT APPLE) TARGET_LINK_LIBRARIES( pgagent ${PG_LIBRARIES} ${Boost_LIBRARIES} -pthread ) ELSE() TARGET_LINK_LIBRARIES( pgagent ${PG_LIBRARIES} ${Boost_LIBRARIES} ) ENDIF() # Installation IF (WIN32) INSTALL(TARGETS pgagent DESTINATION .) INSTALL(FILES ${pgagent_SOURCE_DIR}/sql/pgagent.sql DESTINATION .) ELSE(WIN32) INSTALL(TARGETS pgagent DESTINATION bin) INSTALL(FILES ${pgagent_SOURCE_DIR}/sql/pgagent.sql DESTINATION share) ENDIF(WIN32) INSTALL(FILES ${pgagent_SOURCE_DIR}/README DESTINATION .) INSTALL(FILES ${pgagent_SOURCE_DIR}/LICENSE DESTINATION .) # Extension IF(PG_EXTENSION) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_BINARY_DIR}/pgagent--${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.sql pgagent.control COMMAND ${CMAKE_COMMAND} -D MAJOR_VERSION=${CPACK_PACKAGE_VERSION_MAJOR} -D MINOR_VERSION=${CPACK_PACKAGE_VERSION_MINOR} -DPGAGENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/MakeExt.cmake MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/sql/pgagent.sql ) ADD_CUSTOM_TARGET(run ALL DEPENDS ${CMAKE_BINARY_DIR}/pgagent--${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.sql ${CMAKE_BINARY_DIR}/pgagent.control) INSTALL(FILES ${CMAKE_BINARY_DIR}/pgagent--${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.sql DESTINATION ${PG_SHARE_DIR}/extension) FILE(GLOB SQL "${CMAKE_CURRENT_SOURCE_DIR}/sql/*--*.sql") FILE(GLOB CONTROL "${CMAKE_CURRENT_SOURCE_DIR}/*.control") INSTALL(FILES ${CMAKE_BINARY_DIR}/pgagent.control ${CONTROL} ${SQL} DESTINATION ${PG_SHARE_DIR}/extension) ENDIF(PG_EXTENSION) ################################################################################ # 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 string : ${PG_VERSION_STRING}") IF(${PG_MAJOR_VERSION} GREATER 9) MESSAGE(STATUS " PostgreSQL version parts : ${PG_MAJOR_VERSION}") ELSE() MESSAGE(STATUS " PostgreSQL version parts : ${PG_MAJOR_VERSION}.${PG_MINOR_VERSION}") ENDIF(${PG_MAJOR_VERSION} GREATER 9) 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 " PostgreSQL share path : ${PG_SHARE_DIR}") MESSAGE(STATUS " ") MESSAGE(STATUS " Boost version : ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") MESSAGE(STATUS " Boost path : ${Boost_INCLUDE_DIRS}") MESSAGE(STATUS " Boost include directory : ${Boost_INCLUDE_DIRS}") MESSAGE(STATUS " Boost library directory : ${Boost_LIBRARY_DIRS}") MESSAGE(STATUS " Boost Static linking : ${Boost_USE_STATIC_LIBS}") 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) pgagent-REL-4_2_2/LICENSE000066400000000000000000000020231412006174200147250ustar00rootroot00000000000000pgAgent Copyright (C) 2002 - 2021, The pgAdmin Development Team Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL THE PGADMIN DEVELOPMENT TEAM BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE PGADMIN DEVELOPMENT TEAM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE PGADMIN DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE PGADMIN DEVELOPMENT TEAM HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. pgagent-REL-4_2_2/README000066400000000000000000000040531412006174200146050ustar00rootroot00000000000000pgAgent ======= 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 3.3 (from www.cmake.org) - A Boost library 1.41 or higher installation - 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 x86_64 CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.10.sdk PostgreSQL_CONFIG_EXECUTABLE /usr/local/pgsql/bin/pg_config Boost_FIND_REQUIRED ON Boost_FIND_QUIETLY OFF Boost_DEBUG OFF Boost_USE_MULTITHREADED ON Boost_USE_STATIC_LIBS OFF 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. Running Regression Tests ======================== To run the regression tests, use a command such as: make USE_PGXS=1 -f test/Makefile installcheck You will need to ensure that the appropriate pg_config executable is in the path and that variables such as PGPORT and PGUSER are set if required.pgagent-REL-4_2_2/cmake/000077500000000000000000000000001412006174200150035ustar00rootroot00000000000000pgagent-REL-4_2_2/cmake/FindBoost.cmake000066400000000000000000002766021412006174200177110ustar00rootroot00000000000000# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #.rst: # FindBoost # --------- # # Find Boost include dirs and libraries # # Use this module by invoking find_package with the form:: # # find_package(Boost # [version] [EXACT] # Minimum or EXACT version e.g. 1.67.0 # [REQUIRED] # Fail with error if Boost is not found # [COMPONENTS ...] # Boost libraries by their canonical name # # e.g. "date_time" for "libboost_date_time" # [OPTIONAL_COMPONENTS ...] # # Optional Boost libraries by their canonical name) # ) # e.g. "date_time" for "libboost_date_time" # # This module finds headers and requested component libraries OR a CMake # package configuration file provided by a "Boost CMake" build. For the # latter case skip to the "Boost CMake" section below. For the former # case results are reported in variables:: # # Boost_FOUND - True if headers and requested libraries were found # Boost_INCLUDE_DIRS - Boost include directories # Boost_LIBRARY_DIRS - Link directories for Boost libraries # Boost_LIBRARIES - Boost component libraries to be linked # Boost__FOUND - True if component was found ( is upper-case) # Boost__LIBRARY - Libraries to link for component (may include # target_link_libraries debug/optimized keywords) # Boost_VERSION - BOOST_VERSION value from boost/version.hpp # Boost_LIB_VERSION - Version string appended to library filenames # Boost_MAJOR_VERSION - Boost major version number (X in X.y.z) # Boost_MINOR_VERSION - Boost minor version number (Y in x.Y.z) # Boost_SUBMINOR_VERSION - Boost subminor version number (Z in x.y.Z) # Boost_LIB_DIAGNOSTIC_DEFINITIONS (Windows) # - Pass to add_definitions() to have diagnostic # information about Boost's automatic linking # displayed during compilation # # Note that Boost Python components require a Python version suffix # (Boost 1.67 and later), e.g. ``python36`` or ``python27`` for the # versions built against Python 3.6 and 2.7, respectively. This also # applies to additional components using Python including # ``mpi_python`` and ``numpy``. Earlier Boost releases may use # distribution-specific suffixes such as ``2``, ``3`` or ``2.7``. # These may also be used as suffixes, but note that they are not # portable. # # This module reads hints about search locations from variables:: # # BOOST_ROOT - Preferred installation prefix # (or BOOSTROOT) # BOOST_INCLUDEDIR - Preferred include directory e.g. /include # BOOST_LIBRARYDIR - Preferred library directory e.g. /lib # Boost_NO_SYSTEM_PATHS - Set to ON to disable searching in locations not # specified by these hint variables. Default is OFF. # Boost_ADDITIONAL_VERSIONS # - List of Boost versions not known to this module # (Boost install locations may contain the version) # # and saves search results persistently in CMake cache entries:: # # Boost_INCLUDE_DIR - Directory containing Boost headers # Boost_LIBRARY_DIR_RELEASE - Directory containing release Boost libraries # Boost_LIBRARY_DIR_DEBUG - Directory containing debug Boost libraries # Boost__LIBRARY_DEBUG - Component library debug variant # Boost__LIBRARY_RELEASE - Component library release variant # # The following :prop_tgt:`IMPORTED` targets are also defined:: # # Boost::boost - Target for header-only dependencies # (Boost include directory) # Boost:: - Target for specific component dependency # (shared or static library); is lower- # case # Boost::diagnostic_definitions - interface target to enable diagnostic # information about Boost's automatic linking # during compilation (adds BOOST_LIB_DIAGNOSTIC) # Boost::disable_autolinking - interface target to disable automatic # linking with MSVC (adds BOOST_ALL_NO_LIB) # Boost::dynamic_linking - interface target to enable dynamic linking # linking with MSVC (adds BOOST_ALL_DYN_LINK) # # Implicit dependencies such as Boost::filesystem requiring # Boost::system will be automatically detected and satisfied, even # if system is not specified when using find_package and if # Boost::system is not added to target_link_libraries. If using # Boost::thread, then Threads::Threads will also be added automatically. # # It is important to note that the imported targets behave differently # than variables created by this module: multiple calls to # find_package(Boost) in the same directory or sub-directories with # different options (e.g. static or shared) will not override the # values of the targets created by the first call. # # Users may set these hints or results as cache entries. Projects # should not read these entries directly but instead use the above # result variables. Note that some hint names start in upper-case # "BOOST". One may specify these as environment variables if they are # not specified as CMake variables or cache entries. # # This module first searches for the Boost header files using the above # hint variables (excluding BOOST_LIBRARYDIR) and saves the result in # Boost_INCLUDE_DIR. Then it searches for requested component libraries # using the above hints (excluding BOOST_INCLUDEDIR and # Boost_ADDITIONAL_VERSIONS), "lib" directories near Boost_INCLUDE_DIR, # and the library name configuration settings below. It saves the # library directories in Boost_LIBRARY_DIR_DEBUG and # Boost_LIBRARY_DIR_RELEASE and individual library # locations in Boost__LIBRARY_DEBUG and Boost__LIBRARY_RELEASE. # When one changes settings used by previous searches in the same build # tree (excluding environment variables) this module discards previous # search results affected by the changes and searches again. # # Boost libraries come in many variants encoded in their file name. # Users or projects may tell this module which variant to find by # setting variables:: # # Boost_USE_DEBUG_LIBS - Set to ON or OFF to specify whether to search # and use the debug libraries. Default is ON. # Boost_USE_RELEASE_LIBS - Set to ON or OFF to specify whether to search # and use the release libraries. Default is ON. # Boost_USE_MULTITHREADED - Set to OFF to use the non-multithreaded # libraries ('mt' tag). Default is ON. # Boost_USE_STATIC_LIBS - Set to ON to force the use of the static # libraries. Default is OFF. # Boost_USE_STATIC_RUNTIME - Set to ON or OFF to specify whether to use # libraries linked statically to the C++ runtime # ('s' tag). Default is platform dependent. # Boost_USE_DEBUG_RUNTIME - Set to ON or OFF to specify whether to use # libraries linked to the MS debug C++ runtime # ('g' tag). Default is ON. # Boost_USE_DEBUG_PYTHON - Set to ON to use libraries compiled with a # debug Python build ('y' tag). Default is OFF. # Boost_USE_STLPORT - Set to ON to use libraries compiled with # STLPort ('p' tag). Default is OFF. # Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS # - Set to ON to use libraries compiled with # STLPort deprecated "native iostreams" # ('n' tag). Default is OFF. # Boost_COMPILER - Set to the compiler-specific library suffix # (e.g. "-gcc43"). Default is auto-computed # for the C++ compiler in use. A list may be # used if multiple compatible suffixes should # be tested for, in decreasing order of # preference. # Boost_THREADAPI - Suffix for "thread" component library name, # such as "pthread" or "win32". Names with # and without this suffix will both be tried. # Boost_NAMESPACE - Alternate namespace used to build boost with # e.g. if set to "myboost", will search for # myboost_thread instead of boost_thread. # # Other variables one may set to control this module are:: # # Boost_DEBUG - Set to ON to enable debug output from FindBoost. # Please enable this before filing any bug report. # Boost_DETAILED_FAILURE_MSG # - Set to ON to add detailed information to the # failure message even when the REQUIRED option # is not given to the find_package call. # Boost_REALPATH - Set to ON to resolve symlinks for discovered # libraries to assist with packaging. For example, # the "system" component library may be resolved to # "/usr/lib/libboost_system.so.1.67.0" instead of # "/usr/lib/libboost_system.so". This does not # affect linking and should not be enabled unless # the user needs this information. # Boost_LIBRARY_DIR - Default value for Boost_LIBRARY_DIR_RELEASE and # Boost_LIBRARY_DIR_DEBUG. # # On Visual Studio and Borland compilers Boost headers request automatic # linking to corresponding libraries. This requires matching libraries # to be linked explicitly or available in the link library search path. # In this case setting Boost_USE_STATIC_LIBS to OFF may not achieve # dynamic linking. Boost automatic linking typically requests static # libraries with a few exceptions (such as Boost.Python). Use:: # # add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS}) # # to ask Boost to report information about automatic linking requests. # # Example to find Boost headers only:: # # find_package(Boost 1.36.0) # if(Boost_FOUND) # include_directories(${Boost_INCLUDE_DIRS}) # add_executable(foo foo.cc) # endif() # # Example to find Boost libraries and use imported targets:: # # find_package(Boost 1.56 REQUIRED COMPONENTS # date_time filesystem iostreams) # add_executable(foo foo.cc) # target_link_libraries(foo Boost::date_time Boost::filesystem # Boost::iostreams) # # Example to find Boost Python 3.6 libraries and use imported targets:: # # find_package(Boost 1.67 REQUIRED COMPONENTS # python36 numpy36) # add_executable(foo foo.cc) # target_link_libraries(foo Boost::python36 Boost::numpy36) # # Example to find Boost headers and some *static* (release only) libraries:: # # set(Boost_USE_STATIC_LIBS ON) # only find static libs # set(Boost_USE_DEBUG_LIBS OFF) # ignore debug libs and # set(Boost_USE_RELEASE_LIBS ON) # only find release libs # set(Boost_USE_MULTITHREADED ON) # set(Boost_USE_STATIC_RUNTIME OFF) # find_package(Boost 1.66.0 COMPONENTS date_time filesystem system ...) # if(Boost_FOUND) # include_directories(${Boost_INCLUDE_DIRS}) # add_executable(foo foo.cc) # target_link_libraries(foo ${Boost_LIBRARIES}) # endif() # # Boost CMake # ^^^^^^^^^^^ # # If Boost was built using the boost-cmake project it provides a package # configuration file for use with find_package's Config mode. This # module looks for the package configuration file called # BoostConfig.cmake or boost-config.cmake and stores the result in cache # entry "Boost_DIR". If found, the package configuration file is loaded # and this module returns with no further action. See documentation of # the Boost CMake package configuration for details on what it provides. # # Set Boost_NO_BOOST_CMAKE to ON to disable the search for boost-cmake. # Save project's policies cmake_policy(PUSH) cmake_policy(SET CMP0057 NEW) # if IN_LIST #------------------------------------------------------------------------------- # Before we go searching, check whether boost-cmake is available, unless the # user specifically asked NOT to search for boost-cmake. # # If Boost_DIR is set, this behaves as any find_package call would. If not, # it looks at BOOST_ROOT and BOOSTROOT to find Boost. # if (NOT Boost_NO_BOOST_CMAKE) # If Boost_DIR is not set, look for BOOSTROOT and BOOST_ROOT as alternatives, # since these are more conventional for Boost. if ("$ENV{Boost_DIR}" STREQUAL "") if (NOT "$ENV{BOOST_ROOT}" STREQUAL "") set(ENV{Boost_DIR} $ENV{BOOST_ROOT}) elseif (NOT "$ENV{BOOSTROOT}" STREQUAL "") set(ENV{Boost_DIR} $ENV{BOOSTROOT}) endif() endif() # Do the same find_package call but look specifically for the CMake version. # Note that args are passed in the Boost_FIND_xxxxx variables, so there is no # need to delegate them to this find_package call. find_package(Boost QUIET NO_MODULE) mark_as_advanced(Boost_DIR) # If we found boost-cmake, then we're done. Print out what we found. # Otherwise let the rest of the module try to find it. if (Boost_FOUND) message(STATUS "Boost ${Boost_FIND_VERSION} found.") if (Boost_FIND_COMPONENTS) message(STATUS "Found Boost components:\n ${Boost_FIND_COMPONENTS}") endif() # Restore project's policies cmake_policy(POP) return() endif() endif() #------------------------------------------------------------------------------- # FindBoost functions & macros # ############################################ # # Check the existence of the libraries. # ############################################ # This macro was taken directly from the FindQt4.cmake file that is included # with the CMake distribution. This is NOT my work. All work was done by the # original authors of the FindQt4.cmake file. Only minor modifications were # made to remove references to Qt and make this file more generally applicable # And ELSE/ENDIF pairs were removed for readability. ######################################################################### macro(_Boost_ADJUST_LIB_VARS basename) if(Boost_INCLUDE_DIR ) if(Boost_${basename}_LIBRARY_DEBUG AND Boost_${basename}_LIBRARY_RELEASE) # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for # single-config generators, set optimized and debug libraries get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(_isMultiConfig OR CMAKE_BUILD_TYPE) set(Boost_${basename}_LIBRARY optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) else() # For single-config generators where CMAKE_BUILD_TYPE has no value, # just use the release libraries set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) endif() # FIXME: This probably should be set for both cases set(Boost_${basename}_LIBRARIES optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) endif() # if only the release version was found, set the debug variable also to the release version if(Boost_${basename}_LIBRARY_RELEASE AND NOT Boost_${basename}_LIBRARY_DEBUG) set(Boost_${basename}_LIBRARY_DEBUG ${Boost_${basename}_LIBRARY_RELEASE}) set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE}) set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE}) endif() # if only the debug version was found, set the release variable also to the debug version if(Boost_${basename}_LIBRARY_DEBUG AND NOT Boost_${basename}_LIBRARY_RELEASE) set(Boost_${basename}_LIBRARY_RELEASE ${Boost_${basename}_LIBRARY_DEBUG}) set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_DEBUG}) set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_DEBUG}) endif() # If the debug & release library ends up being the same, omit the keywords if("${Boost_${basename}_LIBRARY_RELEASE}" STREQUAL "${Boost_${basename}_LIBRARY_DEBUG}") set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE} ) endif() if(Boost_${basename}_LIBRARY AND Boost_${basename}_HEADER) set(Boost_${basename}_FOUND ON) if("x${basename}" STREQUAL "xTHREAD" AND NOT TARGET Threads::Threads) string(APPEND Boost_ERROR_REASON_THREAD " (missing dependency: Threads)") set(Boost_THREAD_FOUND OFF) endif() endif() endif() # Make variables changeable to the advanced user mark_as_advanced( Boost_${basename}_LIBRARY_RELEASE Boost_${basename}_LIBRARY_DEBUG ) endmacro() # Detect changes in used variables. # Compares the current variable value with the last one. # In short form: # v != v_LAST -> CHANGED = 1 # v is defined, v_LAST not -> CHANGED = 1 # v is not defined, but v_LAST is -> CHANGED = 1 # otherwise -> CHANGED = 0 # CHANGED is returned in variable named ${changed_var} macro(_Boost_CHANGE_DETECT changed_var) set(${changed_var} 0) foreach(v ${ARGN}) if(DEFINED _Boost_COMPONENTS_SEARCHED) if(${v}) if(_${v}_LAST) string(COMPARE NOTEQUAL "${${v}}" "${_${v}_LAST}" _${v}_CHANGED) else() set(_${v}_CHANGED 1) endif() elseif(_${v}_LAST) set(_${v}_CHANGED 1) endif() if(_${v}_CHANGED) set(${changed_var} 1) endif() else() set(_${v}_CHANGED 0) endif() endforeach() endmacro() # # Find the given library (var). # Use 'build_type' to support different lib paths for RELEASE or DEBUG builds # macro(_Boost_FIND_LIBRARY var build_type) find_library(${var} ${ARGN}) if(${var}) # If this is the first library found then save Boost_LIBRARY_DIR_[RELEASE,DEBUG]. if(NOT Boost_LIBRARY_DIR_${build_type}) get_filename_component(_dir "${${var}}" PATH) set(Boost_LIBRARY_DIR_${build_type} "${_dir}" CACHE PATH "Boost library directory ${build_type}" FORCE) endif() elseif(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) # Try component-specific hints but do not save Boost_LIBRARY_DIR_[RELEASE,DEBUG]. find_library(${var} HINTS ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT} ${ARGN}) endif() # If Boost_LIBRARY_DIR_[RELEASE,DEBUG] is known then search only there. if(Boost_LIBRARY_DIR_${build_type}) set(_boost_LIBRARY_SEARCH_DIRS_${build_type} ${Boost_LIBRARY_DIR_${build_type}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " Boost_LIBRARY_DIR_${build_type} = ${Boost_LIBRARY_DIR_${build_type}}" " _boost_LIBRARY_SEARCH_DIRS_${build_type} = ${_boost_LIBRARY_SEARCH_DIRS_${build_type}}") endif() endif() endmacro() #------------------------------------------------------------------------------- # # Runs compiler with "-dumpversion" and parses major/minor # version with a regex. # function(_Boost_COMPILER_DUMPVERSION _OUTPUT_VERSION) string(REGEX REPLACE "([0-9]+)\\.([0-9]+)(\\.[0-9]+)?" "\\1\\2" _boost_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION}) set(${_OUTPUT_VERSION} ${_boost_COMPILER_VERSION} PARENT_SCOPE) endfunction() # # Take a list of libraries with "thread" in it # and prepend duplicates with "thread_${Boost_THREADAPI}" # at the front of the list # function(_Boost_PREPEND_LIST_WITH_THREADAPI _output) set(_orig_libnames ${ARGN}) string(REPLACE "thread" "thread_${Boost_THREADAPI}" _threadapi_libnames "${_orig_libnames}") set(${_output} ${_threadapi_libnames} ${_orig_libnames} PARENT_SCOPE) endfunction() # # If a library is found, replace its cache entry with its REALPATH # function(_Boost_SWAP_WITH_REALPATH _library _docstring) if(${_library}) get_filename_component(_boost_filepathreal ${${_library}} REALPATH) unset(${_library} CACHE) set(${_library} ${_boost_filepathreal} CACHE FILEPATH "${_docstring}") endif() endfunction() function(_Boost_CHECK_SPELLING _var) if(${_var}) string(TOUPPER ${_var} _var_UC) message(FATAL_ERROR "ERROR: ${_var} is not the correct spelling. The proper spelling is ${_var_UC}.") endif() endfunction() # Guesses Boost's compiler prefix used in built library names # Returns the guess by setting the variable pointed to by _ret function(_Boost_GUESS_COMPILER_PREFIX _ret) if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntel") if(WIN32) set (_boost_COMPILER "-iw") else() set (_boost_COMPILER "-il") endif() elseif (GHSMULTI) set(_boost_COMPILER "-ghs") elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) set(_boost_COMPILER "-vc141;-vc140") elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) set(_boost_COMPILER "-vc140") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18) set(_boost_COMPILER "-vc120") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 17) set(_boost_COMPILER "-vc110") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16) set(_boost_COMPILER "-vc100") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15) set(_boost_COMPILER "-vc90") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14) set(_boost_COMPILER "-vc80") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.10) set(_boost_COMPILER "-vc71") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13) # Good luck! set(_boost_COMPILER "-vc7") # yes, this is correct else() # VS 6.0 Good luck! set(_boost_COMPILER "-vc6") # yes, this is correct endif() elseif (BORLAND) set(_boost_COMPILER "-bcb") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") set(_boost_COMPILER "-sw") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "XL") set(_boost_COMPILER "-xlc") elseif (MINGW) if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34) set(_boost_COMPILER "-mgw") # no GCC version encoding prior to 1.34 else() _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION) set(_boost_COMPILER "-mgw${_boost_COMPILER_VERSION}") endif() elseif (UNIX) if (CMAKE_COMPILER_IS_GNUCXX) if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34) set(_boost_COMPILER "-gcc") # no GCC version encoding prior to 1.34 else() _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION) # Determine which version of GCC we have. if(APPLE) if(Boost_MINOR_VERSION) if(${Boost_MINOR_VERSION} GREATER 35) # In Boost 1.36.0 and newer, the mangled compiler name used # on Mac OS X/Darwin is "xgcc". set(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}") else() # In Boost <= 1.35.0, there is no mangled compiler name for # the Mac OS X/Darwin version of GCC. set(_boost_COMPILER "") endif() else() # We don't know the Boost version, so assume it's # pre-1.36.0. set(_boost_COMPILER "") endif() else() set(_boost_COMPILER "-gcc${_boost_COMPILER_VERSION}") endif() endif() endif () else() # TODO at least Boost_DEBUG here? set(_boost_COMPILER "") endif() set(${_ret} ${_boost_COMPILER} PARENT_SCOPE) endfunction() # # Get component dependencies. Requires the dependencies to have been # defined for the Boost release version. # # component - the component to check # _ret - list of library dependencies # function(_Boost_COMPONENT_DEPENDENCIES component _ret) # Note: to add a new Boost release, run # # % cmake -DBOOST_DIR=/path/to/boost/source -P Utilities/Scripts/BoostScanDeps.cmake # # The output may be added in a new block below. If it's the same as # the previous release, simply update the version range of the block # for the previous release. Also check if any new components have # been added, and add any new components to # _Boost_COMPONENT_HEADERS. # # This information was originally generated by running # BoostScanDeps.cmake against every boost release to date supported # by FindBoost: # # % for version in /path/to/boost/sources/* # do # cmake -DBOOST_DIR=$version -P Utilities/Scripts/BoostScanDeps.cmake # done # # The output was then updated by search and replace with these regexes: # # - Strip message(STATUS) prefix dashes # s;^-- ;; # - Indent # s;^set(; set(;; # - Add conditionals # s;Scanning /path/to/boost/sources/boost_\(.*\)_\(.*\)_\(.*); elseif(NOT Boost_VERSION VERSION_LESS \10\20\3 AND Boost_VERSION VERSION_LESS xxxx); # # This results in the logic seen below, but will require the xxxx # replacing with the following Boost release version (or the next # minor version to be released, e.g. 1.59 was the latest at the time # of writing, making 1.60 the next, so 106000 is the needed version # number). Identical consecutive releases were then merged together # by updating the end range of the first block and removing the # following redundant blocks. # # Running the script against all historical releases should be # required only if the BoostScanDeps.cmake script logic is changed. # The addition of a new release should only require it to be run # against the new release. # Handle Python version suffixes if(component MATCHES "^(python|mpi_python|numpy)([0-9][0-9]?|[0-9]\\.[0-9])\$") set(component "${CMAKE_MATCH_1}") set(component_python_version "${CMAKE_MATCH_2}") endif() set(_Boost_IMPORTED_TARGETS TRUE) if(Boost_VERSION VERSION_LESS 103300) message(WARNING "Imported targets and dependency information not available for Boost version ${Boost_VERSION} (all versions older than 1.33)") set(_Boost_IMPORTED_TARGETS FALSE) elseif(NOT Boost_VERSION VERSION_LESS 103300 AND Boost_VERSION VERSION_LESS 103500) set(_Boost_IOSTREAMS_DEPENDENCIES regex thread) set(_Boost_REGEX_DEPENDENCIES thread) set(_Boost_WAVE_DEPENDENCIES filesystem thread) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 103500 AND Boost_VERSION VERSION_LESS 103600) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_WAVE_DEPENDENCIES filesystem system thread) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 103600 AND Boost_VERSION VERSION_LESS 103800) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_WAVE_DEPENDENCIES filesystem system thread) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 103800 AND Boost_VERSION VERSION_LESS 104300) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_THREAD_DEPENDENCIES date_time) set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 104300 AND Boost_VERSION VERSION_LESS 104400) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_THREAD_DEPENDENCIES date_time) set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 104400 AND Boost_VERSION VERSION_LESS 104500) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random serialization) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_THREAD_DEPENDENCIES date_time) set(_Boost_WAVE_DEPENDENCIES serialization filesystem system thread date_time) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 104500 AND Boost_VERSION VERSION_LESS 104700) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_THREAD_DEPENDENCIES date_time) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 104700 AND Boost_VERSION VERSION_LESS 104800) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_THREAD_DEPENDENCIES date_time) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 104800 AND Boost_VERSION VERSION_LESS 105000) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_THREAD_DEPENDENCIES date_time) set(_Boost_TIMER_DEPENDENCIES chrono system) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 105000 AND Boost_VERSION VERSION_LESS 105300) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_THREAD_DEPENDENCIES chrono system date_time) set(_Boost_TIMER_DEPENDENCIES chrono system) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 105300 AND Boost_VERSION VERSION_LESS 105400) set(_Boost_ATOMIC_DEPENDENCIES thread chrono system date_time) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) set(_Boost_TIMER_DEPENDENCIES chrono system) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 105400 AND Boost_VERSION VERSION_LESS 105500) set(_Boost_ATOMIC_DEPENDENCIES thread chrono system date_time) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) set(_Boost_TIMER_DEPENDENCIES chrono system) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 105500 AND Boost_VERSION VERSION_LESS 105600) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_COROUTINE_DEPENDENCIES context system) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) set(_Boost_TIMER_DEPENDENCIES chrono system) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 105600 AND Boost_VERSION VERSION_LESS 105900) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_COROUTINE_DEPENDENCIES context system) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_RANDOM_DEPENDENCIES system) set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) set(_Boost_TIMER_DEPENDENCIES chrono system) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 105900 AND Boost_VERSION VERSION_LESS 106000) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_COROUTINE_DEPENDENCIES context system) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono atomic) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_RANDOM_DEPENDENCIES system) set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) set(_Boost_TIMER_DEPENDENCIES chrono system) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 106000 AND Boost_VERSION VERSION_LESS 106100) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_COROUTINE_DEPENDENCIES context system) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_RANDOM_DEPENDENCIES system) set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) set(_Boost_TIMER_DEPENDENCIES chrono system) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 106100 AND Boost_VERSION VERSION_LESS 106200) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) set(_Boost_COROUTINE_DEPENDENCIES context system) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_RANDOM_DEPENDENCIES system) set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 106200 AND Boost_VERSION VERSION_LESS 106300) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) set(_Boost_COROUTINE_DEPENDENCIES context system) set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_RANDOM_DEPENDENCIES system) set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 106300 AND Boost_VERSION VERSION_LESS 106500) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) set(_Boost_COROUTINE_DEPENDENCIES context system) set(_Boost_COROUTINE2_DEPENDENCIES context fiber thread chrono system date_time) set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_RANDOM_DEPENDENCIES system) set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) elseif(NOT Boost_VERSION VERSION_LESS 106500 AND Boost_VERSION VERSION_LESS 106700) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) set(_Boost_COROUTINE_DEPENDENCIES context system) set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) set(_Boost_RANDOM_DEPENDENCIES system) set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) set(_Boost_TIMER_DEPENDENCIES chrono system) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) else() if(NOT Boost_VERSION VERSION_LESS 106700) set(_Boost_CHRONO_DEPENDENCIES system) set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) set(_Boost_COROUTINE_DEPENDENCIES context system) set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) set(_Boost_FILESYSTEM_DEPENDENCIES system) set(_Boost_IOSTREAMS_DEPENDENCIES regex) set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) set(_Boost_MPI_DEPENDENCIES serialization) set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) set(_Boost_RANDOM_DEPENDENCIES system) set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) set(_Boost_TIMER_DEPENDENCIES chrono system) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) endif() if(NOT Boost_VERSION VERSION_LESS 106800) message(WARNING "New Boost version may have incorrect or missing dependencies and imported targets") endif() endif() string(TOUPPER ${component} uppercomponent) set(${_ret} ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) set(_Boost_IMPORTED_TARGETS ${_Boost_IMPORTED_TARGETS} PARENT_SCOPE) string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_Boost_${uppercomponent}_DEPENDENCIES}") if (NOT _boost_DEPS_STRING) set(_boost_DEPS_STRING "(none)") endif() # message(STATUS "Dependencies for Boost::${component}: ${_boost_DEPS_STRING}") endfunction() # # Get component headers. This is the primary header (or headers) for # a given component, and is used to check that the headers are present # as well as the library itself as an extra sanity check of the build # environment. # # component - the component to check # _hdrs # function(_Boost_COMPONENT_HEADERS component _hdrs) # Handle Python version suffixes if(component MATCHES "^(python|mpi_python|numpy)([0-9][0-9]?|[0-9]\\.[0-9])\$") set(component "${CMAKE_MATCH_1}") set(component_python_version "${CMAKE_MATCH_2}") endif() # Note: new boost components will require adding here. The header # must be present in all versions of Boost providing a library. set(_Boost_ATOMIC_HEADERS "boost/atomic.hpp") set(_Boost_CHRONO_HEADERS "boost/chrono.hpp") set(_Boost_CONTAINER_HEADERS "boost/container/container_fwd.hpp") set(_Boost_CONTEXT_HEADERS "boost/context/all.hpp") set(_Boost_COROUTINE_HEADERS "boost/coroutine/all.hpp") set(_Boost_DATE_TIME_HEADERS "boost/date_time/date.hpp") set(_Boost_EXCEPTION_HEADERS "boost/exception/exception.hpp") set(_Boost_FIBER_HEADERS "boost/fiber/all.hpp") set(_Boost_FILESYSTEM_HEADERS "boost/filesystem/path.hpp") set(_Boost_GRAPH_HEADERS "boost/graph/adjacency_list.hpp") set(_Boost_GRAPH_PARALLEL_HEADERS "boost/graph/adjacency_list.hpp") set(_Boost_IOSTREAMS_HEADERS "boost/iostreams/stream.hpp") set(_Boost_LOCALE_HEADERS "boost/locale.hpp") set(_Boost_LOG_HEADERS "boost/log/core.hpp") set(_Boost_LOG_SETUP_HEADERS "boost/log/detail/setup_config.hpp") set(_Boost_MATH_HEADERS "boost/math_fwd.hpp") set(_Boost_MATH_C99_HEADERS "boost/math/tr1.hpp") set(_Boost_MATH_C99F_HEADERS "boost/math/tr1.hpp") set(_Boost_MATH_C99L_HEADERS "boost/math/tr1.hpp") set(_Boost_MATH_TR1_HEADERS "boost/math/tr1.hpp") set(_Boost_MATH_TR1F_HEADERS "boost/math/tr1.hpp") set(_Boost_MATH_TR1L_HEADERS "boost/math/tr1.hpp") set(_Boost_MPI_HEADERS "boost/mpi.hpp") set(_Boost_MPI_PYTHON_HEADERS "boost/mpi/python/config.hpp") set(_Boost_NUMPY_HEADERS "boost/python/numpy.hpp") set(_Boost_PRG_EXEC_MONITOR_HEADERS "boost/test/prg_exec_monitor.hpp") set(_Boost_PROGRAM_OPTIONS_HEADERS "boost/program_options.hpp") set(_Boost_PYTHON_HEADERS "boost/python.hpp") set(_Boost_RANDOM_HEADERS "boost/random.hpp") set(_Boost_REGEX_HEADERS "boost/regex.hpp") set(_Boost_SERIALIZATION_HEADERS "boost/serialization/serialization.hpp") set(_Boost_SIGNALS_HEADERS "boost/signals.hpp") set(_Boost_SYSTEM_HEADERS "boost/system/config.hpp") set(_Boost_TEST_EXEC_MONITOR_HEADERS "boost/test/test_exec_monitor.hpp") set(_Boost_THREAD_HEADERS "boost/thread.hpp") set(_Boost_TIMER_HEADERS "boost/timer.hpp") set(_Boost_TYPE_ERASURE_HEADERS "boost/type_erasure/config.hpp") set(_Boost_UNIT_TEST_FRAMEWORK_HEADERS "boost/test/framework.hpp") set(_Boost_WAVE_HEADERS "boost/wave.hpp") set(_Boost_WSERIALIZATION_HEADERS "boost/archive/text_wiarchive.hpp") if(WIN32) set(_Boost_BZIP2_HEADERS "boost/iostreams/filter/bzip2.hpp") set(_Boost_ZLIB_HEADERS "boost/iostreams/filter/zlib.hpp") endif() string(TOUPPER ${component} uppercomponent) set(${_hdrs} ${_Boost_${uppercomponent}_HEADERS} PARENT_SCOPE) string(REGEX REPLACE ";" " " _boost_HDRS_STRING "${_Boost_${uppercomponent}_HEADERS}") if (NOT _boost_HDRS_STRING) set(_boost_HDRS_STRING "(none)") endif() # message(STATUS "Headers for Boost::${component}: ${_boost_HDRS_STRING}") endfunction() # # Determine if any missing dependencies require adding to the component list. # # Sets _Boost_${COMPONENT}_DEPENDENCIES for each required component, # plus _Boost_IMPORTED_TARGETS (TRUE if imported targets should be # defined; FALSE if dependency information is unavailable). # # componentvar - the component list variable name # extravar - the indirect dependency list variable name # # function(_Boost_MISSING_DEPENDENCIES componentvar extravar) # _boost_unprocessed_components - list of components requiring processing # _boost_processed_components - components already processed (or currently being processed) # _boost_new_components - new components discovered for future processing # list(APPEND _boost_unprocessed_components ${${componentvar}}) while(_boost_unprocessed_components) list(APPEND _boost_processed_components ${_boost_unprocessed_components}) foreach(component ${_boost_unprocessed_components}) string(TOUPPER ${component} uppercomponent) set(${_ret} ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) _Boost_COMPONENT_DEPENDENCIES("${component}" _Boost_${uppercomponent}_DEPENDENCIES) set(_Boost_${uppercomponent}_DEPENDENCIES ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) set(_Boost_IMPORTED_TARGETS ${_Boost_IMPORTED_TARGETS} PARENT_SCOPE) foreach(componentdep ${_Boost_${uppercomponent}_DEPENDENCIES}) if (NOT ("${componentdep}" IN_LIST _boost_processed_components OR "${componentdep}" IN_LIST _boost_new_components)) list(APPEND _boost_new_components ${componentdep}) endif() endforeach() endforeach() set(_boost_unprocessed_components ${_boost_new_components}) unset(_boost_new_components) endwhile() set(_boost_extra_components ${_boost_processed_components}) if(_boost_extra_components AND ${componentvar}) list(REMOVE_ITEM _boost_extra_components ${${componentvar}}) endif() set(${componentvar} ${_boost_processed_components} PARENT_SCOPE) set(${extravar} ${_boost_extra_components} PARENT_SCOPE) endfunction() # # Some boost libraries may require particular set of compler features. # The very first one was `boost::fiber` introduced in Boost 1.62. # One can check required compiler features of it in # `${Boost_ROOT}/libs/fiber/build/Jamfile.v2`. # function(_Boost_COMPILER_FEATURES component _ret) # Boost >= 1.62 and < 1.67 if(NOT Boost_VERSION VERSION_LESS 106200 AND Boost_VERSION VERSION_LESS 106700) set(_Boost_FIBER_COMPILER_FEATURES cxx_alias_templates cxx_auto_type cxx_constexpr cxx_defaulted_functions cxx_final cxx_lambdas cxx_noexcept cxx_nullptr cxx_rvalue_references cxx_thread_local cxx_variadic_templates ) endif() string(TOUPPER ${component} uppercomponent) set(${_ret} ${_Boost_${uppercomponent}_COMPILER_FEATURES} PARENT_SCOPE) endfunction() # # Update library search directory hint variable with paths used by prebuilt boost binaries. # # Prebuilt windows binaries (https://sourceforge.net/projects/boost/files/boost-binaries/) # have library directories named using MSVC compiler version and architecture. # This function would append corresponding directories if MSVC is a current compiler, # so having `BOOST_ROOT` would be enough to specify to find everything. # function(_Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS componentlibvar basedir) if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(_arch_suffix 64) else() set(_arch_suffix 32) endif() if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-14.1) list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-14.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-14.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18) list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-12.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 17) list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-11.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16) list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-10.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15) list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-9.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14) list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-8.0) endif() set(${componentlibvar} ${${componentlibvar}} PARENT_SCOPE) endif() endfunction() # # End functions/macros # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # main. #------------------------------------------------------------------------------- # If the user sets Boost_LIBRARY_DIR, use it as the default for both # configurations. if(NOT Boost_LIBRARY_DIR_RELEASE AND Boost_LIBRARY_DIR) set(Boost_LIBRARY_DIR_RELEASE "${Boost_LIBRARY_DIR}") endif() if(NOT Boost_LIBRARY_DIR_DEBUG AND Boost_LIBRARY_DIR) set(Boost_LIBRARY_DIR_DEBUG "${Boost_LIBRARY_DIR}") endif() if(NOT DEFINED Boost_USE_DEBUG_LIBS) set(Boost_USE_DEBUG_LIBS TRUE) endif() if(NOT DEFINED Boost_USE_RELEASE_LIBS) set(Boost_USE_RELEASE_LIBS TRUE) endif() if(NOT DEFINED Boost_USE_MULTITHREADED) set(Boost_USE_MULTITHREADED TRUE) endif() if(NOT DEFINED Boost_USE_DEBUG_RUNTIME) set(Boost_USE_DEBUG_RUNTIME TRUE) endif() # Check the version of Boost against the requested version. if(Boost_FIND_VERSION AND NOT Boost_FIND_VERSION_MINOR) message(SEND_ERROR "When requesting a specific version of Boost, you must provide at least the major and minor version numbers, e.g., 1.34") endif() if(Boost_FIND_VERSION_EXACT) # The version may appear in a directory with or without the patch # level, even when the patch level is non-zero. set(_boost_TEST_VERSIONS "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}.${Boost_FIND_VERSION_PATCH}" "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") else() # The user has not requested an exact version. Among known # versions, find those that are acceptable to the user request. # # Note: When adding a new Boost release, also update the dependency # information in _Boost_COMPONENT_DEPENDENCIES and # _Boost_COMPONENT_HEADERS. See the instructions at the top of # _Boost_COMPONENT_DEPENDENCIES. set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS} "1.67.0" "1.67" "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65" "1.64.0" "1.64" "1.63.0" "1.63" "1.62.0" "1.62" "1.61.0" "1.61" "1.60.0" "1.60" "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55" "1.54.0" "1.54" "1.53.0" "1.53" "1.52.0" "1.52" "1.51.0" "1.51" "1.50.0" "1.50" "1.49.0" "1.49" "1.48.0" "1.48" "1.47.0" "1.47" "1.46.1" "1.46.0" "1.46" "1.45.0" "1.45" "1.44.0" "1.44" "1.43.0" "1.43" "1.42.0" "1.42" "1.41.0" "1.41" "1.40.0" "1.40" "1.39.0" "1.39" "1.38.0" "1.38" "1.37.0" "1.37" "1.36.1" "1.36.0" "1.36" "1.35.1" "1.35.0" "1.35" "1.34.1" "1.34.0" "1.34" "1.33.1" "1.33.0" "1.33") set(_boost_TEST_VERSIONS) if(Boost_FIND_VERSION) set(_Boost_FIND_VERSION_SHORT "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") # Select acceptable versions. foreach(version ${_Boost_KNOWN_VERSIONS}) if(NOT "${version}" VERSION_LESS "${Boost_FIND_VERSION}") # This version is high enough. list(APPEND _boost_TEST_VERSIONS "${version}") elseif("${version}.99" VERSION_EQUAL "${_Boost_FIND_VERSION_SHORT}.99") # This version is a short-form for the requested version with # the patch level dropped. list(APPEND _boost_TEST_VERSIONS "${version}") endif() endforeach() else() # Any version is acceptable. set(_boost_TEST_VERSIONS "${_Boost_KNOWN_VERSIONS}") endif() endif() # The reason that we failed to find Boost. This will be set to a # user-friendly message when we fail to find some necessary piece of # Boost. set(Boost_ERROR_REASON) if(Boost_DEBUG) # Output some of their choices message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_USE_MULTITHREADED = ${Boost_USE_MULTITHREADED}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_USE_STATIC_LIBS = ${Boost_USE_STATIC_LIBS}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_USE_STATIC_RUNTIME = ${Boost_USE_STATIC_RUNTIME}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_ADDITIONAL_VERSIONS = ${Boost_ADDITIONAL_VERSIONS}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_NO_SYSTEM_PATHS = ${Boost_NO_SYSTEM_PATHS}") endif() # Supply Boost_LIB_DIAGNOSTIC_DEFINITIONS as a convenience target. It # will only contain any interface definitions on WIN32, but is created # on all platforms to keep end user code free from platform dependent # code. Also provide convenience targets to disable autolinking and # enable dynamic linking. if(NOT TARGET Boost::diagnostic_definitions) add_library(Boost::diagnostic_definitions INTERFACE IMPORTED) add_library(Boost::disable_autolinking INTERFACE IMPORTED) add_library(Boost::dynamic_linking INTERFACE IMPORTED) endif() if(WIN32) # In windows, automatic linking is performed, so you do not have # to specify the libraries. If you are linking to a dynamic # runtime, then you can choose to link to either a static or a # dynamic Boost library, the default is to do a static link. You # can alter this for a specific library "whatever" by defining # BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to be # linked dynamically. Alternatively you can force all Boost # libraries to dynamic link by defining BOOST_ALL_DYN_LINK. # This feature can be disabled for Boost library "whatever" by # defining BOOST_WHATEVER_NO_LIB, or for all of Boost by defining # BOOST_ALL_NO_LIB. # If you want to observe which libraries are being linked against # then defining BOOST_LIB_DIAGNOSTIC will cause the auto-linking # code to emit a #pragma message each time a library is selected # for linking. set(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC") set_target_properties(Boost::diagnostic_definitions PROPERTIES INTERFACE_COMPILE_DEFINITIONS "BOOST_LIB_DIAGNOSTIC") set_target_properties(Boost::disable_autolinking PROPERTIES INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB") set_target_properties(Boost::dynamic_linking PROPERTIES INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK") endif() _Boost_CHECK_SPELLING(Boost_ROOT) _Boost_CHECK_SPELLING(Boost_LIBRARYDIR) _Boost_CHECK_SPELLING(Boost_INCLUDEDIR) # Collect environment variable inputs as hints. Do not consider changes. foreach(v BOOSTROOT BOOST_ROOT BOOST_INCLUDEDIR BOOST_LIBRARYDIR) set(_env $ENV{${v}}) if(_env) file(TO_CMAKE_PATH "${_env}" _ENV_${v}) else() set(_ENV_${v} "") endif() endforeach() if(NOT _ENV_BOOST_ROOT AND _ENV_BOOSTROOT) set(_ENV_BOOST_ROOT "${_ENV_BOOSTROOT}") endif() # Collect inputs and cached results. Detect changes since the last run. if(NOT BOOST_ROOT AND BOOSTROOT) set(BOOST_ROOT "${BOOSTROOT}") endif() set(_Boost_VARS_DIR BOOST_ROOT Boost_NO_SYSTEM_PATHS ) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Declared as CMake or Environmental Variables:") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " BOOST_ROOT = ${BOOST_ROOT}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " BOOST_INCLUDEDIR = ${BOOST_INCLUDEDIR}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " BOOST_LIBRARYDIR = ${BOOST_LIBRARYDIR}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}") endif() # ------------------------------------------------------------------------ # Search for Boost include DIR # ------------------------------------------------------------------------ set(_Boost_VARS_INC BOOST_INCLUDEDIR Boost_INCLUDE_DIR Boost_ADDITIONAL_VERSIONS) _Boost_CHANGE_DETECT(_Boost_CHANGE_INCDIR ${_Boost_VARS_DIR} ${_Boost_VARS_INC}) # Clear Boost_INCLUDE_DIR if it did not change but other input affecting the # location did. We will find a new one based on the new inputs. if(_Boost_CHANGE_INCDIR AND NOT _Boost_INCLUDE_DIR_CHANGED) unset(Boost_INCLUDE_DIR CACHE) endif() if(NOT Boost_INCLUDE_DIR) set(_boost_INCLUDE_SEARCH_DIRS "") if(BOOST_INCLUDEDIR) list(APPEND _boost_INCLUDE_SEARCH_DIRS ${BOOST_INCLUDEDIR}) elseif(_ENV_BOOST_INCLUDEDIR) list(APPEND _boost_INCLUDE_SEARCH_DIRS ${_ENV_BOOST_INCLUDEDIR}) endif() if( BOOST_ROOT ) list(APPEND _boost_INCLUDE_SEARCH_DIRS ${BOOST_ROOT}/include ${BOOST_ROOT}) elseif( _ENV_BOOST_ROOT ) list(APPEND _boost_INCLUDE_SEARCH_DIRS ${_ENV_BOOST_ROOT}/include ${_ENV_BOOST_ROOT}) endif() if( Boost_NO_SYSTEM_PATHS) list(APPEND _boost_INCLUDE_SEARCH_DIRS NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) else() if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") foreach(ver ${_Boost_KNOWN_VERSIONS}) string(REPLACE "." "_" ver "${ver}") list(APPEND _boost_INCLUDE_SEARCH_DIRS PATHS "C:/local/boost_${ver}") endforeach() endif() list(APPEND _boost_INCLUDE_SEARCH_DIRS PATHS C:/boost/include C:/boost /sw/local/include ) endif() # Try to find Boost by stepping backwards through the Boost versions # we know about. # Build a list of path suffixes for each version. set(_boost_PATH_SUFFIXES) foreach(_boost_VER ${_boost_TEST_VERSIONS}) # Add in a path suffix, based on the required version, ideally # we could read this from version.hpp, but for that to work we'd # need to know the include dir already set(_boost_BOOSTIFIED_VERSION) # Transform 1.35 => 1_35 and 1.36.0 => 1_36_0 if(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)") set(_boost_BOOSTIFIED_VERSION "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}_${CMAKE_MATCH_3}") elseif(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)") set(_boost_BOOSTIFIED_VERSION "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}") endif() list(APPEND _boost_PATH_SUFFIXES "boost-${_boost_BOOSTIFIED_VERSION}" "boost_${_boost_BOOSTIFIED_VERSION}" "boost/boost-${_boost_BOOSTIFIED_VERSION}" "boost/boost_${_boost_BOOSTIFIED_VERSION}" ) endforeach() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Include debugging info:") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " _boost_INCLUDE_SEARCH_DIRS = ${_boost_INCLUDE_SEARCH_DIRS}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " _boost_PATH_SUFFIXES = ${_boost_PATH_SUFFIXES}") endif() # Look for a standard boost header file. find_path(Boost_INCLUDE_DIR NAMES boost/config.hpp HINTS ${_boost_INCLUDE_SEARCH_DIRS} PATH_SUFFIXES ${_boost_PATH_SUFFIXES} ) endif() # ------------------------------------------------------------------------ # Extract version information from version.hpp # ------------------------------------------------------------------------ # Set Boost_FOUND based only on header location and version. # It will be updated below for component libraries. if(Boost_INCLUDE_DIR) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "location of version.hpp: ${Boost_INCLUDE_DIR}/boost/version.hpp") endif() # Extract Boost_VERSION and Boost_LIB_VERSION from version.hpp set(Boost_VERSION 0) set(Boost_LIB_VERSION "") file(STRINGS "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS REGEX "#define BOOST_(LIB_)?VERSION ") set(_Boost_VERSION_REGEX "([0-9]+)") set(_Boost_LIB_VERSION_REGEX "\"([0-9_]+)\"") foreach(v VERSION LIB_VERSION) if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_${v} ${_Boost_${v}_REGEX}") set(Boost_${v} "${CMAKE_MATCH_1}") endif() endforeach() unset(_boost_VERSION_HPP_CONTENTS) math(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000") math(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000") math(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100") string(APPEND Boost_ERROR_REASON "Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}\nBoost include path: ${Boost_INCLUDE_DIR}") if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "version.hpp reveals boost " "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") endif() if(Boost_FIND_VERSION) # Set Boost_FOUND based on requested version. set(_Boost_VERSION "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") if("${_Boost_VERSION}" VERSION_LESS "${Boost_FIND_VERSION}") set(Boost_FOUND 0) set(_Boost_VERSION_AGE "old") elseif(Boost_FIND_VERSION_EXACT AND NOT "${_Boost_VERSION}" VERSION_EQUAL "${Boost_FIND_VERSION}") set(Boost_FOUND 0) set(_Boost_VERSION_AGE "new") else() set(Boost_FOUND 1) endif() if(NOT Boost_FOUND) # State that we found a version of Boost that is too new or too old. string(APPEND Boost_ERROR_REASON "\nDetected version of Boost is too ${_Boost_VERSION_AGE}. Requested version was ${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") if (Boost_FIND_VERSION_PATCH) string(APPEND Boost_ERROR_REASON ".${Boost_FIND_VERSION_PATCH}") endif () if (NOT Boost_FIND_VERSION_EXACT) string(APPEND Boost_ERROR_REASON " (or newer)") endif () string(APPEND Boost_ERROR_REASON ".") endif () else() # Caller will accept any Boost version. set(Boost_FOUND 1) endif() else() set(Boost_FOUND 0) string(APPEND Boost_ERROR_REASON "Unable to find the Boost header files. Please set BOOST_ROOT to the root directory containing Boost or BOOST_INCLUDEDIR to the directory containing Boost's headers.") endif() # ------------------------------------------------------------------------ # Prefix initialization # ------------------------------------------------------------------------ set(Boost_LIB_PREFIX "") if ( (GHSMULTI AND Boost_USE_STATIC_LIBS) OR (WIN32 AND Boost_USE_STATIC_LIBS AND NOT CYGWIN) ) set(Boost_LIB_PREFIX "lib") endif() if ( NOT Boost_NAMESPACE ) set(Boost_NAMESPACE "boost") endif() # ------------------------------------------------------------------------ # Suffix initialization and compiler suffix detection. # ------------------------------------------------------------------------ set(_Boost_VARS_NAME Boost_NAMESPACE Boost_COMPILER Boost_THREADAPI Boost_USE_DEBUG_PYTHON Boost_USE_MULTITHREADED Boost_USE_STATIC_LIBS Boost_USE_STATIC_RUNTIME Boost_USE_STLPORT Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS ) _Boost_CHANGE_DETECT(_Boost_CHANGE_LIBNAME ${_Boost_VARS_NAME}) # Setting some more suffixes for the library if (Boost_COMPILER) set(_boost_COMPILER ${Boost_COMPILER}) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "using user-specified Boost_COMPILER = ${_boost_COMPILER}") endif() else() # Attempt to guess the compiler suffix # NOTE: this is not perfect yet, if you experience any issues # please report them and use the Boost_COMPILER variable # to work around the problems. _Boost_GUESS_COMPILER_PREFIX(_boost_COMPILER) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "guessed _boost_COMPILER = ${_boost_COMPILER}") endif() endif() set (_boost_MULTITHREADED "-mt") if( NOT Boost_USE_MULTITHREADED ) set (_boost_MULTITHREADED "") endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_MULTITHREADED = ${_boost_MULTITHREADED}") endif() #====================== # Systematically build up the Boost ABI tag for the 'tagged' and 'versioned' layouts # http://boost.org/doc/libs/1_66_0/more/getting_started/windows.html#library-naming # http://boost.org/doc/libs/1_66_0/boost/config/auto_link.hpp # http://boost.org/doc/libs/1_66_0/tools/build/src/tools/common.jam # http://boost.org/doc/libs/1_66_0/boostcpp.jam set( _boost_RELEASE_ABI_TAG "-") set( _boost_DEBUG_ABI_TAG "-") # Key Use this library when: # s linking statically to the C++ standard library and # compiler runtime support libraries. if(Boost_USE_STATIC_RUNTIME) set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}s") set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}s") endif() # g using debug versions of the standard and runtime # support libraries if(WIN32 AND Boost_USE_DEBUG_RUNTIME) if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang" OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntel") string(APPEND _boost_DEBUG_ABI_TAG "g") endif() endif() # y using special debug build of python if(Boost_USE_DEBUG_PYTHON) string(APPEND _boost_DEBUG_ABI_TAG "y") endif() # d using a debug version of your code string(APPEND _boost_DEBUG_ABI_TAG "d") # p using the STLport standard library rather than the # default one supplied with your compiler if(Boost_USE_STLPORT) string(APPEND _boost_RELEASE_ABI_TAG "p") string(APPEND _boost_DEBUG_ABI_TAG "p") endif() # n using the STLport deprecated "native iostreams" feature # removed from the documentation in 1.43.0 but still present in # boost/config/auto_link.hpp if(Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS) string(APPEND _boost_RELEASE_ABI_TAG "n") string(APPEND _boost_DEBUG_ABI_TAG "n") endif() # -x86 Architecture and address model tag # First character is the architecture, then word-size, either 32 or 64 # Only used in 'versioned' layout, added in Boost 1.66.0 set(_boost_ARCHITECTURE_TAG "") # {CMAKE_CXX_COMPILER_ARCHITECTURE_ID} is not currently set for all compilers if(NOT "x${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "x" AND NOT Boost_VERSION VERSION_LESS 106600) string(APPEND _boost_ARCHITECTURE_TAG "-") # This needs to be kept in-sync with the section of CMakePlatformId.h.in # inside 'defined(_WIN32) && defined(_MSC_VER)' if(${CMAKE_CXX_COMPILER_ARCHITECTURE_ID} STREQUAL "IA64") string(APPEND _boost_ARCHITECTURE_TAG "i") elseif(${CMAKE_CXX_COMPILER_ARCHITECTURE_ID} STREQUAL "X86" OR ${CMAKE_CXX_COMPILER_ARCHITECTURE_ID} STREQUAL "x64") string(APPEND _boost_ARCHITECTURE_TAG "x") elseif(${CMAKE_CXX_COMPILER_ARCHITECTURE_ID} MATCHES "^ARM") string(APPEND _boost_ARCHITECTURE_TAG "a") elseif(${CMAKE_CXX_COMPILER_ARCHITECTURE_ID} STREQUAL "MIPS") string(APPEND _boost_ARCHITECTURE_TAG "m") endif() if(CMAKE_SIZEOF_VOID_P EQUAL 8) string(APPEND _boost_ARCHITECTURE_TAG "64") else() string(APPEND _boost_ARCHITECTURE_TAG "32") endif() endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_RELEASE_ABI_TAG = ${_boost_RELEASE_ABI_TAG}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_DEBUG_ABI_TAG = ${_boost_DEBUG_ABI_TAG}") endif() # ------------------------------------------------------------------------ # Begin finding boost libraries # ------------------------------------------------------------------------ set(_Boost_VARS_LIB "") foreach(c DEBUG RELEASE) set(_Boost_VARS_LIB_${c} BOOST_LIBRARYDIR Boost_LIBRARY_DIR_${c}) list(APPEND _Boost_VARS_LIB ${_Boost_VARS_LIB_${c}}) _Boost_CHANGE_DETECT(_Boost_CHANGE_LIBDIR_${c} ${_Boost_VARS_DIR} ${_Boost_VARS_LIB_${c}} Boost_INCLUDE_DIR) # Clear Boost_LIBRARY_DIR_${c} if it did not change but other input affecting the # location did. We will find a new one based on the new inputs. if(_Boost_CHANGE_LIBDIR_${c} AND NOT _Boost_LIBRARY_DIR_${c}_CHANGED) unset(Boost_LIBRARY_DIR_${c} CACHE) endif() # If Boost_LIBRARY_DIR_[RELEASE,DEBUG] is set, prefer its value. if(Boost_LIBRARY_DIR_${c}) set(_boost_LIBRARY_SEARCH_DIRS_${c} ${Boost_LIBRARY_DIR_${c}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) else() set(_boost_LIBRARY_SEARCH_DIRS_${c} "") if(BOOST_LIBRARYDIR) list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${BOOST_LIBRARYDIR}) elseif(_ENV_BOOST_LIBRARYDIR) list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${_ENV_BOOST_LIBRARYDIR}) endif() if(BOOST_ROOT) list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${BOOST_ROOT}/lib ${BOOST_ROOT}/stage/lib) _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${BOOST_ROOT}") elseif(_ENV_BOOST_ROOT) list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${_ENV_BOOST_ROOT}/lib ${_ENV_BOOST_ROOT}/stage/lib) _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${_ENV_BOOST_ROOT}") endif() list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${Boost_INCLUDE_DIR}/lib ${Boost_INCLUDE_DIR}/../lib ${Boost_INCLUDE_DIR}/stage/lib ) _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${Boost_INCLUDE_DIR}/..") _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${Boost_INCLUDE_DIR}") if( Boost_NO_SYSTEM_PATHS ) list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) else() foreach(ver ${_Boost_KNOWN_VERSIONS}) string(REPLACE "." "_" ver "${ver}") _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "C:/local/boost_${ver}") endforeach() _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "C:/boost") list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} PATHS C:/boost/lib C:/boost /sw/local/lib ) endif() endif() endforeach() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_LIBRARY_SEARCH_DIRS_RELEASE = ${_boost_LIBRARY_SEARCH_DIRS_RELEASE}" "_boost_LIBRARY_SEARCH_DIRS_DEBUG = ${_boost_LIBRARY_SEARCH_DIRS_DEBUG}") endif() # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES if( Boost_USE_STATIC_LIBS ) set( _boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) if(WIN32) list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a) else() set(CMAKE_FIND_LIBRARY_SUFFIXES .a) endif() endif() # We want to use the tag inline below without risking double dashes if(_boost_RELEASE_ABI_TAG) if(${_boost_RELEASE_ABI_TAG} STREQUAL "-") set(_boost_RELEASE_ABI_TAG "") endif() endif() if(_boost_DEBUG_ABI_TAG) if(${_boost_DEBUG_ABI_TAG} STREQUAL "-") set(_boost_DEBUG_ABI_TAG "") endif() endif() # The previous behavior of FindBoost when Boost_USE_STATIC_LIBS was enabled # on WIN32 was to: # 1. Search for static libs compiled against a SHARED C++ standard runtime library (use if found) # 2. Search for static libs compiled against a STATIC C++ standard runtime library (use if found) # We maintain this behavior since changing it could break people's builds. # To disable the ambiguous behavior, the user need only # set Boost_USE_STATIC_RUNTIME either ON or OFF. set(_boost_STATIC_RUNTIME_WORKAROUND false) if(WIN32 AND Boost_USE_STATIC_LIBS) if(NOT DEFINED Boost_USE_STATIC_RUNTIME) set(_boost_STATIC_RUNTIME_WORKAROUND TRUE) endif() endif() # On versions < 1.35, remove the System library from the considered list # since it wasn't added until 1.35. if(Boost_VERSION AND Boost_FIND_COMPONENTS) if(Boost_VERSION LESS 103500) list(REMOVE_ITEM Boost_FIND_COMPONENTS system) endif() endif() # Additional components may be required via component dependencies. # Add any missing components to the list. _Boost_MISSING_DEPENDENCIES(Boost_FIND_COMPONENTS _Boost_EXTRA_FIND_COMPONENTS) # If thread is required, get the thread libs as a dependency if("thread" IN_LIST Boost_FIND_COMPONENTS) if(Boost_FIND_QUIETLY) set(_Boost_find_quiet QUIET) else() set(_Boost_find_quiet "") endif() find_package(Threads ${_Boost_find_quiet}) unset(_Boost_find_quiet) endif() # If the user changed any of our control inputs flush previous results. if(_Boost_CHANGE_LIBDIR_DEBUG OR _Boost_CHANGE_LIBDIR_RELEASE OR _Boost_CHANGE_LIBNAME) foreach(COMPONENT ${_Boost_COMPONENTS_SEARCHED}) string(TOUPPER ${COMPONENT} UPPERCOMPONENT) foreach(c DEBUG RELEASE) set(_var Boost_${UPPERCOMPONENT}_LIBRARY_${c}) unset(${_var} CACHE) set(${_var} "${_var}-NOTFOUND") endforeach() endforeach() set(_Boost_COMPONENTS_SEARCHED "") endif() foreach(COMPONENT ${Boost_FIND_COMPONENTS}) string(TOUPPER ${COMPONENT} UPPERCOMPONENT) set( _boost_docstring_release "Boost ${COMPONENT} library (release)") set( _boost_docstring_debug "Boost ${COMPONENT} library (debug)") # Compute component-specific hints. set(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT "") if(${COMPONENT} STREQUAL "mpi" OR ${COMPONENT} STREQUAL "mpi_python" OR ${COMPONENT} STREQUAL "graph_parallel") foreach(lib ${MPI_CXX_LIBRARIES} ${MPI_C_LIBRARIES}) if(IS_ABSOLUTE "${lib}") get_filename_component(libdir "${lib}" PATH) string(REPLACE "\\" "/" libdir "${libdir}") list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT ${libdir}) endif() endforeach() endif() # Handle Python version suffixes unset(COMPONENT_PYTHON_VERSION_MAJOR) unset(COMPONENT_PYTHON_VERSION_MINOR) if(${COMPONENT} MATCHES "^(python|mpi_python|numpy)([0-9])\$") set(COMPONENT_UNVERSIONED "${CMAKE_MATCH_1}") set(COMPONENT_PYTHON_VERSION_MAJOR "${CMAKE_MATCH_2}") elseif(${COMPONENT} MATCHES "^(python|mpi_python|numpy)([0-9])\\.?([0-9])\$") set(COMPONENT_UNVERSIONED "${CMAKE_MATCH_1}") set(COMPONENT_PYTHON_VERSION_MAJOR "${CMAKE_MATCH_2}") set(COMPONENT_PYTHON_VERSION_MINOR "${CMAKE_MATCH_3}") endif() unset(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME) if (COMPONENT_PYTHON_VERSION_MINOR) # Boost >= 1.67 list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") # Debian/Ubuntu (Some versions omit the 2 and/or 3 from the suffix) list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}-py${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-py${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") # Gentoo list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") # RPMs list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") endif() if (COMPONENT_PYTHON_VERSION_MAJOR AND NOT COMPONENT_PYTHON_VERSION_MINOR) # Boost < 1.67 list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}") endif() # Consolidate and report component-specific hints. if(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME) list(REMOVE_DUPLICATES _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Component-specific library search names for ${COMPONENT_NAME}: " "${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME}") endif() endif() if(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) list(REMOVE_DUPLICATES _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Component-specific library search paths for ${COMPONENT}: " "${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT}") endif() endif() # # Find headers # _Boost_COMPONENT_HEADERS("${COMPONENT}" Boost_${UPPERCOMPONENT}_HEADER_NAME) # Look for a standard boost header file. if(Boost_${UPPERCOMPONENT}_HEADER_NAME) if(EXISTS "${Boost_INCLUDE_DIR}/${Boost_${UPPERCOMPONENT}_HEADER_NAME}") set(Boost_${UPPERCOMPONENT}_HEADER ON) else() set(Boost_${UPPERCOMPONENT}_HEADER OFF) endif() else() set(Boost_${UPPERCOMPONENT}_HEADER ON) message(WARNING "No header defined for ${COMPONENT}; skipping header check") endif() # # Find RELEASE libraries # unset(_boost_RELEASE_NAMES) foreach(component IN LISTS _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME COMPONENT) foreach(compiler IN LISTS _boost_COMPILER) list(APPEND _boost_RELEASE_NAMES ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} ) endforeach() list(APPEND _boost_RELEASE_NAMES ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component} ) if(_boost_STATIC_RUNTIME_WORKAROUND) set(_boost_RELEASE_STATIC_ABI_TAG "-s${_boost_RELEASE_ABI_TAG}") foreach(compiler IN LISTS _boost_COMPILER) list(APPEND _boost_RELEASE_NAMES ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) endforeach() list(APPEND _boost_RELEASE_NAMES ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) endif() endforeach() if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_RELEASE_NAMES ${_boost_RELEASE_NAMES}) endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: ${_boost_RELEASE_NAMES}") endif() # if Boost_LIBRARY_DIR_RELEASE is not defined, # but Boost_LIBRARY_DIR_DEBUG is, look there first for RELEASE libs if(NOT Boost_LIBRARY_DIR_RELEASE AND Boost_LIBRARY_DIR_DEBUG) list(INSERT _boost_LIBRARY_SEARCH_DIRS_RELEASE 0 ${Boost_LIBRARY_DIR_DEBUG}) endif() # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing. string(REPLACE "\\" "/" _boost_LIBRARY_SEARCH_DIRS_tmp "${_boost_LIBRARY_SEARCH_DIRS_RELEASE}") if(Boost_USE_RELEASE_LIBS) _Boost_FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE RELEASE NAMES ${_boost_RELEASE_NAMES} HINTS ${_boost_LIBRARY_SEARCH_DIRS_tmp} NAMES_PER_DIR DOC "${_boost_docstring_release}" ) endif() # # Find DEBUG libraries # unset(_boost_DEBUG_NAMES) foreach(component IN LISTS _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME COMPONENT) foreach(compiler IN LISTS _boost_COMPILER) list(APPEND _boost_DEBUG_NAMES ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} ) endforeach() list(APPEND _boost_DEBUG_NAMES ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component} ) if(_boost_STATIC_RUNTIME_WORKAROUND) set(_boost_DEBUG_STATIC_ABI_TAG "-s${_boost_DEBUG_ABI_TAG}") foreach(compiler IN LISTS _boost_COMPILER) list(APPEND _boost_DEBUG_NAMES ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) endforeach() list(APPEND _boost_DEBUG_NAMES ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) endif() endforeach() if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_DEBUG_NAMES ${_boost_DEBUG_NAMES}) endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: ${_boost_DEBUG_NAMES}") endif() # if Boost_LIBRARY_DIR_DEBUG is not defined, # but Boost_LIBRARY_DIR_RELEASE is, look there first for DEBUG libs if(NOT Boost_LIBRARY_DIR_DEBUG AND Boost_LIBRARY_DIR_RELEASE) list(INSERT _boost_LIBRARY_SEARCH_DIRS_DEBUG 0 ${Boost_LIBRARY_DIR_RELEASE}) endif() # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing. string(REPLACE "\\" "/" _boost_LIBRARY_SEARCH_DIRS_tmp "${_boost_LIBRARY_SEARCH_DIRS_DEBUG}") if(Boost_USE_DEBUG_LIBS) _Boost_FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG DEBUG NAMES ${_boost_DEBUG_NAMES} HINTS ${_boost_LIBRARY_SEARCH_DIRS_tmp} NAMES_PER_DIR DOC "${_boost_docstring_debug}" ) endif () if(Boost_REALPATH) _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "${_boost_docstring_release}") _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "${_boost_docstring_debug}" ) endif() _Boost_ADJUST_LIB_VARS(${UPPERCOMPONENT}) # Check if component requires some compiler features _Boost_COMPILER_FEATURES(${COMPONENT} _Boost_${UPPERCOMPONENT}_COMPILER_FEATURES) endforeach() # Restore the original find library ordering if( Boost_USE_STATIC_LIBS ) set(CMAKE_FIND_LIBRARY_SUFFIXES ${_boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) endif() # ------------------------------------------------------------------------ # End finding boost libraries # ------------------------------------------------------------------------ set(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIR}) set(Boost_LIBRARY_DIRS) if(Boost_LIBRARY_DIR_RELEASE) list(APPEND Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIR_RELEASE}) endif() if(Boost_LIBRARY_DIR_DEBUG) list(APPEND Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIR_DEBUG}) endif() if(Boost_LIBRARY_DIRS) list(REMOVE_DUPLICATES Boost_LIBRARY_DIRS) endif() # The above setting of Boost_FOUND was based only on the header files. # Update it for the requested component libraries. if(Boost_FOUND) # The headers were found. Check for requested component libs. set(_boost_CHECKED_COMPONENT FALSE) set(_Boost_MISSING_COMPONENTS "") foreach(COMPONENT ${Boost_FIND_COMPONENTS}) string(TOUPPER ${COMPONENT} UPPERCOMPONENT) set(_boost_CHECKED_COMPONENT TRUE) if(NOT Boost_${UPPERCOMPONENT}_FOUND AND Boost_FIND_REQUIRED_${COMPONENT}) list(APPEND _Boost_MISSING_COMPONENTS ${COMPONENT}) endif() endforeach() if(_Boost_MISSING_COMPONENTS AND _Boost_EXTRA_FIND_COMPONENTS) # Optional indirect dependencies are not counted as missing. list(REMOVE_ITEM _Boost_MISSING_COMPONENTS ${_Boost_EXTRA_FIND_COMPONENTS}) endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] Boost_FOUND = ${Boost_FOUND}") endif() if (_Boost_MISSING_COMPONENTS) set(Boost_FOUND 0) # We were unable to find some libraries, so generate a sensible # error message that lists the libraries we were unable to find. string(APPEND Boost_ERROR_REASON "\nCould not find the following") if(Boost_USE_STATIC_LIBS) string(APPEND Boost_ERROR_REASON " static") endif() string(APPEND Boost_ERROR_REASON " Boost libraries:\n") foreach(COMPONENT ${_Boost_MISSING_COMPONENTS}) string(TOUPPER ${COMPONENT} UPPERCOMPONENT) string(APPEND Boost_ERROR_REASON " ${Boost_NAMESPACE}_${COMPONENT}${Boost_ERROR_REASON_${UPPERCOMPONENT}}\n") endforeach() list(LENGTH Boost_FIND_COMPONENTS Boost_NUM_COMPONENTS_WANTED) list(LENGTH _Boost_MISSING_COMPONENTS Boost_NUM_MISSING_COMPONENTS) if (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) string(APPEND Boost_ERROR_REASON "No Boost libraries were found. You may need to set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") else () string(APPEND Boost_ERROR_REASON "Some (but not all) of the required Boost libraries were found. You may need to install these additional Boost libraries. Alternatively, set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") endif () endif () if( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT ) # Compatibility Code for backwards compatibility with CMake # 2.4's FindBoost module. # Look for the boost library path. # Note that the user may not have installed any libraries # so it is quite possible the Boost_LIBRARY_DIRS may not exist. set(_boost_LIB_DIR ${Boost_INCLUDE_DIR}) if("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+") get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) endif() if("${_boost_LIB_DIR}" MATCHES "/include$") # Strip off the trailing "/include" in the path. get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) endif() if(EXISTS "${_boost_LIB_DIR}/lib") string(APPEND _boost_LIB_DIR /lib) elseif(EXISTS "${_boost_LIB_DIR}/stage/lib") string(APPEND _boost_LIB_DIR "/stage/lib") else() set(_boost_LIB_DIR "") endif() if(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}") set(Boost_LIBRARY_DIRS ${_boost_LIB_DIR}) endif() endif() else() # Boost headers were not found so no components were found. foreach(COMPONENT ${Boost_FIND_COMPONENTS}) string(TOUPPER ${COMPONENT} UPPERCOMPONENT) set(Boost_${UPPERCOMPONENT}_FOUND 0) endforeach() endif() # ------------------------------------------------------------------------ # Add imported targets # ------------------------------------------------------------------------ if(Boost_FOUND) # For header-only libraries if(NOT TARGET Boost::boost) add_library(Boost::boost INTERFACE IMPORTED) if(Boost_INCLUDE_DIRS) set_target_properties(Boost::boost PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}") endif() endif() foreach(COMPONENT ${Boost_FIND_COMPONENTS}) if(_Boost_IMPORTED_TARGETS AND NOT TARGET Boost::${COMPONENT}) string(TOUPPER ${COMPONENT} UPPERCOMPONENT) if(Boost_${UPPERCOMPONENT}_FOUND) if(Boost_USE_STATIC_LIBS) add_library(Boost::${COMPONENT} STATIC IMPORTED) else() # Even if Boost_USE_STATIC_LIBS is OFF, we might have static # libraries as a result. add_library(Boost::${COMPONENT} UNKNOWN IMPORTED) endif() if(Boost_INCLUDE_DIRS) set_target_properties(Boost::${COMPONENT} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}") endif() if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY}") set_target_properties(Boost::${COMPONENT} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION "${Boost_${UPPERCOMPONENT}_LIBRARY}") endif() if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE}") set_property(TARGET Boost::${COMPONENT} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties(Boost::${COMPONENT} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" IMPORTED_LOCATION_RELEASE "${Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE}") endif() if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG}") set_property(TARGET Boost::${COMPONENT} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties(Boost::${COMPONENT} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" IMPORTED_LOCATION_DEBUG "${Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG}") endif() if(_Boost_${UPPERCOMPONENT}_DEPENDENCIES) unset(_Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES) foreach(dep ${_Boost_${UPPERCOMPONENT}_DEPENDENCIES}) list(APPEND _Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES Boost::${dep}) endforeach() if(COMPONENT STREQUAL "thread") list(APPEND _Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES Threads::Threads) endif() set_target_properties(Boost::${COMPONENT} PROPERTIES INTERFACE_LINK_LIBRARIES "${_Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES}") endif() if(_Boost_${UPPERCOMPONENT}_COMPILER_FEATURES) set_target_properties(Boost::${COMPONENT} PROPERTIES INTERFACE_COMPILE_FEATURES "${_Boost_${UPPERCOMPONENT}_COMPILER_FEATURES}") endif() endif() endif() endforeach() endif() # ------------------------------------------------------------------------ # Notification to end user about what was found # ------------------------------------------------------------------------ set(Boost_LIBRARIES "") if(Boost_FOUND) if(NOT Boost_FIND_QUIETLY) message(STATUS "Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") if(Boost_FIND_COMPONENTS) message(STATUS "Found the following Boost libraries:") endif() endif() foreach( COMPONENT ${Boost_FIND_COMPONENTS} ) string( TOUPPER ${COMPONENT} UPPERCOMPONENT ) if( Boost_${UPPERCOMPONENT}_FOUND ) if(NOT Boost_FIND_QUIETLY) message (STATUS " ${COMPONENT}") endif() list(APPEND Boost_LIBRARIES ${Boost_${UPPERCOMPONENT}_LIBRARY}) endif() endforeach() else() if(Boost_FIND_REQUIRED) message(SEND_ERROR "Unable to find the requested Boost libraries.\n${Boost_ERROR_REASON}") else() if(NOT Boost_FIND_QUIETLY) # we opt not to automatically output Boost_ERROR_REASON here as # it could be quite lengthy and somewhat imposing in its requests # Since Boost is not always a required dependency we'll leave this # up to the end-user. if(Boost_DEBUG OR Boost_DETAILED_FAILURE_MSG) message(STATUS "Could NOT find Boost\n${Boost_ERROR_REASON}") else() message(STATUS "Could NOT find Boost") endif() endif() endif() endif() # Configure display of cache entries in GUI. foreach(v BOOSTROOT BOOST_ROOT ${_Boost_VARS_INC} ${_Boost_VARS_LIB}) get_property(_type CACHE ${v} PROPERTY TYPE) if(_type) set_property(CACHE ${v} PROPERTY ADVANCED 1) if("x${_type}" STREQUAL "xUNINITIALIZED") if("x${v}" STREQUAL "xBoost_ADDITIONAL_VERSIONS") set_property(CACHE ${v} PROPERTY TYPE STRING) else() set_property(CACHE ${v} PROPERTY TYPE PATH) endif() endif() endif() endforeach() # Record last used values of input variables so we can # detect on the next run if the user changed them. foreach(v ${_Boost_VARS_INC} ${_Boost_VARS_LIB} ${_Boost_VARS_DIR} ${_Boost_VARS_NAME} ) if(DEFINED ${v}) set(_${v}_LAST "${${v}}" CACHE INTERNAL "Last used ${v} value.") else() unset(_${v}_LAST CACHE) endif() endforeach() # Maintain a persistent list of components requested anywhere since # the last flush. set(_Boost_COMPONENTS_SEARCHED "${_Boost_COMPONENTS_SEARCHED}") list(APPEND _Boost_COMPONENTS_SEARCHED ${Boost_FIND_COMPONENTS}) list(REMOVE_DUPLICATES _Boost_COMPONENTS_SEARCHED) list(SORT _Boost_COMPONENTS_SEARCHED) set(_Boost_COMPONENTS_SEARCHED "${_Boost_COMPONENTS_SEARCHED}" CACHE INTERNAL "Components requested for this build tree.") # Restore project's policies cmake_policy(POP) pgagent-REL-4_2_2/cmake/FindPG.cmake000066400000000000000000000121541412006174200171170ustar00rootroot00000000000000####################################################################### # # FindPg.cmake - A CMake module for locating PostgreSQL # # Dave Page, EnterpriseDB UK Ltd. # This code is released under the PostgreSQL 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_SHARE_DIR - The directory containing architecture-independent PostgreSQL support files. # PG_VERSION_STRING - The PostgreSQL version number. # PG_MAJOR_VERSION - The PostgreSQL major version (x in x.y.z). # PG_MINOR_VERSION - The PostgreSQL minor version (y in x.y.z). # PG_EXTENSION - Set to TRUE if PostgreSQL supports extensions. 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) # Split the version into its component parts. STRING(REGEX MATCHALL "[0-9]+" PG_VERSION_PARTS "${PG_VERSION_STRING}") LIST(GET PG_VERSION_PARTS 0 PG_MAJOR_VERSION) IF((PG_MAJOR_VERSION LESS 10)) LIST(GET PG_VERSION_PARTS 1 PG_MINOR_VERSION) ENDIF((PG_MAJOR_VERSION LESS 10)) # Are extensions supported? IF((PG_MAJOR_VERSION GREATER 9) OR ((PG_MAJOR_VERSION EQUAL 9) AND (PG_MINOR_VERSION GREATER 0))) SET(PG_EXTENSION TRUE) ENDIF((PG_MAJOR_VERSION GREATER 9) OR ((PG_MAJOR_VERSION EQUAL 9) AND (PG_MINOR_VERSION GREATER 0))) 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") SET(PG_SHARE_DIR "${PG_ROOT_DIR}/share") # 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) EXEC_PROGRAM(${PG_CONFIG_PATH} ARGS --sharedir OUTPUT_VARIABLE PG_SHARE_DIR) 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") IF(_op MATCHES "ldap_init") LIST(APPEND PG_LIBRARIES "ldap") ENDIF(_op MATCHES "ldap_init") 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) pgagent-REL-4_2_2/cmake/MakeExt.cmake000066400000000000000000000015501412006174200173440ustar00rootroot00000000000000####################################################################### # # pgAgent - PostgreSQL tools # Copyright (C) 2002 - 2021, The pgAdmin Development Team # This software is released under the PostgreSQL Licence # # MakeExt,cmake - Create the PG Extension # ####################################################################### FILE(READ ${PGAGENT_SOURCE_DIR}/sql/pgagent.sql PGAGENT_SQL) STRING(REPLACE "BEGIN TRANSACTION;" "" PGAGENT_SQL "${PGAGENT_SQL}") STRING(REPLACE "COMMIT TRANSACTION;" "" PGAGENT_SQL "${PGAGENT_SQL}") STRING(REPLACE "CREATE SCHEMA pgagent;" "" PGAGENT_SQL "${PGAGENT_SQL}") STRING(REPLACE "-- EXT SELECT" "SELECT" PGAGENT_SQL "${PGAGENT_SQL}") FILE(WRITE "${CMAKE_BINARY_DIR}/pgagent--${MAJOR_VERSION}.${MINOR_VERSION}.sql" "${PGAGENT_SQL}") CONFIGURE_FILE(${PGAGENT_SOURCE_DIR}/pgagent.control.in ${CMAKE_BINARY_DIR}/pgagent.control) pgagent-REL-4_2_2/connection.cpp000066400000000000000000000242071412006174200165730ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // connection.cpp - database connection // ////////////////////////////////////////////////////////////////////////// #include "pgAgent.h" #include namespace ip = boost::asio::ip; DBconn *DBconn::ms_primaryConn = NULL; CONNinfo DBconn::ms_basicConnInfo; static boost::mutex s_poolLock; DBconn::DBconn(const std::string &connectString) : m_inUse(false), m_next(NULL), m_prev(NULL), m_minorVersion(0), m_majorVersion(0) { m_connStr = connectString; Connect(connectString); } bool DBconn::Connect(const std::string &connStr) { LogMessage(("Creating DB connection: " + connStr), LOG_DEBUG); m_conn = PQconnectdb(connStr.c_str()); if (PQstatus(m_conn) != CONNECTION_OK) { m_lastError = (const char *)PQerrorMessage(m_conn); PQfinish(m_conn); m_conn = NULL; return false; } return (m_conn != NULL); } DBconn::~DBconn() { // clear a single connection if (m_conn) { PQfinish(m_conn); m_conn = NULL; } } std::string DBconn::qtDbString(const std::string &value) { std::string result = value; boost::replace_all(result, "\\", "\\\\"); boost::replace_all(result, "'", "''"); result.append("'"); if (BackendMinimumVersion(8, 1)) { if (result.find("\\") != std::string::npos) result.replace(0, 0, "E'"); else result.replace(0, 0, "'"); } else result.replace(0, 0, "'"); return result; } bool DBconn::BackendMinimumVersion(int major, int minor) { if (!m_majorVersion) { std::string ver = ExecuteScalar("SELECT version();"); sscanf(ver.c_str(), "%*s %d.%d", &m_majorVersion, &m_minorVersion); } return m_majorVersion > major || (m_majorVersion == major && m_minorVersion >= minor); } DBconn *DBconn::InitConnection(const std::string &connectString) { MutexLocker locker(&s_poolLock); if (!ms_basicConnInfo.Set(connectString)) { ms_primaryConn = NULL; // Unlock the mutex before logging error. locker = (boost::mutex *)NULL; LogMessage( "Primary connection string is not valid!\n" + ms_basicConnInfo.GetError(), LOG_ERROR ); } ms_primaryConn = new DBconn(ms_basicConnInfo.Get()); if (ms_primaryConn == NULL) { // Unlock the mutex before logging error. locker = (boost::mutex *)NULL; LogMessage( "Failed to create primary connection... out of memory?", LOG_ERROR ); } if (ms_primaryConn->m_conn == NULL) { std::string error = ms_primaryConn->GetLastError(); delete ms_primaryConn; ms_primaryConn = NULL; LogMessage( "Failed to create primary connection: " + error, LOG_WARNING ); return NULL; } ms_primaryConn->m_inUse = true; return ms_primaryConn; } DBconn *DBconn::Get(const std::string &_connStr, const std::string &db) { std::string connStr; if (!_connStr.empty()) { CONNinfo connInfo; if (!connInfo.Set(_connStr)) { LogMessage( "Failed to parse the connection string \"" + _connStr + "\" with error: " + connInfo.GetError(), LOG_WARNING ); return NULL; } connStr = connInfo.Get(); } else { connStr = DBconn::ms_basicConnInfo.Get(db); } MutexLocker locker(&s_poolLock); DBconn *thisConn = ms_primaryConn; DBconn *lastConn = NULL; // find an existing connection do { if (thisConn && !thisConn->m_inUse && thisConn->m_connStr == connStr) { LogMessage(( "Using the existing connection '" + CONNinfo::Parse(thisConn->m_connStr, NULL, NULL, true) + "'..."), LOG_DEBUG ); thisConn->m_inUse = true; return thisConn; } lastConn = thisConn; if (thisConn != NULL) thisConn = thisConn->m_next; } while (thisConn != NULL); // No suitable connection was found, so create a new one. DBconn *newConn = new DBconn(connStr); if (newConn && newConn->m_conn) { LogMessage(( "Allocating new connection for the database with connection string: " + CONNinfo::Parse(newConn->m_connStr, NULL, NULL, true) + "..." ), LOG_DEBUG); newConn->m_inUse = true; newConn->m_prev = lastConn; lastConn->m_next = newConn; } else { std::string warnMsg; if (connStr.empty()) warnMsg = ( "Failed to create new connection to database '" + db + "'" + (newConn != NULL ? ": " + newConn->GetLastError() : "") ); else warnMsg = ( "Failed to create new connection for connection string '" + connStr + "'" + (newConn != NULL ? ": " + newConn->GetLastError() : "") ); LogMessage(warnMsg, LOG_STARTUP); if (newConn != NULL) { delete newConn; newConn = NULL; } return NULL; } return newConn; } void DBconn::Return() { MutexLocker locker(&s_poolLock); // Cleanup ExecuteVoid("RESET ALL"); m_lastError.empty(); m_inUse = false; LogMessage(( "Returning the connection to the connection pool: '" + CONNinfo::Parse(m_connStr, NULL, NULL, true) + "'..." ), LOG_DEBUG); } void DBconn::ClearConnections(bool all) { MutexLocker locker(&s_poolLock); if (all) LogMessage("Clearing all connections", LOG_DEBUG); else LogMessage("Clearing inactive connections", LOG_DEBUG); DBconn *thisConn = ms_primaryConn, *deleteConn; int total = 0, free = 0, deleted = 0; if (thisConn) { total++; // Find the last connection while (thisConn->m_next != NULL) { total++; if (!thisConn->m_inUse) free++; thisConn = thisConn->m_next; } if (!thisConn->m_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->m_prev != NULL) { if ((!thisConn->m_inUse) || all) { deleteConn = thisConn; thisConn = deleteConn->m_prev; thisConn->m_next = deleteConn->m_next; if (deleteConn->m_next) deleteConn->m_next->m_prev = deleteConn->m_prev; delete deleteConn; deleted++; } else { thisConn = thisConn->m_prev; } } if (all) { delete thisConn; ms_primaryConn = NULL; deleted++; } LogMessage((boost::format( "Connection stats: total - %d, free - %d, deleted - %d" ) % total % free % deleted).str(), LOG_DEBUG); } else LogMessage("No connections found!", LOG_DEBUG); } DBresult *DBconn::Execute(const std::string &query) { DBresult *res = new DBresult(this, query); if (!res->IsValid()) { // error handling here delete res; return 0; } return res; } std::string DBconn::ExecuteScalar(const std::string &query) { int rows = -1; DBresultPtr res = Execute(query); std::string data; if (res) { data = res->GetString(0); rows = res->RowsAffected(); return data; } return data; } int DBconn::ExecuteVoid(const std::string &query) { int rows = -1; DBresultPtr res = Execute(query); if (res) { rows = res->RowsAffected(); } return rows; } std::string DBconn::GetLastError() { boost::algorithm::trim(m_lastError); return m_lastError; } ///////////////////////////////////////////////////////7 DBresult::DBresult(DBconn *conn, const std::string &query) { m_currentRow = 0; m_maxRows = 0; m_result = PQexec(conn->m_conn, query.c_str()); if (m_result != nullptr) { int rc = PQresultStatus(m_result); conn->SetLastResult(rc); if (rc == PGRES_TUPLES_OK) m_maxRows = PQntuples(m_result); else if (rc != PGRES_COMMAND_OK) { conn->m_lastError = PQerrorMessage(conn->m_conn); LogMessage("Query error: " + conn->m_lastError, LOG_WARNING); PQclear(m_result); m_result = nullptr; } } else conn->m_lastError = PQerrorMessage(conn->m_conn); } DBresult::~DBresult() { if (m_result) { PQclear(m_result); m_result = NULL; } } std::string DBresult::GetString(int col) const { std::string str; if (m_result && m_currentRow < m_maxRows && col >= 0) { str = (const char *)PQgetvalue(m_result, m_currentRow, col); } return str; } std::string DBresult::GetString(const std::string &colname) const { // Below function will return -1 if string is NULL or does not match. int col = PQfnumber(m_result, colname.c_str()); if (col < 0) { // fatal: not found return ""; } return GetString(col); } const std::string CONNinfo::Parse( const std::string& connStr, std::string *error, std::string *dbName, bool forLogging ) { std::stringstream res; PQconninfoOption *opts, *opt; char *errmsg = nullptr; if (error != nullptr) *error = ""; if (connStr.empty()) { if (error != nullptr) *error = "Empty connection string"; return res.str(); } // Parse Keyword/Value Connection Strings and Connection URIs opts = PQconninfoParse(connStr.c_str(), &errmsg); if (errmsg != nullptr || opts == NULL) { if (errmsg != nullptr) { if (error != nullptr) *error = errmsg; PQfreemem(errmsg); } else if (error != nullptr) { *error = "Failed to parse the connection string"; } return res.str(); } std::string val; bool atleastOneParameter = false; LogMessage("Parsing connection information...", LOG_DEBUG); // Iterate over all options for (opt = opts; opt->keyword; opt++) { if (opt->val == NULL) continue; if (opt->dispchar[0] == 'D') continue; if (!forLogging) val = opt->dispchar[0] == '*' ? "*****" : opt->val; else { val = opt->val; LogMessage(( boost::format("%s: %s") % opt->keyword % (opt->dispchar[0] == '*' ? "*****" : val)).str(), LOG_DEBUG ); } // Create plain keyword=value connection string. used // to find pooled connections in DBconn::Get() and to // open the connection in DBconn::Connect. this works // because PQconninfoParse() always returns the // connection info options in the same order. if (atleastOneParameter) res << ' '; atleastOneParameter = true; if ( dbName != NULL && strncmp(opt->keyword, "dbname", strlen(opt->keyword)) == 0 ) *dbName = val; res << opt->keyword << "=" << val; } PQconninfoFree(opts); return res.str(); } bool CONNinfo::Set(const std::string& connStr) { m_connStr = CONNinfo::Parse(connStr, &m_error, &m_dbName); return !m_connStr.empty(); } const std::string CONNinfo::Get(const std::string &dbName) const { if (m_connStr.empty()) return m_connStr; return ( m_connStr + " dbname=" + "" + (dbName.empty() ? m_dbName : dbName) ); } pgagent-REL-4_2_2/include/000077500000000000000000000000001412006174200153465ustar00rootroot00000000000000pgagent-REL-4_2_2/include/connection.h000066400000000000000000000075511412006174200176660ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // connection.h - database connection // ////////////////////////////////////////////////////////////////////////// #ifndef CONNECTION_H #define CONNECTION_H #include class DBresult; class CONNinfo { public: bool Set(const std::string& connStr); const std::string Get(const std::string &dbName="") const; const std::string& GetError() const { return m_error; } static const std::string Parse( const std::string& connStr, std::string *error, std::string *dbName, bool forLogging=false ); operator bool() const { return m_connStr.empty(); } private: std::string m_connStr; std::string m_dbName; std::string m_error; }; class DBconn { protected: DBconn(const std::string& connStr); ~DBconn(); public: static DBconn *Get(const std::string &connStr="", const std::string &db=""); static DBconn *InitConnection(const std::string &connectString); static void ClearConnections(bool allIncludingPrimary = false); std::string qtDbString(const std::string &value); bool BackendMinimumVersion(int major, int minor); std::string GetLastError(); operator bool() const { return m_conn != NULL; } DBresult *Execute(const std::string &query); std::string ExecuteScalar(const std::string &query); int ExecuteVoid(const std::string &query); void Return(); const std::string &DebugConnectionStr() const; bool LastCommandOk() { return IsCommandOk((ExecStatusType)m_lastResult); } bool IsCommandOk(ExecStatusType ret) { switch (ret) { case PGRES_COMMAND_OK: case PGRES_TUPLES_OK: case PGRES_COPY_OUT: case PGRES_COPY_IN: #if (PG_VERSION_NUM >= 90100) case PGRES_COPY_BOTH: #endif return true; default: return false; }; } void SetLastResult(int res) { m_lastResult = res; } int GetLastResult() { return m_lastResult; } private: bool Connect(const std::string &connectString); int m_minorVersion, m_majorVersion; protected: static CONNinfo ms_basicConnInfo; static DBconn *ms_primaryConn; std::string m_lastError; std::string m_connStr; PGconn *m_conn; DBconn *m_next; DBconn *m_prev; bool m_remoteDatabase; bool m_inUse; int m_lastResult; friend class DBresult; }; class DBresult { protected: DBresult(DBconn *conn, const std::string &query); public: ~DBresult(); std::string GetString(int col) const; std::string GetString(const std::string &colname) const; bool IsValid() const { return m_result != NULL; } bool HasData() const { return m_currentRow < m_maxRows; } void MoveNext() { if (m_currentRow < m_maxRows) m_currentRow++; } long RowsAffected() const { return atol(PQcmdTuples(m_result)); } protected: PGresult *m_result; int m_currentRow, m_maxRows; friend class DBconn; }; class DBresultPtr { public: DBresultPtr(DBresult* in_ptr) : m_ptr(in_ptr) {} ~DBresultPtr() { if (m_ptr) { delete m_ptr; m_ptr = NULL; } } DBresultPtr& operator=(DBresult *other) { if (m_ptr) { delete m_ptr; } m_ptr = other; return *this; } const DBresult& operator*() const { return (*(const DBresult *)m_ptr); } const DBresult* operator->() const { return (const DBresult*)(m_ptr); } DBresult& operator*() { return (*(DBresult *)m_ptr); } DBresult* operator->() { return (DBresult *)m_ptr; } operator void*() const { return (DBresult *)m_ptr; } operator bool() const { return (m_ptr != NULL); } protected: DBresult* m_ptr; }; #endif // CONNECTION_H pgagent-REL-4_2_2/include/job.h000066400000000000000000000014141412006174200162710ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // job.h - agent job // ////////////////////////////////////////////////////////////////////////// #ifndef JOB_H #define JOB_H #include class Job { public: Job(DBconn *conn, const std::string &jid); ~Job(); int Execute(); bool Runnable() { return m_status == "r"; } protected: DBconn *m_threadConn; std::string m_jobid, m_logid; std::string m_status; }; class JobThread { public: JobThread(const std::string &jid); ~JobThread(); void operator()(); private: std::string m_jobid; }; #endif // JOB_H pgagent-REL-4_2_2/include/misc.h000066400000000000000000000027031412006174200164540ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // misc.h - misc functions // ////////////////////////////////////////////////////////////////////////// #ifndef MISC_H #define MISC_H void WaitAWhile(const bool waitLong = false); void setOptions(int argc, char **argv, const std::string &executable); std::string getArg(int &argc, char **&argv); std::string NumToStr(const long l); void printVersion(); #if BOOST_OS_WINDOWS std::wstring s2ws(const std::string &str); std::string ws2s(const std::wstring &wstr); #endif std::string generateRandomString(size_t length); std::string getTemporaryDirectoryPath(); class MutexLocker { public: MutexLocker(boost::mutex *lock): m_lock(lock) { if (m_lock != NULL) m_lock->lock(); } ~MutexLocker() { if (m_lock != NULL) m_lock->unlock(); m_lock = NULL; } // When the exit(code) is being called, static object is being released // earlier. Hence - it is a good idea to set the current mutex object to // NULL to avoid ASSERTION in debug mode (specifically on OSX). MutexLocker& operator =(boost::mutex *lock) { if (m_lock != NULL) m_lock->unlock(); m_lock = lock; if (m_lock != NULL) m_lock->lock(); return *this; } private: boost::mutex *m_lock; }; #endif // MISC_H pgagent-REL-4_2_2/include/pgAgent.h000066400000000000000000000033701412006174200171070ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // pgAgent.h - main include // ////////////////////////////////////////////////////////////////////////// #ifndef PGAGENT_H #define PGAGENT_H #if BOOST_OS_WINDOWS #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "misc.h" #include "connection.h" #include "job.h" extern long longWait; extern long shortWait; extern long minLogLevel; extern std::string connectString; extern std::string backendPid; #if !BOOST_OS_WINDOWS extern bool runInForeground; extern std::string 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(const std::string &msg, const int &level); void MainLoop(); #if BOOST_OS_WINDOWS void CheckForInterrupt(); HANDLE win32_popen_r(const WCHAR *command, HANDLE &handle); #endif #endif // PGAGENT_H pgagent-REL-4_2_2/include/pgAgent.ico000066400000000000000000000463161412006174200174410ustar00rootroot00000000000000hv ¨Þ00¨†h. ¨ – 00¨>- èæI( @iEˆa.Žb/‹g/Žf/‹h.‘e/ƒa2…a5ƒd4†g6ˆb2b2Šd2Žd1‰b5Œc5Žd6a8„b9…d9Šc9Še9‡i?‰h8h:‰h=b2‘e1”e0‘c4h?‰eA‰mFŠkHŠpKqH™rJˆvW˜vV–|Y˜}Xž}]œ€]£^’…`œƒa¢„a¦ˆa¡Žk Žnª–n¡u¥”w«—u­–u²}´¡|£•„®¡Š­¥‹¬£º©†½©…¶¤‹¸¦´ª½©Œ´¥“·«‘¸ª‘»¬‘¾¯•½­š¿°’¸°•¼²•À¬ŒÁ¯Ä±‘ĵ“À´•Å·”È´—µ˜Ä¸›Å· Ç¿§Çº¨Ç¾©È¿¯ÉÀ´ÉŶËźÏɼÓÉ»ÔÌ»ÊÆÁÓÏÂÕÏÀÜÔÃÙÑÇßÜÔáÙÎáÞ×åßÕæá×ãáÙîëæîîìñíçñîéóðêôòîc#)k6/0&- ej=]+oA_l=(Z;bg"_AMCnBD" Q Z^,Q 94'FjrN8!Q$:2cQ8MM.@JNQV9DZVeF8+60VjQ $F_F EC 2Q Jrrrm][rÿÿÿÿèÄ€€€€Îc( @€tY7~Z2z_2~_0}[4}]5t]:z_:}a3wb<|c;w_@kcGtbF}eArfLxdN}kK|mR~pRƒ^/ƒ_1†_1[5]6†\5Œ^3‹_6_7…^:^;^4ƒa-d+ˆ`/c,‰e.f.‰h.Œh-‘c.•c/‘e.–f.™d/h.”h/a2…a1„d2‚a6…a5†e7‰b1b1Šd2e1‰a5a5‰d4d4‚c9„b9ƒe9„d;„e>Šb8†h?‹h;‘b2”c2‘e1”e0’b5•b5d4•e6˜c1–h2b8ƒdC„kFˆkC„kL‰lIŽqAsLvI“sO“tNœzOoP‹vS‰qTŒqWtXƒ}^Š{[”{Uš~U”vY™~[¡\†u`ŠubŽ{`{iž`–Zœ‚[¡€V¥„Y“‚d™…c—†l™‚jœiš…j…iІs’‰pœ‹p˜Šu™‹yž“w˜}¡‡e¥‰g¨Œc¤Œk«‘n¢Žs¥Žx ’sª”t«˜q£’|ª—}¬™|¶¤~™’†¥–ƒ¢ž‡ª›ƒ¥™Š²œ‚®¤ƒ¬ Ž¶¥†¸£†¸¨…³£Œ»¦ˆ´¨¸¨‹¿®ˆ¼ª¾³¯¡‘°¦“µ¬“»¬’»ª”¼¯”¾¯œº³–¸³˜³¯«»´¢Ã¯‹Ä´•Ǻ•Á·œÎ»›Å¶¡È·¡Å½ ÇìÊÀ®ÑÃ¤ÕÆ«ÓÉ«Ùέ×ЬÛÒ­Ì±ËżÐɵÚ˲ÑɹÔ͹ÑȼÕʼÖοØÌ»ÚѲÜÓ¼ßÜ¿âÕ´áØ²áÕ¼åÜ¿æà¿ÍÎÅÔÑÂÛÔÃÙÓÇßÓÅÝ×ÇÔÒËÚÓËÜÚÉßÚÑßÝÙâ×ÃãÙÃèÚÀäÜÌáÞÑäßÒâÞÖèÜÑàßÛçàÂëàÂäáËìäËäàÓêäÓäãÞëåÛïéÚëèßíéßòìßßßàçäàéèæìêåîìäëëéíëèîíêðêáðïàñïäñíêõñêòóìúôëõóòøöñûøòùøôüüôóÎv]v¢öÝz2„êÁG=GGA¥­G==/ŠóA===(=ð™$G=( gùß–==G((GZÿóæðÒ•G-G( Uçû»©ÁÕÌ’ G-$$GSÕÞv•ð»‘{â’GG$$=ÝÿúúçrA³óÕÁ •G(($=Á h¨ó°A$=TÁæ²ÃlG=(/=¯¼”ÎææûÝS=GGÚçÒÁâ}=PPPGGG=¼Ö©A=/‚ØzcØPGGPP-/=råßÖÎv=*G=WÃ}AA½“$-=PGGGP¼ÃÒÒÖÉUG**=ØQ(’¶-==G-=ZØxÔ‘ÿó«AG**=ƒÅ2==A]ÅGGG-GA‹âiÁùA***=‚É ==T´QPGGGP]¹Q\à]…ÿåU=**/=fáD=GPQ´TG*P œ´mÈUTÒÁGG**=cáS===UµSP==E ň$rÅE† $=G*=nØSnj·P=PGTáb2bÈV(Qðí‰==GG*=nãq †Ø¥¸=PG=SÊ}žaã[*ÃÝvP$GG*=nãʶ¦©ØŒGGGG¬Í±åpGÝeG/=G*=cásˆ®®‡S=G====VœÅÃêp*=‚ÿãeP/=G==SÎr=====O*$Ž·E==[ðÚr=-===(¬ªA$$====P(G-G=bÃ=G=cçê•=PP=GPbà]G===P=G-PA æ=GPjçÁ A=GP=P ¶¦=P==G/A’¶TAP ÿ÷  =====AjΆ2==A\¬ÅE2AQ’ÿݱW2 QkÁð¦R222Q‹Å´n2\­÷öÔÁÁÓðêÁ²²Úöÿâz{†š¼öûÝÓðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿâýàøÀð`à8À?ÀÀ€€€€€€€€Àð<ÿÿü?(0`€ ^M8YS5y[,gS3mS3lY6dW8kU:fZ=n[9sV2}V4t[4z[3tV;{V9t];{\:}b,nc4vc6|`3ua={b;h;iXAw[Bk`GtaA|cC~iCwcI|kK|qNnjT|kUzqY|vd„],€\2‰[3€V9ƒ\:_:”_6ƒb.Œb-†i-‹i-’e-šc.”h.„b4‹d3„h1‹h1ƒc:‹c9Œi=’d2™d1“h2™i3“a9˜b9’j9™j8„jF‹pFpHŒpLgR‚lSŒoP„qT‹sRŒ|UŒu]‰|[’{Tœ~Q“|Z™~Z‡vd“|b^”‚]›ƒ^¢…]Še’‚e‚cžŠg“€o›‚j“Šj‰l’kˆ†y“„r”‹s›Œt‰|Ÿ{˜’y¡‹d¢Šm©nª“m£t©”s«›q£”zª”z¦š|«š|°–q´œ{¬ {°¥}‹ˆ†˜š”†¥™·Ÿ‰©œ’®¡‰²£†¿¤ƒµ¦¸¤ˆµ¨Šº¨‹¯¢–³ª“¼«“·®Ÿ¾¯š½°‘³³¼±œ¾¸¨¦¡²­¥¶³£½µ ²³ª·º¯¶´±¹´²¾»·Â«‰Á¯—IJ‘ɳ‘óœÎ¶œÂ¸ÊºœÑ¼žÈ»¥Ð½¦Á¿½Ë¼»ÎœÒÄŸÌèÖÂ¥ÓÅ©ÙÆªÓÈ­Û̬ÌɳļÍȹÓÃ²ÚÆ±Ô˲Ú̲ÖÇ¿ÓÌ»ÜÍ»ÓÑ·ÜÒµÐÑ»ÛѾÛÙ½âβàÓµäÚ´èÚ·âÕ»âÙ»êá¼ÆÂÅÎÆÃÌÊÄÎÏÊÑËÅÔÎËÜÓÃÔÑÌÛÕÊÚÙËÕÔÓÙÔÐÝÚÒÕרÞÜÛàÖÁäÚÂëÛÁã×ÈâÚËëÜÉóßÌâÝÓÞãÜëãÄéãÊïèÏóèÊääÔëäÒíéÓäãÛëåÛéëÝôæÐôëÔøîÓóìÜùíÞìðÕü÷ÚæäãêæâìíæëêéòìáñîëùïîìñãõòäúôãýúãôòëúõêóøèýýëôóòùõòöùòýûôýüúÏøˆUUqŠàøÇõf ‚ø÷Ž(6666( ˆ÷ø[ 6=6<<<5IÖÜK<266>>6°ìÕ!6=+:>46 ˆÇ¸6616684<(…˳:(80=<00<)vÌâ«+<60=108=)l䮫+@11=<08<)Xø“©+<<<3<08=)Rø÷ñÅÆ®Îÿ“«+A<4=408<)Jè¤ìíãËáúü–”§+<=>=601<@DàÄïòΖïÑ&#[ýüŽ:-=>3406<@Ëï÷¨Eoüïãñâµfiö¢,@>80041::°ôØåøúñÖD(1¡ï®Ëø §±:6<80421:¢ðdIITzÊÄüa)6(H²ï®÷i²+<>8804/(5œð%$^gcy£÷¬:12>JÕÊîè»ç\*:@<66<4>6(nøÕ¡ÖÿÆôX<22<5HÌàÙôù·t(@<<8@8><<85iàì÷÷’66<4>1!Óùœ&˜ùO:<<@::<<=><6 `è÷ï–üZ :566<1:¡ör QëŒ B=<>6@@<=?>6EÕüÇÐÐýÇØ668><6këŸ:;¼áF5336::B=4?<(ùáßýÆè‹<42426ŸøR666lùw43<76<4436EØÕgù{Ä÷—ø\624466DÔº566:Dا<=<5<<==>(jùn#ùTøËØD:<<4426Eا:666+¥Â6=>5==?<5¦¼#ê¡´üã¡:8224<69س561@:rÛF)==8==<:RÞk%ù^éér6<222<6:ÀÕ52<6:\Û!,@<<=<@: ¥ÂD Mö˜³íèP(<2224<5¨ÞD.?><6UÜK+A=426:!ç¥bëm+rüí¶62>224>6ŸçG62=<:*\Ø%+@<<>7 ˜öY((pëY+:F¹ý‚<2<<<416 åE+666/ qÛE6:::>B5Á¿8(töW.|üîf*<1<<<326¨åD((5:„ÂB6:@:>8Gç¥ (qöj.0(KðßN(@6<<>4155¦åD‹ÀZ§Á56<@@2<:Wö MZùv.21µîÚÖD,<0@><226:³ù…!M»á‡Ü¥(<<=A2<5EاgÞx#ù¦/2<ˆøâÕ -<0<<4425¬ùöÂbi{­öp'<<<=<>5‹ù’Žb%õ«/==*kø÷¡->0<<<426(Ÿç€½çööùö˜51<<<<61<6E¬ùÛÛßü«<<=4>>2446‹øKPuvQ(<68856<64.7p¦­ÕÿŸ126)6»úŠ*A>18<>486(tør 5((((,:<>68766>426~øk(261(¦ÿôŸ;33886567.Xç›502/>@:66861:·ÛD511228:<<6<:><==<@7­çY)<<>6‹üÏåK<6<<6<6<<töv5<3<666B6<643<<:: „ú…66<<6¡ýúq :6<<@<<<@"Þ¾:1<6<6666<2?>:: Rù³6><): ÕýÙÕ :6<6@<@>5tú‚:66;66666C<:FÓ¿I5:56:{øìüˆ6668868:ºèe58686566::YÁÞR(;5;nõÆøx'8866866:TäÜ`6866..6FtÞëm'0<.6}èÿÎú«jD  H^‚ÙùŽW55M€Óö¾M5([°øýëܧœ‡‡¡µÑøÿñüø¸˜||€Ÿ³äùúŽHEO|²÷ÿýÎñÿÿÿüÑâüüÿÿÿðËÕÕÜèúü÷ËÆÃñÿÿÿ€?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿýÿþ ÿþüøÀøà?ð`à¿à?À?ÀÀÀÀÀ€€€€€€€€ÀÀ ø0üøÿÿÿÿáÿ( @ÐɸŠkH–|YÛÓÅþþþ£’tŽc2f1œƒaöõôøøö¢„ae0‹g/™rJóòíööõïîìççä£^“f/‹g/h?ôïêóîêʾ°ïîíÚÖΪ¡ŒÈÄ´ž}]”f1‹h.Šc9êåÜü÷ðýýûõôò²ž„ˆb2Ÿ¥òñîßÜÓ­¥‹˜vVf3Žg/ˆb3Ǻ¨Ÿ~»¶°îìéÿÿÿØÔʆd9f0ŠnGÑȶ©›ƒ¸°•c5Žd6“d2e2µªããàðï︦e0Že1½©Œ‰mF†b7µ˜Žb/‹d3•e0h:Ǿ©ÊĹøöôõó]‘e/e0İ“„b6‹c4±~‹d:“d1‘c4ª–nˆvW¸ª‘ÙÏÁëæÝ‰c6‘e/e0À¬ŒŠf9Žc2¬•w‰eAe1‚c9ĵ“qH´¡|ŠiþþýÊĵŒb3’e2Že/IJiE«—u½³”Œc4“c4‰h=¼²—’…`½©…ˆb5ìé཭šf1’e2f0Á¯¿°’ĸ›³ž}Žd0d2‹d2º©†Ç¿§È´—b1Ñů¾¯•“d2Œe3Še2®—t˜}Xˆa.c6e3‹e3”d1d1¡u¦ˆad3¾®”ÙЀ`8c3c3‡i?À´•…`5d3Œd3e2e3ŠpK»¬‘†b5‰a5Ž­ôòñµ©Ž‰h8ƒb3„b9³¤’®¤‡†g6ƒa1…d8¡ŽkÅ·”ƒd4…f:¸¦‘ûûøúúúîêáæáÙîëåûùöø÷öëæÜâÜÒñïäôñéÀ¶§Ã¹¨êæÞþþþÿþþøÀ€€( @€ èæàÝ×Ç™‚j‰qTš…j»ª”ëä×ûúößÚÊœ‹p~Z2†_1„`2€_6¡qåàÕÐȱ~fB‘e2d0‘f1‘f1„d;¾¯œöõõþýûÁ·œ|d@d2ˆa4Œe4”h/„`2ª—}äáÝÿÿÿõôñ¼ª…a9Šf1c1‹f2Œh/`2¥‰gäãÙýýýïî黦ˆ‹_6‰g/“f/g/‰h/`3¡\ëìáþþþÿÿÿÿÿÿÿÿÿÿÿÿÓÒ͸£†Ž`7e.•f0g/Ši/‘`3“sOøóèýüüùùøãáßÝÛ×àßÜÿÿÿËÌÆ·¤†_7’g0–e/g/‰h._2ŒlHìáÖñííûúúúööìèåðïíúúùäâãëèäÌÄ»¹³¢ÑʳÜ×ÍÍÎŲŸ€^7–f0—e0g/‰h.“c6‡fBߨÎñïîñïíå×Ɇk®œ…÷õñèççèåÞÊÆ¼¤šˆ|mR’‰päáα›‚†];”e3g0‹h.Œh.‹b1„c;áÙËöóêöìÞûóåýûôûûùÿÿÿñïîåÝÒ˜‚e…`0ƒa7ø¥øõî÷÷÷ÝÜÙßÝÔÒʹkcG©Ÿ…·ž†‚^;‘e4Œg0‹h.h.‰b0„a6Ùʸ¯¡‘xdN†u`™’†³¯«ïììúø÷ûûûèæáÆ´œ„e>c,e2‡nOÒÆ±ù÷ðùùùææäåäÝÇìØÐµž`‡_8‘e4Œf2f0‘g.Že2ƒ_3Å· Ðȶ¬ ŽÐȺÔÏÈÎÉÆãáÝíéæÿÿÿíìêßÝÏŠlE‰d4’f-’g/„b5|hIåÜÉãßÔȶÔÌ»äâÌ¡”wˆ`7‘c6d4d6e3”e0‘e0‰c3oPÑʵòñíééæÿÿÿÙÕк°ž}]4ˆd5Žd1g1ˆb1¡ŒkäÛĘŠutbF•|WßÜ¿~pR’e6•d1d4Žb8“c5–d0–h2‹d0™‡céæÓÚÙÒØØÙÿÿÿíììßÓÅ›„g‹d2e0’g1‹d3ŽqJàÕ½£Žn~_7…c8…c:Ú˰®¤ƒ†a-™d/Œd2‰d6’e2—f.”f2ˆa6ÚȰÕÒÀÑÑÆÔÍÈïíìÿÿÿÖÔÒßÓ¾ˆmJ‘e0”f.’f.Šc3¡‡eãØÃ~fC‡b2‹e5€\6°šÒÊ«a.™c0Œe2‹d4”e1–f/Žc2“tNâ×ʆsÜÜ˦˜Œ÷ñëüüûÿÿÿéåßð–ƒc;‘f1“f.“f.Šc2«‘nÜηz_:Œe4Œc1…a7tXÛѰƒe9–c4e2“c0˜d2d3‚c7¿®ˆ®˜~rfLäàÈŠubÒĵúúõûûúóí㣋l‡c5e/’e-“f.Šc3¦‹häÖ½~b;Œc1d1Šd7ˆhJÒŧgC’`7’e1•c/“c3ˆc9ŒuOÛÒ­ƒiGoMçàÂŒqW¤vóðä÷öôêâÕ†iEc0e/‘d,“g/‹d3™~[èÛÀ†h?e0”f1‹c5‡dEЦjM^;”e1f.ˆd5z`;¶¦†ÓÄ }[4–€XáØ²mK†jJÐË·þþþùú÷ÑǶ[5e0‘e2’e/“f.Šc1–|VéÙÀ‰jE‰b2Žb0Œb1…iIÔÆ¨ˆjD‹a9d5f2‰h8{b=ÞÓ´«˜q„b3‡aÜÓ³ˆk@b2 ‘rüüùòõî³§’†\5Že0d4“e0’f.Šd1›‚ZèÛÀ|dB|_6‰lBŸƒ^Š|^ÚÏ­‰f8c5b8’d2ˆc3ˆnIëàˆz\}e8Œ}[àÖ»ŽqB‰d.‚fBêåÛúúøáäÚ£’|Œ`7Žg/e4“e0’f-Šd1ž„\îåÊ“ƒbr_; ’rãÚ¸³˜×Ь…`1“c4–b6”d0‹d1‰mEåܘ}¾³ƒ}^éâÉœzO’c/ƒ\6ÓʸúúõáßÒœia5h,d3“e0’f.Šd1šZîæÏåÜ¿Ùήº³–ºµ¡áÛÀ¶¤~ˆ`/’d1“d3‘c0Že1…b5Ƶ”Ùտž ¢ž‡ëåÒ¥„Y—d0Œ^3·¦ˆñïæäßÑ•u[”c5Žk-e3“e0“g.Œe2”{TçÙÅ“‚fª–tͺ˜Ï¼Ÿ«“tŠhBŽe1f0‹f2‹d3Že0f0qA¸¨…ØÍ²ÛÔÃïéÚ¡€V‘c.b2§ŽjôñææßÏ”wX•e6’g,e3Že1Žf0‰e2ŠnDáÔ½…h~^6ƒ_0ƒ^/ˆa8b8f2Žf1ˆg2ˆd4d2—g.‘e.„c1u\<¥–ƒ×Ưi>e1Šc1š~UèãÖæß͘…`c4™b0Œg4Še3‰d2Še3ˆe6Å·–ï‹b6‹d/d+‘e2d4e4e4e4e2“d2˜c2”c2Œe1ŠyYßÖº¨ŒcŒd4e4Œd3”|UäÝÐçãØ²¢ˆ}]6Œb2‘d4‘d4b2c3Šb3}Zæà¿‹vS…a6’c1c1Œe4d3d3d3“e/–f/d3ƒ`7d>Ù黬’~^5‹c2’d1Šc4Ž}`åßÕóðìØÌ½w_@‚c8c2c3‘d4d3c4wb<ÓË®¼¯”tY7‡a5‹d2Œe4‹d3Šc2‹c2”g3e3†e7w^9­œ}ÔÈ­„nMƒc7Šd4‹b6}\7®¤õóí÷öõìçâ´¦Žzg=ˆc1‹e3‹d2Œf3‹e4„`8Žy`àØÆž“wyg=„d2Še3‰e3‡c1‡c1‡`6`:ƒoGǺ•âÕ´ˆj@ƒb2‰e5†c8cD¬˜‚öóêüüûÿÿÿñïîâÞÐÄ»žvIc5z_2{`3}`5ƒcE{iÏÆ¹ìêÚ´­ˆoCb2~_0~_0a3†kGª™zÙаÕʨ–‚]€a1‚b.~`1ˆoKÄ´ ïéàýýüúúúññððéÚÛÕÄÑÈ·ÌóÙÑÂæãÝùõðôñìùùøïìêëäÔÓȴĹ¤È½©ÞÔÀìë×úûëÝÖÇ™‹y—†l¡‘q®¢†Ë°êçÜýýûþþþ÷õóöõôþýüþýüüúùþþþùùøóòñúúøþþüþþýþþýüýûþýüù÷õðìèàÚÐÙÒËåàÝüù÷ø÷öÿÿÿÿÿÿÿÿÿþ?ÿþ?ÿþ?ÿà?ÿÀ?ð?ðÀÀ€€Àð8(0`€ø÷÷ÛÚÏùõ軩–‘yd‘~f£’}¿°›ìáÒùõéüû÷ÐÎÅøòàœ‹soR3{X4|\4yZ3sV2zbC·§ùòãõóððíÞÁ·Ÿt\<€\2Ža2‹c0‹c0f5€^2tX5½¬•îìäøóá‘‚fuY3f5•e0e1‘f1“g1f2ƒa5…nPäÛÏúùùéãÍ„rT{^7e3”b-ˆb3Žf3“h1”g/‹d3|a>ÐñãáÞþû÷àÙ¿zjK}a:Žd3–e2`9‡d8’g2—i/Œd1tW0¾¯šÑËÅÿÿÿòðìÚе~dC‡b9g4Še.‹a5‹e5‹h1‘h/‘d2X0¹¥ˆÚÖÊüüüïíçṴ́…a>‹]0‹g0‚i-›d0‘f/†i.Šh/–e5‰X1µ›xÙÙÈùùùãâÚÕÈ­„`=a4Œe/ˆj/še1f0‡i.Œh0”d4‰Y3©nçéÙÂÁ¹ÔÈ­ƒ];”b6Œb-‹j/še1f0‡i.Œi0”c3‹[5š_öòáÿÿÿÿÿÿÿÿÿÿÿÿ³³ªÐÅ©ƒ^<”`5“f1Ži/™d0f0‡i.Œi0•e4‰Y3”}ZüòáíææèäáÍÊÆÐÍÇÇÅ¿×ÖÑÿÿÿ²´ªÒÉ­„];–`5•f1‘i0šd0f0‡i.‹h/’a1‹\5‹rOõêÛ˼»ÿÿÿüù÷øöóØÕÖðíëêåßìäÚÛ×ÉëæÔÿüçúõë¶´±·º¯Íħ„];–`5—e1“i0šd0f0‡i.‹h/”d4’b;„kHéßÐÑÈÇÿÿÿáÙÚøëêÙÓкµ²æåâêéèÔÓÕÿþü´®§{rfneRk`GŽ‚dº±Ÿõõïýÿó¸„]<–_5˜e1”h0™d0f0‡i.‹h/”d4a9eCÛÙÉßáÞíííóðç×§‹kEzY0©“vùõëâáÞæãÚðïåæãÙÓ̼™ŒwjW:dW8–‘uüöáм§y[B‡_<’d6•g1‰i0‰i.i-h/‰b,ˆd6‚b<×ųÿÿ÷ôíÝñâÍõçÐüòÝþùíúùôúùùùø÷ìçãâÙÉ‚iH]0ˆb3b>Æ»«üùìßÝÛÃÂ½ÚØÎüö审‹e\?VP2ÐÄ¬ÚÆ±zZ@…`;‘d6”f2ˆi0Ši.h-‘h/‹c.‰d6‚`9н©óêà•…r‚mWkTˆwb˜°¬£ÕÑÎûøøÿÿÿÎÆÃÿù윈o|]6‰b0Že0_4~iN×ʵøõëÜÜÛļøô锎v]W9Õ˰ζœ|Z;‰a9‘e6“g2‰g1‹h0h.h.Šb-‡a2‚`6ųœõîà|m[^M8xgQ‘ƒrˆ}…y‹ˆ†Á¿½ü÷ôëæäððïíìãÚȰz^=‰e7b+“e+i7yZ5ˆqTäÙÃýùìèçåÐÐÍðïèñîÝÛÙ½øîÓž€a‚\8Œa8‘e6‘f3‹f4Œf2f0“h/”i4‹e5€]2¡pùõäÞÖÃÆº©äÜÎýúðûùòôíéïêèäãßùöñæâÞÿÿÿÎÏÊóôæ™~[\2Žg5‘e,•g,‘g0‰e6y_;nSàÖÁçãÖïïëù÷ñàÛÒôðäúøæÓÑ·¬›}[6c9‘c7d5e4e6Že4’f2”f0‘e/Žf4†b4wa@›‘zìçÔÿÿþÜÚÕööôÿÿÿååäõðã½µ y[3Šf9Œe4’g2“g0‘g1e1x[3~lPá׿þøå½±Ÿ~s^l\B¿­þüâ~{bkX7Žf:”c3”d3e4d6Žc8‘d6•e2–e0–g1f2Šd3v_9“‰mòíÚðïåðïëÜÛÛÿÿÿ¹³²ÿýò‰xbxY2ˆf:†b4‹c2Že1h3‹b-„e;ͽ ÿú⤖gW@r`Cs[7œ~Qÿù׳³nY7“h:–c/–e1e3d7a;’b8–d3˜e0™j4“i3ˆa.ˆqFâÞÂÿÿòÌËÁÕרÓÓÖòññÖËÄëÜÉ{bE‡c4‹d3Žf2“h3f1‹d4€]0£‹kúóÞ˺žw_<|_:…f=ƒb9Œi?âΰìëÔ~nHƒa/—e0šd/d2‡e6Œc8‘d6–e0˜f.›j4Žc1‚\1¿¤†ûöáæäÒâ䨍¦¡÷òñåãâÿÿÿËÉÆ÷ñß¿­‘y\8’g2”f/•g-•h.e/‰d6{]6ƶŸúóà“`|^1‹c1‰a/‰c9{X5§uÿþå© xu^)•e/žc/d1‚g4Œe5‘f2–g.™g-”c.Œb6lHóßÌÚÓËŒzóøè•ˆÖÇ¿îêåÿÿÿ¾»·þöä…hy[4e1“f0”g.”g.Žc.‰d6†g@ëÚÁÜÓÀu`@`5Œe3Žg5Œf;|Y4€dIòäÍÌǦza0’c1d1’f2„f2’c5•e2—e0–f0“h5]2¡ŠeÿùãŸ{mmXô÷ä·®Ÿ‰wjûñæôóñÿÿÿ×ÓËóæÑeC„c:‘g2’f0”g.•h.d/‰c5ŠkDóàÇÏÄ®t^=„c7g4d0‰b6^6vW:ʼ¡çâ¼h;`1e5”g4†d/™c2šd2—e2d1‡c3{_4ÒÄŸâϵqZCnkQððØÉ¿«jRBÖôóôëîæÛλ£{^9‹g9f1’e/“f-•h/e0ˆc4‡hAîÝÃØÌµw_<„b4e2b.Že7ˆd;xW:¬•zíåÃ~jB‰_4™d6•f3‹e0œc1™d2“c5‹d7{\3’}UõíÈ¢ŒmsW;{sTûùÞĵpT?š€mõðßüüúîíë÷íÞ«•z~^5e3e0‘e.’e-•g.e0ˆc5ƒd<çÕºæÛÃ}d@†c4‘d/“f0Žd4‰d8~Z:šfë寀oM†\8˜a8•d2f1˜c.•c2d8ƒcˆa1”g/’g2d.’e,•h/‘f1‰d6xY2Í»žöíÒŒpKˆb1“e.–g0’e3Œd6€Y7ŸƒfëäÈpU‚[?•`<–d3“g/j0ˆh5}d9o[:·¨‹ÿüÞž…`ƒ^4€[1«›qÿüÔ…^\8‚_={gBÐÑ»üþüò÷춦|U3d4f/‘e5’e2”f0•g.Žd-ˆc2{^2ѼŸöçÐŒoP‚_7‰b2Œa0‹a0Œa0uX5 ’xðãÂpF‡b5Œd8Šd8Šc8’g1’l9‚b9eCãÙºëà¼}e:‰h5^/­~ÿû㕃_€b-…f/v\)¨˜€ûùôêðàŸŒvV3‘d5Œd-d5’e2”f0•g.f/‰e4~b5×Ã¥óçÏ„mLy\6‚`4`3„c7‚a8gQ2´¨îὌj>‰c3Žd7Žc8Žc9”f1f3}]4ŠrPþðÑËÁ£lZ6{`1x\-¡”xþøážŠg„c.‹h0}^*‡pUðêÞõõóêîéãåÕŒu]†\9“g6Žh.e5’e2”f0”g.Žd-‡c2~a4ÕäïèÏs`@v`;zb;lGñãÔ¸‚fÄĦäÚ´…c6c3’c5”c7”b8“d-d0ƒa7•~[ÿúÜ»±˜f[DŒ|Uvd7…€eÿû㵟~‚]+e0Žd2z\>Ö̼çèàÞãÜàÜË‚gN‹_:‘d1i.e5’e2”f0”g.f.‰e4c7ÝÍ­þúඨˆnMgV4ˆ{[àØ¾íéÖ³®–èæÈÎÜ\-‘f5–c4—c5—b7•f.‘g1„a3‰oHñæÌÊ­‘‹|ðêͰ§|onVùùåѽž‰_.“b-–f4|W5½­–õôääæÝÙѾ‚`F_:d.Šh*d4’e2”f0•h.Žd-‰e4€c7ׯ¨ÿÿêÿúÞëáÁ½°‘˜Žp™”|˜”„Ìɳÿþݪ•m\,‘e2•d2•d4•c5“e/f0Šd4`7Æ´“ûöÞ¶³£¾¸œ”oqp]ðïßØÊ­‹`/™e0—b1‚X1ŸŠjøõàëëéóôéŹ¥Z>’_7“h0l,e4’e2”f0•h/f.ˆd2y\/Ͼ¡ôìׯ¢‡àÓµýõÕÿüÜÿ÷ÜÿúåýõÜ«‰ƒe=‹d2f0’f1e2e4Œa.Žd/g4ˆd4‰mAÞϬþûäêâÇíãÄåãÕÿÿõÖǪe4—e0–e3‘e9ŽpJïèÐø÷ó÷÷ìÀ°›V9•a7•j2‹m,e4’e2”f0•h.f/‹f5}`4¯•ùíÞpWu^>uP°–q¿¤´›|”xX~[:†`7Že2g0Žg0‹g2‡f4Œe5Žf2f/g/…a,‚f8¨—sÏħΪÚÒÇÿÿ÷̸ˆ`/c,Žd0Š`1‡d8à×»ÿÿüøöìÀ¯š€V9˜c:–k1Šj)d4‘e2“f0”h/g0‰e4y\.¬˜~ÿ÷訓|rV6a:€]2~[1\3\8Šb?b9‘f3g0Œg0†i1ƒh2ˆc5c2“h/–i,g,‰f2x_3x^…a5–d4™a0Žg4Œg5‹e3Šd2g5Œf4‹b/f>×ϱóçÄkD`3Šd1Že.“e,’e0e5e4e4e4e4e4e4’f0“e1—d2˜c2”b3e6†d2weCÑȳúñÓ¢…]…`1’g5’f4“g5Šc2z`5ò˜ôòìÝÚÒóêÓ†qR{\6Œc5`/’f5‘e5c3Žb2d4d3’d2y^6¥œ|ÿÿÝ­œypV/…b7d3˜e1‘c0Œe4e4e4Že4Že4Že4e4—g-–f.–e0’d4‰a6†dgR“€o¯¢–áÛÏÿÿùøõ⾸ž“Z€b3|`2z]0x[.{^1|_2‚e9‹{[³¦‡äÛ½ÿûßÜÓ´“^v^9€c4~b+{^,z`1xa9”‚dÑİøóè÷÷ôêêéêëéûóßéãÌÌÅ­¿³›µª“³¨‘Ê¿¦ÍȹàÞØòìäÿúóèâÛæäâõñíýöåÜϲ¹¨Œ¨˜|§˜|±¡…ȹœÝÏ´ìðÕøûãüúèÁ·¤|mZmZAs`?wd=pH^§œ€Òκöóçüý÷þþþîéãÚÔÐíèåþúöÿûùýùöòìèþüøæäãÜÙÕßÞÚüùóýûõÿÿúþüùþüùÿÿûõ÷ï÷õììãÜÝÔËã×ÈåÙÃêàÍ÷ëßøóéüôíìäâíêéÿÿÿíìé×ÓÌÓÎÊÆÂÅèããÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿŒÿÿÿÿÿœÿþÿüøðÀð`à?À?À?À€€€À€€€€€€€€Àð üð?ÿÿÿÿÿ( @€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿð÷ˆøˆˆðxˆˆðˆˆˆðˆˆˆøˆˆˆˆˆˆ€ˆÿÿˆˆˆ€ÿ÷ˆˆÿˆˆˆÿÿÿ÷ˆ÷ˆˆˆˆˆˆ‡ðxˆˆ‡xøˆˆˆ÷÷ÿðøˆˆ÷øˆˆˆˆø‡xˆˆøxˆˆˆ‡ÿ€ˆˆ‡xˆ÷ˆˆˆ‡øˆˆˆˆˆˆˆxˆˆˆˆˆˆˆøøˆˆˆˆˆˆˆøxˆˆˆˆˆˆˆˆðˆˆˆˆˆˆˆˆˆð€ˆˆˆˆ÷ˆˆˆˆˆˆ÷ˆøˆˆˆˆˆˆˆÿˆˆˆˆ÷÷ˆˆˆˆˆˆˆˆˆˆˆøˆˆˆˆ‡xˆˆˆˆˆˆøˆˆˆˆˆøˆˆˆˆˆˆˆøˆˆˆˆˆˆˆˆøˆˆ÷ˆˆˆˆxˆˆˆˆˆˆðxˆ‡ÿÿxˆøˆˆÿÿÿ÷ÿˆÿÿÿ€ˆÿÿ‡ÿÿÿÿÿþÿÿþÿÿüÿÿüÿÿüÿÿüÿ€øðàààÀÀ€€€€Ààð<0?pgagent-REL-4_2_2/job.cpp000066400000000000000000000243541412006174200152110ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // job.cpp - pgAgent job // ////////////////////////////////////////////////////////////////////////// #include "pgAgent.h" #include #if !BOOST_OS_WINDOWS #include #include #include #endif Job::Job(DBconn *conn, const std::string &jid) { m_threadConn = conn; m_jobid = jid; m_status = ""; LogMessage("Starting job: " + m_jobid, LOG_DEBUG); int rc = m_threadConn->ExecuteVoid( "UPDATE pgagent.pga_job SET jobagentid=" + backendPid + ", joblastrun=now() WHERE jobagentid IS NULL AND jobid=" + m_jobid ); if (rc == 1) { DBresultPtr id = m_threadConn->Execute( "SELECT nextval('pgagent.pga_joblog_jlgid_seq') AS id" ); if (id) { m_logid = id->GetString("id"); DBresultPtr res = m_threadConn->Execute( "INSERT INTO pgagent.pga_joblog(jlgid, jlgjobid, jlgstatus) " "VALUES (" + m_logid + ", " + m_jobid + ", 'r')"); if (res) { m_status = "r"; } } } } Job::~Job() { if (!m_status.empty()) { m_threadConn->ExecuteVoid( "UPDATE pgagent.pga_joblog " " SET jlgstatus='" + m_status + "', jlgduration=now() - jlgstart " + " WHERE jlgid=" + m_logid + ";\n" + "UPDATE pgagent.pga_job " + " SET jobagentid=NULL, jobnextrun=NULL " + " WHERE jobid=" + m_jobid ); } m_threadConn->Return(); LogMessage("Completed job: " + m_jobid, LOG_DEBUG); } int Job::Execute() { int rc = 0; bool succeeded = false; DBresultPtr steps = m_threadConn->Execute( "SELECT * " " FROM pgagent.pga_jobstep " " WHERE jstenabled " " AND jstjobid=" + m_jobid + " ORDER BY jstname, jstid"); if (!steps) { m_status = "i"; return -1; } while (steps->HasData()) { DBconn *stepConn = nullptr; std::string jslid, stepid, jpecode, output; stepid = steps->GetString("jstid"); DBresultPtr id = m_threadConn->Execute( "SELECT nextval('pgagent.pga_jobsteplog_jslid_seq') AS id" ); if (id) { jslid = id->GetString("id"); DBresultPtr res = m_threadConn->Execute( "INSERT INTO pgagent.pga_jobsteplog(jslid, jsljlgid, jsljstid, jslstatus) " "SELECT " + jslid + ", " + m_logid + ", " + stepid + ", 'r'" + " FROM pgagent.pga_jobstep WHERE jstid=" + stepid); if (res) rc = res->RowsAffected(); else rc = -1; } if (rc != 1) { m_status = "i"; return -1; } switch ((int)steps->GetString("jstkind")[0]) { case 's': { std::string jstdbname = steps->GetString("jstdbname"); std::string jstconnstr = steps->GetString("jstconnstr"); stepConn = DBconn::Get(jstconnstr, jstdbname); if (stepConn) { LogMessage( "Executing SQL step " + stepid + "(part of job " + m_jobid + ")", LOG_DEBUG ); rc = stepConn->ExecuteVoid(steps->GetString("jstcode")); succeeded = stepConn->LastCommandOk(); output = stepConn->GetLastError(); stepConn->Return(); } else { output = "Couldn't get a connection to the database!"; succeeded = false; } break; } case 'b': { // Batch jobs are more complex thank SQL, for obvious reasons... LogMessage( "Executing batch step" + stepid + "(part of job " + m_jobid + ")", LOG_DEBUG ); // Get a temporary filename, then reuse it to create an empty directory. std::string sDirectory = getTemporaryDirectoryPath(); std::string sFilesName = std::string(""); std::string prefix = std::string("pga_"); // Generate random string of 6 characters long to make unique dir name std::string result = generateRandomString(7); sFilesName = prefix + m_jobid + std::string("_") + stepid + std::string("_") + result; #if BOOST_OS_WINDOWS std::string sModel = (boost::format("%s\\%s") % sDirectory % sFilesName).str(); #else std::string sModel = (boost::format("%s/%s") % sDirectory % sFilesName).str(); #endif std::string dirname = sModel; if (dirname == "") { output = "Couldn't get a temporary filename!"; LogMessage(output, LOG_WARNING); rc = -1; break; } if (!boost::filesystem::create_directory(boost::filesystem::path(dirname))) { LogMessage( "Couldn't create temporary directory: " + dirname, LOG_WARNING ); rc = -1; break; } #if BOOST_OS_WINDOWS std::string filename = dirname + "\\" + m_jobid + "_" + stepid + ".bat"; std::string errorFile = dirname + "\\" + m_jobid + "_" + stepid + "_error.txt"; #else std::string filename = dirname + "/" + m_jobid + "_" + stepid + ".scr"; std::string errorFile = dirname + "/" + m_jobid + "_" + stepid + "_error.txt"; #endif std::string code = steps->GetString("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 boost::replace_all(code, "\r\n", "\n"); #if BOOST_OS_WINDOWS boost::replace_all(code, "\n", "\r\n"); #endif std::ofstream out_file; out_file.open((const char *)filename.c_str(), std::ios::out); if (out_file.fail()) { LogMessage( "Couldn't open temporary script file: " + filename, LOG_WARNING ); if (boost::filesystem::exists(dirname)) boost::filesystem::remove_all(dirname); rc = -1; break; } else { out_file << code; out_file.close(); #if !BOOST_OS_WINDOWS // change file permission to 700 for executable in linux int ret = chmod((const char *)filename.c_str(), S_IRWXU); if (ret != 0) LogMessage( "Error setting executable permission to file: " + filename, LOG_DEBUG ); #endif } LogMessage("Executing script file: " + filename, LOG_DEBUG); // freopen function is used to redirect output of stream (stderr in our case) // into the specified file. FILE *fpError = freopen((const char *)errorFile.c_str(), "w", stderr); // Execute the file and capture the output #if BOOST_OS_WINDOWS // The Windows way HANDLE h_script, h_process; DWORD dwRead; char chBuf[4098]; h_script = win32_popen_r(s2ws(filename).c_str(), h_process); if (!h_script) { LogMessage((boost::format( "Couldn't execute script: %s, GetLastError() returned %d, errno = %d" ) % filename.c_str() % GetLastError() % errno).str(), LOG_WARNING); CloseHandle(h_process); rc = -1; if (fpError) fclose(fpError); 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 += (const char *)chBuf; } } GetExitCodeProcess(h_process, (LPDWORD)&rc); CloseHandle(h_process); CloseHandle(h_script); #else // The *nix way. FILE *fp_script = nullptr; char buf[4098]; fp_script = popen((const char *)filename.c_str(), "r"); if (!fp_script) { LogMessage((boost::format( "Couldn't execute script: %s, errno = %d" ) % filename.c_str() % errno).str(), LOG_WARNING); rc = -1; if(fpError) fclose(fpError); break; } while(!feof(fp_script)) { if (fgets(buf, 4096, fp_script) != NULL) output += (const char *)buf; } rc = pclose(fp_script); if (WIFEXITED(rc)) rc = WEXITSTATUS(rc); else rc = -1; #endif // set success status for batch runs, be pessimistic by default LogMessage( (boost::format("Script return code: %d") % rc).str(), LOG_DEBUG ); succeeded = ((rc == 0) ? true : false); // If output is empty then either script did not return any output // or script threw some error into stderr. // Check script threw some error into stderr if (fpError) { fclose(fpError); FILE* fpErr = fopen((const char *)errorFile.c_str(), "r"); if (fpErr) { char buffer[4098]; std::string errorMsg = ""; while (!feof(fpErr)) { if (fgets(buffer, 4096, fpErr) != NULL) errorMsg += buffer; } if (errorMsg != "") { std::string errmsg = "Script Error: \n" + errorMsg + "\n"; LogMessage("Script Error: \n" + errorMsg + "\n", LOG_WARNING); output += "\n" + errmsg; } fclose(fpErr); } } // Delete the file/directory. If we fail, don't overwrite the script // output in the log, just throw warnings. try { boost::filesystem::path dir_path(dirname); if (boost::filesystem::exists(dir_path)) boost::filesystem::remove_all(dir_path); } catch (boost::filesystem::filesystem_error const & e) { //display error message LogMessage((const char *)e.what(), LOG_WARNING); break; } break; } default: { output = "Invalid step type!"; m_status = "i"; return -1; } } std::string stepstatus; if (succeeded) stepstatus = "s"; else stepstatus = steps->GetString("jstonerror"); rc = m_threadConn->ExecuteVoid( "UPDATE pgagent.pga_jobsteplog " " SET jslduration = now() - jslstart, " " jslresult = " + NumToStr(rc) + ", jslstatus = '" + stepstatus + "', " + " jsloutput = " + m_threadConn->qtDbString(output) + " " + " WHERE jslid=" + jslid); if (rc != 1 || stepstatus == "f") { m_status = "f"; return -1; } steps->MoveNext(); } m_status = "s"; return 0; } JobThread::JobThread(const std::string &jid) : m_jobid(jid) { LogMessage("Creating job thread for job " + m_jobid, LOG_DEBUG); } JobThread::~JobThread() { LogMessage("Destroying job thread for job " + m_jobid, LOG_DEBUG); } void JobThread::operator()() { DBconn *threadConn = DBconn::Get(); if (threadConn) { Job job(threadConn, m_jobid); if (job.Runnable()) { job.Execute(); } else { // Failed to launch the thread. Insert an entry with // "internal error" status in the joblog table, to leave // a trace of fact that we tried to launch the job. DBresultPtr res = threadConn->Execute( "INSERT INTO pgagent.pga_joblog(jlgid, jlgjobid, jlgstatus) " "VALUES (nextval('pgagent.pga_joblog_jlgid_seq'), " + m_jobid + ", 'i')" ); if (res) res = NULL; } } } pgagent-REL-4_2_2/misc.cpp000066400000000000000000000077541412006174200153770ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // misc.cpp - misc functions // ////////////////////////////////////////////////////////////////////////// #include "pgAgent.h" #include "connection.h" #include #if !BOOST_OS_WINDOWS #include #include #endif #define APPVERSION_STR PGAGENT_VERSION // In unix.c or win32.c void usage(const std::string &executable); std::string getArg(int &argc, char **&argv) { std::string res; if (argv[0][2]) return (argv[0] + 2); if (argc >= 1) { argc--; argv++; return argv[0]; } // very bad! LogMessage("Invalid command line argument", LOG_ERROR); return res; } void printVersion() { printf("PostgreSQL Scheduling Agent\n"); printf("Version: %s\n", APPVERSION_STR); } void setOptions(int argc, char **argv, const std::string &executable) { while (argc-- > 0) { if (argv[0][0] == '-') { switch (argv[0][1]) { case 't': { int val = atoi((const char*)getArg(argc, argv).c_str()); if (val > 0) shortWait = val; break; } case 'r': { int val = atoi((const char*)getArg(argc, argv).c_str()); if (val >= 10) longWait = val; break; } case 'l': { int val = atoi((const char*)getArg(argc, argv).c_str()); if (val >= 0 && val <= 2) minLogLevel = val; break; } case 'v': { printVersion(); exit(0); } #if !BOOST_OS_WINDOWS case 'f': { runInForeground = true; break; } case 's': { logFile = getArg(argc, argv); break; } #endif default: { usage(executable); exit(1); } } } else { if (!connectString.empty()) connectString += " "; connectString += *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 } } std::string NumToStr(const long l) { return boost::lexical_cast(l); } #if BOOST_OS_WINDOWS // This function is used to convert const std::str to std::wstring. std::wstring s2ws(const std::string &str) { using boost::locale::conv::utf_to_utf; return utf_to_utf(str.c_str(), str.c_str() + str.size()); } // This function is used to convert std::wstring to std::str std::string ws2s(const std::wstring &wstr) { using boost::locale::conv::utf_to_utf; return utf_to_utf(wstr.c_str(), wstr.c_str() + wstr.size()); } #endif // Below function will generate random string of given character. std::string generateRandomString(size_t length) { char *str = new char[length]; size_t i = 0; int r; str[length - 1] = '\0'; srand(time(NULL)); for(i = 0; i < length - 1; ++i) { for(;;) { // interval between 'A' and 'z' r = rand() % 57 + 65; if((r >= 65 && r <= 90) || (r >= 97 && r <= 122)) { str[i] = (char)r; break; } } } std::string result(str); if (str != NULL) { delete []str; str = NULL; } return result; } std::string getTemporaryDirectoryPath() { #if BOOST_OS_WINDOWS std::wstring tmp_dir; wchar_t wcharPath[MAX_PATH]; if (GetTempPathW(MAX_PATH, wcharPath)) { tmp_dir = wcharPath; return ws2s(tmp_dir); } return ""; #else // Read this environment variable (TMPDIR, TMP, TEMP, TEMPDIR) and if not found then use "/tmp" std::string tmp_dir = "/tmp"; const char *s_tmp = getenv("TMPDIR"); if (s_tmp != NULL) return s_tmp; s_tmp = getenv("TMP"); if (s_tmp != NULL) return s_tmp; s_tmp = getenv("TEMP"); if (s_tmp != NULL) return s_tmp; s_tmp = getenv("TEMPDIR"); if (s_tmp != NULL) return s_tmp; return tmp_dir; #endif } pgagent-REL-4_2_2/pgAgent.cpp000066400000000000000000000145201412006174200160160ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // pgAgent.cpp - pgAgent main entry // ////////////////////////////////////////////////////////////////////////// #include "pgAgent.h" #if !BOOST_OS_WINDOWS #include #endif std::string connectString; std::string backendPid; long longWait = 30; long shortWait = 5; long minLogLevel = LOG_ERROR; using namespace std; #define MAXATTEMPTS 10 #if !BOOST_OS_WINDOWS bool runInForeground = false; std::string logFile; #else // pgAgent Initialized void Initialized(); #endif int MainRestartLoop(DBconn *serviceConn) { // clean up old jobs int rc; LogMessage("Clearing zombies", LOG_DEBUG); rc = serviceConn->ExecuteVoid("CREATE TEMP TABLE pga_tmp_zombies(jagpid int4)"); if (serviceConn->BackendMinimumVersion(9, 2)) { rc = serviceConn->ExecuteVoid( "INSERT INTO pga_tmp_zombies (jagpid) " "SELECT jagpid " " FROM pgagent.pga_jobagent AG " " LEFT JOIN pg_stat_activity PA ON jagpid=pid " " WHERE pid IS NULL" ); } else { rc = serviceConn->ExecuteVoid( "INSERT INTO pga_tmp_zombies (jagpid) " "SELECT jagpid " " FROM pgagent.pga_jobagent AG " " LEFT JOIN pg_stat_activity PA ON jagpid=procpid " " WHERE procpid IS NULL" ); } if (rc > 0) { // There are orphaned agent entries // mark the jobs as aborted rc = serviceConn->ExecuteVoid( "UPDATE pgagent.pga_joblog SET jlgstatus='d' WHERE jlgid IN (" "SELECT jlgid " "FROM pga_tmp_zombies z, pgagent.pga_job j, pgagent.pga_joblog l " "WHERE z.jagpid=j.jobagentid AND j.jobid = l.jlgjobid AND l.jlgstatus='r');\n" "UPDATE pgagent.pga_jobsteplog SET jslstatus='d' WHERE jslid IN ( " "SELECT jslid " "FROM pga_tmp_zombies z, pgagent.pga_job j, pgagent.pga_joblog l, pgagent.pga_jobsteplog s " "WHERE z.jagpid=j.jobagentid AND j.jobid = l.jlgjobid AND l.jlgid = s.jsljlgid AND s.jslstatus='r');\n" "UPDATE pgagent.pga_job SET jobagentid=NULL, jobnextrun=NULL " " WHERE jobagentid IN (SELECT jagpid FROM pga_tmp_zombies);\n" "DELETE FROM pgagent.pga_jobagent " " WHERE jagpid IN (SELECT jagpid FROM pga_tmp_zombies);\n" ); } rc = serviceConn->ExecuteVoid("DROP TABLE pga_tmp_zombies"); std::string host_name = boost::asio::ip::host_name(); rc = serviceConn->ExecuteVoid( "INSERT INTO pgagent.pga_jobagent (jagpid, jagstation) SELECT pg_backend_pid(), '" + host_name + "'" ); if (rc < 0) return rc; while (1) { bool foundJobToExecute = false; LogMessage("Checking for jobs to run", LOG_DEBUG); DBresultPtr res = serviceConn->Execute( "SELECT J.jobid " " FROM pgagent.pga_job J " " WHERE jobenabled " " AND jobagentid IS NULL " " AND jobnextrun <= now() " " AND (jobhostagent = '' OR jobhostagent = '" + host_name + "')" " ORDER BY jobnextrun" ); if (res) { while (res->HasData()) { std::string jobid = res->GetString("jobid"); boost::thread job_thread = boost::thread(JobThread(jobid)); job_thread.detach(); foundJobToExecute = true; res->MoveNext(); } res = NULL; 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) { // Basic sanity check, and a chance to get the serviceConn's PID LogMessage("Database sanity check", LOG_DEBUG); DBresultPtr res = serviceConn->Execute( "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) { std::string val = res->GetString("count"); if (val == "0") LogMessage( "Could not find the table 'pgagent.pga_job'. Have you run pgagent.sql on this database?", LOG_ERROR ); backendPid = res->GetString("pid"); res = NULL; } // Check for particular version bool hasSchemaVerFunc = false; std::string sqlCheckSchemaVersion = "SELECT COUNT(*) " \ "FROM pg_proc " \ "WHERE proname = 'pgagent_schema_version' AND " \ " pronamespace = (SELECT oid " \ " FROM pg_namespace " \ " WHERE nspname = 'pgagent') AND " \ " prorettype = (SELECT oid " \ " FROM pg_type " \ " WHERE typname = 'int2') AND " \ " proargtypes = '' "; res = serviceConn->Execute(sqlCheckSchemaVersion); if (res) { if (res->IsValid() && res->GetString(0) == "1") hasSchemaVerFunc = true; res = NULL; } if (!hasSchemaVerFunc) { LogMessage( "Couldn't find the function 'pgagent_schema_version' - please run ALTER EXTENSION \"pgagent\" UPDATE;.", LOG_ERROR ); } std::string strPgAgentSchemaVer = serviceConn->ExecuteScalar( "SELECT pgagent.pgagent_schema_version()" ); std::string currentPgAgentVersion = (boost::format("%d") % PGAGENT_VERSION_MAJOR).str(); if (strPgAgentSchemaVer != currentPgAgentVersion) { LogMessage( "Unsupported schema version: " + strPgAgentSchemaVer + ". Version " + currentPgAgentVersion + " is required - please run ALTER EXTENSION \"pgagent\" UPDATE;.", LOG_ERROR ); } #ifdef WIN32 Initialized(); #endif MainRestartLoop(serviceConn); } LogMessage((boost::format( "Couldn't create the primary connection [Attempt #%d]") % attemptCount ).str(), LOG_STARTUP); DBconn::ClearConnections(true); // Try establishing primary connection upto MAXATTEMPTS times if (attemptCount++ >= (int)MAXATTEMPTS) { LogMessage( "Stopping pgAgent: Couldn't establish the primary connection with the database server.", LOG_ERROR ); } WaitAWhile(); } while (1); } pgagent-REL-4_2_2/pgAgent.rc000066400000000000000000000026001412006174200156340ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // pgAgent.rc - win32 Resources // ////////////////////////////////////////////////////////////////////////// #include // Icon (Don't remove the aaa prefix - it makes it the default icon) aaaPGAGENT ICON DISCARDABLE "include/pgAgent.ico" VS_VERSION_INFO VERSIONINFO FILEVERSION 4,2,2,0 PRODUCTVERSION 4,2,2,0 FILEOS VOS__WINDOWS32 FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "FileVersion", "4.2.2", "\0" VALUE "File Version", "4.2.2", "\0" VALUE "FileDescription", "pgAgent - PostgreSQL Scheduling Agent", "\0" VALUE "LegalCopyright", "\251 2002 - 2021, The pgAdmin Development Team", "\0" VALUE "LegalTrademarks", "This software is released under the PostgreSQL Licence.", "\0" VALUE "InternalName", "pgAgent", "\0" VALUE "OriginalFilename","pgagent.exe", "\0" VALUE "ProductName", "pgAgent", "\0" VALUE "ProductVersion", "4.2.2", "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 0x04E4 END END pgagent-REL-4_2_2/pgaevent/000077500000000000000000000000001412006174200155345ustar00rootroot00000000000000pgagent-REL-4_2_2/pgaevent/CMakeLists.txt000066400000000000000000000013121412006174200202710ustar00rootroot00000000000000####################################################################### # # pgAgent - PostgreSQL tools # Copyright (C) 2002 - 2021, The pgAdmin Development Team # This software is released under the PostgreSQL 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) pgagent-REL-4_2_2/pgaevent/MSG00001.bin000066400000000000000000000000341412006174200172320ustar00rootroot00000000000000 %1 pgagent-REL-4_2_2/pgaevent/README000066400000000000000000000014431412006174200164160ustar00rootroot00000000000000This 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 pgagent-REL-4_2_2/pgaevent/pgaevent.c000066400000000000000000000014141412006174200175110ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // pgaevent.c - win32 message format dll // ////////////////////////////////////////////////////////////////////////// #include #include #include 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; } pgagent-REL-4_2_2/pgaevent/pgaevent.def000066400000000000000000000007011412006174200200230ustar00rootroot00000000000000; //////////////////////////////////////////////////////////////////////// ; // ; // pgAgent - PostgreSQL Tools ; // ; // Copyright (C) 2002 - 2021, The pgAdmin Development Team ; // This software is released under the PostgreSQL Licence ; // ; // pgaeventdef - pgaevent.dll exports ; // ; //////////////////////////////////////////////////////////////////////// ; dlltool --output-def pgaevent.def pgaevent.o pgamsgevent.o EXPORTS pgagent-REL-4_2_2/pgaevent/pgamsgevent.h000066400000000000000000000006151412006174200202270ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // pgamsgevent.h - Message id declarations // ////////////////////////////////////////////////////////////////////////// #define PGADMIN_EVENTLOG_MSG 0x00000000L pgagent-REL-4_2_2/pgaevent/pgamsgevent.mc000066400000000000000000000001111412006174200203660ustar00rootroot00000000000000MessageId=0 SymbolicName=PGADMIN_EVENTLOG_MSG Language=English %1 . pgagent-REL-4_2_2/pgaevent/pgamsgevent.rc000066400000000000000000000027501412006174200204060ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // pgaevent.rc - win32 Resources // ////////////////////////////////////////////////////////////////////////// LANGUAGE 0x9,0x1 1 11 MSG00001.bin #include // Icon (Don't remove the aaa prefix - it makes it the default icon) aaaPGAEVENT ICON DISCARDABLE "../include/pgagent.ico" VS_VERSION_INFO VERSIONINFO FILEVERSION 4,2,2,0 PRODUCTVERSION 4,2,2,0 FILEOS VOS__WINDOWS32 FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "FileVersion", "4.2.2", "\0" VALUE "File Version", "4.2.2", "\0" VALUE "FileDescription", "pgaevent - pgAgent Event Log Message DLL", "\0" VALUE "LegalCopyright", "\251 2002 - 2021, The pgAdmin Development Team", "\0" VALUE "LegalTrademarks", "This software is released under the PostgreSQL Licence.", "\0" VALUE "InternalName", "pgaevent", "\0" VALUE "OriginalFilename","pgaevent.dll", "\0" VALUE "ProductName", "pgAgent", "\0" VALUE "ProductVersion", "4.2.2", "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 0x04E4 END END pgagent-REL-4_2_2/pgagent.control.in000066400000000000000000000002511412006174200173550ustar00rootroot00000000000000# pgagent extension comment = 'A PostgreSQL job scheduler' default_version = '${MAJOR_VERSION}.${MINOR_VERSION}' relocatable = false superuser = false schema = pgagent pgagent-REL-4_2_2/precomp.cpp000066400000000000000000000005701412006174200160760ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // precomp.cpp - pgAgent precompiled headers // ////////////////////////////////////////////////////////////////////////// #include "pgAgent.h" pgagent-REL-4_2_2/sql/000077500000000000000000000000001412006174200145225ustar00rootroot00000000000000pgagent-REL-4_2_2/sql/pgagent--3.4--4.2.sql000066400000000000000000000357611412006174200176410ustar00rootroot00000000000000/* // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // pgagent--3.4--4.2.sql - Upgrade the pgAgent schema to 4.2 // */ \echo Use "ALTER EXTENSION pgagent UPDATE" to load this file. \quit CREATE OR REPLACE FUNCTION pgagent.pgagent_schema_version() RETURNS int2 AS ' BEGIN -- RETURNS PGAGENT MAJOR VERSION -- WE WILL CHANGE THE MAJOR VERSION, ONLY IF THERE IS A SCHEMA CHANGE RETURN 4; END; ' LANGUAGE 'plpgsql' VOLATILE; CREATE OR REPLACE FUNCTION pgagent.pga_next_schedule(int4, timestamptz, timestamptz, _bool, _bool, _bool, _bool, _bool) RETURNS timestamptz AS ' DECLARE jscid ALIAS FOR $1; jscstart ALIAS FOR $2; jscend ALIAS FOR $3; jscminutes ALIAS FOR $4; jschours ALIAS FOR $5; jscweekdays ALIAS FOR $6; jscmonthdays ALIAS FOR $7; jscmonths ALIAS FOR $8; nextrun timestamp := ''1970-01-01 00:00:00-00''; runafter timestamp := ''1970-01-01 00:00:00-00''; bingo bool := FALSE; gotit bool := FALSE; foundval bool := FALSE; daytweak bool := FALSE; minutetweak bool := FALSE; i int2 := 0; d int2 := 0; nextminute int2 := 0; nexthour int2 := 0; nextday int2 := 0; nextmonth int2 := 0; nextyear int2 := 0; BEGIN -- No valid start date has been specified IF jscstart IS NULL THEN RETURN NULL; END IF; -- The schedule is past its end date IF jscend IS NOT NULL AND jscend < now() THEN RETURN NULL; END IF; -- Get the time to find the next run after. It will just be the later of -- now() + 1m and the start date for the time being, however, we might want to -- do more complex things using this value in the future. IF date_trunc(''MINUTE'', jscstart) > date_trunc(''MINUTE'', (now() + ''1 Minute''::interval)) THEN runafter := date_trunc(''MINUTE'', jscstart); ELSE runafter := date_trunc(''MINUTE'', (now() + ''1 Minute''::interval)); END IF; -- -- Enter a loop, generating next run timestamps until we find one -- that falls on the required weekday, and is not matched by an exception -- WHILE bingo = FALSE LOOP -- -- Get the next run year -- nextyear := date_part(''YEAR'', runafter); -- -- Get the next run month -- nextmonth := date_part(''MONTH'', runafter); gotit := FALSE; FOR i IN (nextmonth) .. 12 LOOP IF jscmonths[i] = TRUE THEN nextmonth := i; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. (nextmonth - 1) LOOP IF jscmonths[i] = TRUE THEN nextmonth := i; -- Wrap into next year nextyear := nextyear + 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; -- -- Get the next run day -- -- If the year, or month have incremented, get the lowest day, -- otherwise look for the next day matching or after today. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter)) THEN nextday := 1; FOR i IN 1 .. 32 LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nextday := date_part(''DAY'', runafter); gotit := FALSE; FOR i IN nextday .. 32 LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. (nextday - 1) LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; -- Wrap into next month IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- Was the last day flag selected? IF nextday = 32 THEN IF nextmonth = 1 THEN nextday := 31; ELSIF nextmonth = 2 THEN IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN nextday := 29; ELSE nextday := 28; END IF; ELSIF nextmonth = 3 THEN nextday := 31; ELSIF nextmonth = 4 THEN nextday := 30; ELSIF nextmonth = 5 THEN nextday := 31; ELSIF nextmonth = 6 THEN nextday := 30; ELSIF nextmonth = 7 THEN nextday := 31; ELSIF nextmonth = 8 THEN nextday := 31; ELSIF nextmonth = 9 THEN nextday := 30; ELSIF nextmonth = 10 THEN nextday := 31; ELSIF nextmonth = 11 THEN nextday := 30; ELSIF nextmonth = 12 THEN nextday := 31; END IF; END IF; -- -- Get the next run hour -- -- If the year, month or day have incremented, get the lowest hour, -- otherwise look for the next hour matching or after the current one. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter) OR nextday > date_part(''DAY'', runafter) OR daytweak = TRUE) THEN nexthour := 0; FOR i IN 1 .. 24 LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nexthour := date_part(''HOUR'', runafter); gotit := FALSE; FOR i IN (nexthour + 1) .. 24 LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. nexthour LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; -- Wrap into next month IF (nextmonth = 1 OR nextmonth = 3 OR nextmonth = 5 OR nextmonth = 7 OR nextmonth = 8 OR nextmonth = 10 OR nextmonth = 12) THEN d = 31; ELSIF (nextmonth = 4 OR nextmonth = 6 OR nextmonth = 9 OR nextmonth = 11) THEN d = 30; ELSE IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN d := 29; ELSE d := 28; END IF; END IF; IF nextday = d THEN nextday := 1; IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; ELSE nextday := nextday + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- -- Get the next run minute -- -- If the year, month day or hour have incremented, get the lowest minute, -- otherwise look for the next minute matching or after the current one. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter) OR nextday > date_part(''DAY'', runafter) OR nexthour > date_part(''HOUR'', runafter) OR daytweak = TRUE) THEN nextminute := 0; IF minutetweak = TRUE THEN d := 1; ELSE d := date_part(''MINUTE'', runafter)::int2; END IF; FOR i IN d .. 60 LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nextminute := date_part(''MINUTE'', runafter); gotit := FALSE; FOR i IN (nextminute + 1) .. 60 LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. nextminute LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; -- Wrap into next hour IF (nextmonth = 1 OR nextmonth = 3 OR nextmonth = 5 OR nextmonth = 7 OR nextmonth = 8 OR nextmonth = 10 OR nextmonth = 12) THEN d = 31; ELSIF (nextmonth = 4 OR nextmonth = 6 OR nextmonth = 9 OR nextmonth = 11) THEN d = 30; ELSE IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN d := 29; ELSE d := 28; END IF; END IF; IF nexthour = 23 THEN nexthour = 0; IF nextday = d THEN nextday := 1; IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; ELSE nextday := nextday + 1; END IF; ELSE nexthour := nexthour + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- Build the result, and check it is not the same as runafter - this may -- happen if all array entries are set to false. In this case, add a minute. nextrun := (nextyear::varchar || ''-''::varchar || nextmonth::varchar || ''-'' || nextday::varchar || '' '' || nexthour::varchar || '':'' || nextminute::varchar)::timestamptz; IF nextrun = runafter AND foundval = FALSE THEN nextrun := nextrun + INTERVAL ''1 Minute''; END IF; -- If the result is past the end date, exit. IF nextrun > jscend THEN RETURN NULL; END IF; -- Check to ensure that the nextrun time is actually still valid. Its -- possible that wrapped values may have carried the nextrun onto an -- invalid time or date. IF ((jscminutes = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscminutes[date_part(''MINUTE'', nextrun) + 1] = TRUE) AND (jschours = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jschours[date_part(''HOUR'', nextrun) + 1] = TRUE) AND (jscmonthdays = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscmonthdays[date_part(''DAY'', nextrun)] = TRUE OR (jscmonthdays = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,t}'' AND ((date_part(''MONTH'', nextrun) IN (1,3,5,7,8,10,12) AND date_part(''DAY'', nextrun) = 31) OR (date_part(''MONTH'', nextrun) IN (4,6,9,11) AND date_part(''DAY'', nextrun) = 30) OR (date_part(''MONTH'', nextrun) = 2 AND ((pgagent.pga_is_leap_year(date_part(''YEAR'', nextrun)::int2) AND date_part(''DAY'', nextrun) = 29) OR date_part(''DAY'', nextrun) = 28))))) AND (jscmonths = ''{f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscmonths[date_part(''MONTH'', nextrun)] = TRUE)) THEN -- Now, check to see if the nextrun time found is a) on an acceptable -- weekday, and b) not matched by an exception. If not, set -- runafter = nextrun and try again. -- Check for a wildcard weekday gotit := FALSE; FOR i IN 1 .. 7 LOOP IF jscweekdays[i] = TRUE THEN gotit := TRUE; EXIT; END IF; END LOOP; -- OK, is the correct weekday selected, or a wildcard? IF (jscweekdays[date_part(''DOW'', nextrun) + 1] = TRUE OR gotit = FALSE) THEN -- Check for exceptions SELECT INTO d jexid FROM pgagent.pga_exception WHERE jexscid = jscid AND ((jexdate = nextrun::date AND jextime = nextrun::time) OR (jexdate = nextrun::date AND jextime IS NULL) OR (jexdate IS NULL AND jextime = nextrun::time)); IF FOUND THEN -- Nuts - found an exception. Increment the time and try again runafter := nextrun + INTERVAL ''1 Minute''; bingo := FALSE; minutetweak := TRUE; daytweak := FALSE; ELSE bingo := TRUE; END IF; ELSE -- We''re on the wrong week day - increment a day and try again. runafter := nextrun + INTERVAL ''1 Day''; bingo := FALSE; minutetweak := FALSE; daytweak := TRUE; END IF; ELSE runafter := nextrun + INTERVAL ''1 Minute''; bingo := FALSE; minutetweak := TRUE; daytweak := FALSE; END IF; END LOOP; RETURN nextrun; END; ' LANGUAGE 'plpgsql' VOLATILE; COMMENT ON FUNCTION pgagent.pga_next_schedule(int4, timestamptz, timestamptz, _bool, _bool, _bool, _bool, _bool) IS 'Calculates the next runtime for a given schedule'; pgagent-REL-4_2_2/sql/pgagent--4.0--4.2.sql000066400000000000000000000353731412006174200176350ustar00rootroot00000000000000/* // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // pgagent--4.0--4.2.sql - Upgrade the pgAgent schema to 4.2 // */ \echo Use "ALTER EXTENSION pgagent UPDATE" to load this file. \quit CREATE OR REPLACE FUNCTION pgagent.pga_next_schedule(int4, timestamptz, timestamptz, _bool, _bool, _bool, _bool, _bool) RETURNS timestamptz AS ' DECLARE jscid ALIAS FOR $1; jscstart ALIAS FOR $2; jscend ALIAS FOR $3; jscminutes ALIAS FOR $4; jschours ALIAS FOR $5; jscweekdays ALIAS FOR $6; jscmonthdays ALIAS FOR $7; jscmonths ALIAS FOR $8; nextrun timestamp := ''1970-01-01 00:00:00-00''; runafter timestamp := ''1970-01-01 00:00:00-00''; bingo bool := FALSE; gotit bool := FALSE; foundval bool := FALSE; daytweak bool := FALSE; minutetweak bool := FALSE; i int2 := 0; d int2 := 0; nextminute int2 := 0; nexthour int2 := 0; nextday int2 := 0; nextmonth int2 := 0; nextyear int2 := 0; BEGIN -- No valid start date has been specified IF jscstart IS NULL THEN RETURN NULL; END IF; -- The schedule is past its end date IF jscend IS NOT NULL AND jscend < now() THEN RETURN NULL; END IF; -- Get the time to find the next run after. It will just be the later of -- now() + 1m and the start date for the time being, however, we might want to -- do more complex things using this value in the future. IF date_trunc(''MINUTE'', jscstart) > date_trunc(''MINUTE'', (now() + ''1 Minute''::interval)) THEN runafter := date_trunc(''MINUTE'', jscstart); ELSE runafter := date_trunc(''MINUTE'', (now() + ''1 Minute''::interval)); END IF; -- -- Enter a loop, generating next run timestamps until we find one -- that falls on the required weekday, and is not matched by an exception -- WHILE bingo = FALSE LOOP -- -- Get the next run year -- nextyear := date_part(''YEAR'', runafter); -- -- Get the next run month -- nextmonth := date_part(''MONTH'', runafter); gotit := FALSE; FOR i IN (nextmonth) .. 12 LOOP IF jscmonths[i] = TRUE THEN nextmonth := i; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. (nextmonth - 1) LOOP IF jscmonths[i] = TRUE THEN nextmonth := i; -- Wrap into next year nextyear := nextyear + 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; -- -- Get the next run day -- -- If the year, or month have incremented, get the lowest day, -- otherwise look for the next day matching or after today. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter)) THEN nextday := 1; FOR i IN 1 .. 32 LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nextday := date_part(''DAY'', runafter); gotit := FALSE; FOR i IN nextday .. 32 LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. (nextday - 1) LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; -- Wrap into next month IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- Was the last day flag selected? IF nextday = 32 THEN IF nextmonth = 1 THEN nextday := 31; ELSIF nextmonth = 2 THEN IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN nextday := 29; ELSE nextday := 28; END IF; ELSIF nextmonth = 3 THEN nextday := 31; ELSIF nextmonth = 4 THEN nextday := 30; ELSIF nextmonth = 5 THEN nextday := 31; ELSIF nextmonth = 6 THEN nextday := 30; ELSIF nextmonth = 7 THEN nextday := 31; ELSIF nextmonth = 8 THEN nextday := 31; ELSIF nextmonth = 9 THEN nextday := 30; ELSIF nextmonth = 10 THEN nextday := 31; ELSIF nextmonth = 11 THEN nextday := 30; ELSIF nextmonth = 12 THEN nextday := 31; END IF; END IF; -- -- Get the next run hour -- -- If the year, month or day have incremented, get the lowest hour, -- otherwise look for the next hour matching or after the current one. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter) OR nextday > date_part(''DAY'', runafter) OR daytweak = TRUE) THEN nexthour := 0; FOR i IN 1 .. 24 LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nexthour := date_part(''HOUR'', runafter); gotit := FALSE; FOR i IN (nexthour + 1) .. 24 LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. nexthour LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; -- Wrap into next month IF (nextmonth = 1 OR nextmonth = 3 OR nextmonth = 5 OR nextmonth = 7 OR nextmonth = 8 OR nextmonth = 10 OR nextmonth = 12) THEN d = 31; ELSIF (nextmonth = 4 OR nextmonth = 6 OR nextmonth = 9 OR nextmonth = 11) THEN d = 30; ELSE IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN d := 29; ELSE d := 28; END IF; END IF; IF nextday = d THEN nextday := 1; IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; ELSE nextday := nextday + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- -- Get the next run minute -- -- If the year, month day or hour have incremented, get the lowest minute, -- otherwise look for the next minute matching or after the current one. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter) OR nextday > date_part(''DAY'', runafter) OR nexthour > date_part(''HOUR'', runafter) OR daytweak = TRUE) THEN nextminute := 0; IF minutetweak = TRUE THEN d := 1; ELSE d := date_part(''MINUTE'', runafter)::int2; END IF; FOR i IN d .. 60 LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nextminute := date_part(''MINUTE'', runafter); gotit := FALSE; FOR i IN (nextminute + 1) .. 60 LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. nextminute LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; -- Wrap into next hour IF (nextmonth = 1 OR nextmonth = 3 OR nextmonth = 5 OR nextmonth = 7 OR nextmonth = 8 OR nextmonth = 10 OR nextmonth = 12) THEN d = 31; ELSIF (nextmonth = 4 OR nextmonth = 6 OR nextmonth = 9 OR nextmonth = 11) THEN d = 30; ELSE IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN d := 29; ELSE d := 28; END IF; END IF; IF nexthour = 23 THEN nexthour = 0; IF nextday = d THEN nextday := 1; IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; ELSE nextday := nextday + 1; END IF; ELSE nexthour := nexthour + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- Build the result, and check it is not the same as runafter - this may -- happen if all array entries are set to false. In this case, add a minute. nextrun := (nextyear::varchar || ''-''::varchar || nextmonth::varchar || ''-'' || nextday::varchar || '' '' || nexthour::varchar || '':'' || nextminute::varchar)::timestamptz; IF nextrun = runafter AND foundval = FALSE THEN nextrun := nextrun + INTERVAL ''1 Minute''; END IF; -- If the result is past the end date, exit. IF nextrun > jscend THEN RETURN NULL; END IF; -- Check to ensure that the nextrun time is actually still valid. Its -- possible that wrapped values may have carried the nextrun onto an -- invalid time or date. IF ((jscminutes = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscminutes[date_part(''MINUTE'', nextrun) + 1] = TRUE) AND (jschours = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jschours[date_part(''HOUR'', nextrun) + 1] = TRUE) AND (jscmonthdays = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscmonthdays[date_part(''DAY'', nextrun)] = TRUE OR (jscmonthdays = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,t}'' AND ((date_part(''MONTH'', nextrun) IN (1,3,5,7,8,10,12) AND date_part(''DAY'', nextrun) = 31) OR (date_part(''MONTH'', nextrun) IN (4,6,9,11) AND date_part(''DAY'', nextrun) = 30) OR (date_part(''MONTH'', nextrun) = 2 AND ((pgagent.pga_is_leap_year(date_part(''YEAR'', nextrun)::int2) AND date_part(''DAY'', nextrun) = 29) OR date_part(''DAY'', nextrun) = 28))))) AND (jscmonths = ''{f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscmonths[date_part(''MONTH'', nextrun)] = TRUE)) THEN -- Now, check to see if the nextrun time found is a) on an acceptable -- weekday, and b) not matched by an exception. If not, set -- runafter = nextrun and try again. -- Check for a wildcard weekday gotit := FALSE; FOR i IN 1 .. 7 LOOP IF jscweekdays[i] = TRUE THEN gotit := TRUE; EXIT; END IF; END LOOP; -- OK, is the correct weekday selected, or a wildcard? IF (jscweekdays[date_part(''DOW'', nextrun) + 1] = TRUE OR gotit = FALSE) THEN -- Check for exceptions SELECT INTO d jexid FROM pgagent.pga_exception WHERE jexscid = jscid AND ((jexdate = nextrun::date AND jextime = nextrun::time) OR (jexdate = nextrun::date AND jextime IS NULL) OR (jexdate IS NULL AND jextime = nextrun::time)); IF FOUND THEN -- Nuts - found an exception. Increment the time and try again runafter := nextrun + INTERVAL ''1 Minute''; bingo := FALSE; minutetweak := TRUE; daytweak := FALSE; ELSE bingo := TRUE; END IF; ELSE -- We''re on the wrong week day - increment a day and try again. runafter := nextrun + INTERVAL ''1 Day''; bingo := FALSE; minutetweak := FALSE; daytweak := TRUE; END IF; ELSE runafter := nextrun + INTERVAL ''1 Minute''; bingo := FALSE; minutetweak := TRUE; daytweak := FALSE; END IF; END LOOP; RETURN nextrun; END; ' LANGUAGE 'plpgsql' VOLATILE; COMMENT ON FUNCTION pgagent.pga_next_schedule(int4, timestamptz, timestamptz, _bool, _bool, _bool, _bool, _bool) IS 'Calculates the next runtime for a given schedule'; pgagent-REL-4_2_2/sql/pgagent--4.1--4.2.sql000066400000000000000000000353731412006174200176360ustar00rootroot00000000000000/* // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // pgagent--4.1--4.2.sql - Upgrade the pgAgent schema to 4.2 // */ \echo Use "ALTER EXTENSION pgagent UPDATE" to load this file. \quit CREATE OR REPLACE FUNCTION pgagent.pga_next_schedule(int4, timestamptz, timestamptz, _bool, _bool, _bool, _bool, _bool) RETURNS timestamptz AS ' DECLARE jscid ALIAS FOR $1; jscstart ALIAS FOR $2; jscend ALIAS FOR $3; jscminutes ALIAS FOR $4; jschours ALIAS FOR $5; jscweekdays ALIAS FOR $6; jscmonthdays ALIAS FOR $7; jscmonths ALIAS FOR $8; nextrun timestamp := ''1970-01-01 00:00:00-00''; runafter timestamp := ''1970-01-01 00:00:00-00''; bingo bool := FALSE; gotit bool := FALSE; foundval bool := FALSE; daytweak bool := FALSE; minutetweak bool := FALSE; i int2 := 0; d int2 := 0; nextminute int2 := 0; nexthour int2 := 0; nextday int2 := 0; nextmonth int2 := 0; nextyear int2 := 0; BEGIN -- No valid start date has been specified IF jscstart IS NULL THEN RETURN NULL; END IF; -- The schedule is past its end date IF jscend IS NOT NULL AND jscend < now() THEN RETURN NULL; END IF; -- Get the time to find the next run after. It will just be the later of -- now() + 1m and the start date for the time being, however, we might want to -- do more complex things using this value in the future. IF date_trunc(''MINUTE'', jscstart) > date_trunc(''MINUTE'', (now() + ''1 Minute''::interval)) THEN runafter := date_trunc(''MINUTE'', jscstart); ELSE runafter := date_trunc(''MINUTE'', (now() + ''1 Minute''::interval)); END IF; -- -- Enter a loop, generating next run timestamps until we find one -- that falls on the required weekday, and is not matched by an exception -- WHILE bingo = FALSE LOOP -- -- Get the next run year -- nextyear := date_part(''YEAR'', runafter); -- -- Get the next run month -- nextmonth := date_part(''MONTH'', runafter); gotit := FALSE; FOR i IN (nextmonth) .. 12 LOOP IF jscmonths[i] = TRUE THEN nextmonth := i; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. (nextmonth - 1) LOOP IF jscmonths[i] = TRUE THEN nextmonth := i; -- Wrap into next year nextyear := nextyear + 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; -- -- Get the next run day -- -- If the year, or month have incremented, get the lowest day, -- otherwise look for the next day matching or after today. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter)) THEN nextday := 1; FOR i IN 1 .. 32 LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nextday := date_part(''DAY'', runafter); gotit := FALSE; FOR i IN nextday .. 32 LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. (nextday - 1) LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; -- Wrap into next month IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- Was the last day flag selected? IF nextday = 32 THEN IF nextmonth = 1 THEN nextday := 31; ELSIF nextmonth = 2 THEN IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN nextday := 29; ELSE nextday := 28; END IF; ELSIF nextmonth = 3 THEN nextday := 31; ELSIF nextmonth = 4 THEN nextday := 30; ELSIF nextmonth = 5 THEN nextday := 31; ELSIF nextmonth = 6 THEN nextday := 30; ELSIF nextmonth = 7 THEN nextday := 31; ELSIF nextmonth = 8 THEN nextday := 31; ELSIF nextmonth = 9 THEN nextday := 30; ELSIF nextmonth = 10 THEN nextday := 31; ELSIF nextmonth = 11 THEN nextday := 30; ELSIF nextmonth = 12 THEN nextday := 31; END IF; END IF; -- -- Get the next run hour -- -- If the year, month or day have incremented, get the lowest hour, -- otherwise look for the next hour matching or after the current one. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter) OR nextday > date_part(''DAY'', runafter) OR daytweak = TRUE) THEN nexthour := 0; FOR i IN 1 .. 24 LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nexthour := date_part(''HOUR'', runafter); gotit := FALSE; FOR i IN (nexthour + 1) .. 24 LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. nexthour LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; -- Wrap into next month IF (nextmonth = 1 OR nextmonth = 3 OR nextmonth = 5 OR nextmonth = 7 OR nextmonth = 8 OR nextmonth = 10 OR nextmonth = 12) THEN d = 31; ELSIF (nextmonth = 4 OR nextmonth = 6 OR nextmonth = 9 OR nextmonth = 11) THEN d = 30; ELSE IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN d := 29; ELSE d := 28; END IF; END IF; IF nextday = d THEN nextday := 1; IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; ELSE nextday := nextday + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- -- Get the next run minute -- -- If the year, month day or hour have incremented, get the lowest minute, -- otherwise look for the next minute matching or after the current one. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter) OR nextday > date_part(''DAY'', runafter) OR nexthour > date_part(''HOUR'', runafter) OR daytweak = TRUE) THEN nextminute := 0; IF minutetweak = TRUE THEN d := 1; ELSE d := date_part(''MINUTE'', runafter)::int2; END IF; FOR i IN d .. 60 LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nextminute := date_part(''MINUTE'', runafter); gotit := FALSE; FOR i IN (nextminute + 1) .. 60 LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. nextminute LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; -- Wrap into next hour IF (nextmonth = 1 OR nextmonth = 3 OR nextmonth = 5 OR nextmonth = 7 OR nextmonth = 8 OR nextmonth = 10 OR nextmonth = 12) THEN d = 31; ELSIF (nextmonth = 4 OR nextmonth = 6 OR nextmonth = 9 OR nextmonth = 11) THEN d = 30; ELSE IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN d := 29; ELSE d := 28; END IF; END IF; IF nexthour = 23 THEN nexthour = 0; IF nextday = d THEN nextday := 1; IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; ELSE nextday := nextday + 1; END IF; ELSE nexthour := nexthour + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- Build the result, and check it is not the same as runafter - this may -- happen if all array entries are set to false. In this case, add a minute. nextrun := (nextyear::varchar || ''-''::varchar || nextmonth::varchar || ''-'' || nextday::varchar || '' '' || nexthour::varchar || '':'' || nextminute::varchar)::timestamptz; IF nextrun = runafter AND foundval = FALSE THEN nextrun := nextrun + INTERVAL ''1 Minute''; END IF; -- If the result is past the end date, exit. IF nextrun > jscend THEN RETURN NULL; END IF; -- Check to ensure that the nextrun time is actually still valid. Its -- possible that wrapped values may have carried the nextrun onto an -- invalid time or date. IF ((jscminutes = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscminutes[date_part(''MINUTE'', nextrun) + 1] = TRUE) AND (jschours = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jschours[date_part(''HOUR'', nextrun) + 1] = TRUE) AND (jscmonthdays = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscmonthdays[date_part(''DAY'', nextrun)] = TRUE OR (jscmonthdays = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,t}'' AND ((date_part(''MONTH'', nextrun) IN (1,3,5,7,8,10,12) AND date_part(''DAY'', nextrun) = 31) OR (date_part(''MONTH'', nextrun) IN (4,6,9,11) AND date_part(''DAY'', nextrun) = 30) OR (date_part(''MONTH'', nextrun) = 2 AND ((pgagent.pga_is_leap_year(date_part(''YEAR'', nextrun)::int2) AND date_part(''DAY'', nextrun) = 29) OR date_part(''DAY'', nextrun) = 28))))) AND (jscmonths = ''{f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscmonths[date_part(''MONTH'', nextrun)] = TRUE)) THEN -- Now, check to see if the nextrun time found is a) on an acceptable -- weekday, and b) not matched by an exception. If not, set -- runafter = nextrun and try again. -- Check for a wildcard weekday gotit := FALSE; FOR i IN 1 .. 7 LOOP IF jscweekdays[i] = TRUE THEN gotit := TRUE; EXIT; END IF; END LOOP; -- OK, is the correct weekday selected, or a wildcard? IF (jscweekdays[date_part(''DOW'', nextrun) + 1] = TRUE OR gotit = FALSE) THEN -- Check for exceptions SELECT INTO d jexid FROM pgagent.pga_exception WHERE jexscid = jscid AND ((jexdate = nextrun::date AND jextime = nextrun::time) OR (jexdate = nextrun::date AND jextime IS NULL) OR (jexdate IS NULL AND jextime = nextrun::time)); IF FOUND THEN -- Nuts - found an exception. Increment the time and try again runafter := nextrun + INTERVAL ''1 Minute''; bingo := FALSE; minutetweak := TRUE; daytweak := FALSE; ELSE bingo := TRUE; END IF; ELSE -- We''re on the wrong week day - increment a day and try again. runafter := nextrun + INTERVAL ''1 Day''; bingo := FALSE; minutetweak := FALSE; daytweak := TRUE; END IF; ELSE runafter := nextrun + INTERVAL ''1 Minute''; bingo := FALSE; minutetweak := TRUE; daytweak := FALSE; END IF; END LOOP; RETURN nextrun; END; ' LANGUAGE 'plpgsql' VOLATILE; COMMENT ON FUNCTION pgagent.pga_next_schedule(int4, timestamptz, timestamptz, _bool, _bool, _bool, _bool, _bool) IS 'Calculates the next runtime for a given schedule'; pgagent-REL-4_2_2/sql/pgagent--unpackaged--4.2.sql000066400000000000000000000420031412006174200214220ustar00rootroot00000000000000/* // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // pgagent--unpackaged--4.2.sql - Convert pgAgent existing tables and functions to an extension // */ \echo Use "CREATE EXTENSION pgagent FROM unpackaged" to load this file. \quit ALTER EXTENSION pgagent ADD TABLE pgagent.pga_jobagent; ALTER EXTENSION pgagent ADD TABLE pgagent.pga_jobclass; ALTER EXTENSION pgagent ADD TABLE pgagent.pga_job; ALTER EXTENSION pgagent ADD TABLE pgagent.pga_jobstep; ALTER EXTENSION pgagent ADD TABLE pgagent.pga_schedule; ALTER EXTENSION pgagent ADD TABLE pgagent.pga_exception; ALTER EXTENSION pgagent ADD TABLE pgagent.pga_joblog; ALTER EXTENSION pgagent ADD TABLE pgagent.pga_jobsteplog; ALTER EXTENSION pgagent ADD SEQUENCE pgagent.pga_exception_jexid_seq; ALTER EXTENSION pgagent ADD SEQUENCE pgagent.pga_job_jobid_seq; ALTER EXTENSION pgagent ADD SEQUENCE pgagent.pga_jobclass_jclid_seq; ALTER EXTENSION pgagent ADD SEQUENCE pgagent.pga_joblog_jlgid_seq; ALTER EXTENSION pgagent ADD SEQUENCE pgagent.pga_jobstep_jstid_seq; ALTER EXTENSION pgagent ADD SEQUENCE pgagent.pga_jobsteplog_jslid_seq; ALTER EXTENSION pgagent ADD SEQUENCE pgagent.pga_schedule_jscid_seq; ALTER EXTENSION pgagent ADD FUNCTION pgagent.pgagent_schema_version(); ALTER EXTENSION pgagent ADD FUNCTION pgagent.pga_next_schedule(int4, timestamptz, timestamptz, _bool, _bool, _bool, _bool, _bool); ALTER EXTENSION pgagent ADD FUNCTION pgagent.pga_is_leap_year(int2); ALTER EXTENSION pgagent ADD FUNCTION pgagent.pga_job_trigger(); ALTER EXTENSION pgagent ADD FUNCTION pgagent.pga_schedule_trigger(); ALTER EXTENSION pgagent ADD FUNCTION pgagent.pga_exception_trigger(); SELECT pg_catalog.pg_extension_config_dump('pga_jobagent', ''); SELECT pg_catalog.pg_extension_config_dump('pga_jobclass', $$WHERE jclname NOT IN ('Routine Maintenance', 'Data Import', 'Data Export', 'Data Summarisation', 'Miscellaneous')$$); SELECT pg_catalog.pg_extension_config_dump('pga_job', ''); SELECT pg_catalog.pg_extension_config_dump('pga_jobstep', ''); SELECT pg_catalog.pg_extension_config_dump('pga_schedule', ''); SELECT pg_catalog.pg_extension_config_dump('pga_exception', ''); SELECT pg_catalog.pg_extension_config_dump('pga_joblog', ''); SELECT pg_catalog.pg_extension_config_dump('pga_jobsteplog', ''); CREATE OR REPLACE FUNCTION pgagent.pgagent_schema_version() RETURNS int2 AS ' BEGIN -- RETURNS PGAGENT MAJOR VERSION -- WE WILL CHANGE THE MAJOR VERSION, ONLY IF THERE IS A SCHEMA CHANGE RETURN 4; END; ' LANGUAGE 'plpgsql' VOLATILE; CREATE OR REPLACE FUNCTION pgagent.pga_next_schedule(int4, timestamptz, timestamptz, _bool, _bool, _bool, _bool, _bool) RETURNS timestamptz AS ' DECLARE jscid ALIAS FOR $1; jscstart ALIAS FOR $2; jscend ALIAS FOR $3; jscminutes ALIAS FOR $4; jschours ALIAS FOR $5; jscweekdays ALIAS FOR $6; jscmonthdays ALIAS FOR $7; jscmonths ALIAS FOR $8; nextrun timestamp := ''1970-01-01 00:00:00-00''; runafter timestamp := ''1970-01-01 00:00:00-00''; bingo bool := FALSE; gotit bool := FALSE; foundval bool := FALSE; daytweak bool := FALSE; minutetweak bool := FALSE; i int2 := 0; d int2 := 0; nextminute int2 := 0; nexthour int2 := 0; nextday int2 := 0; nextmonth int2 := 0; nextyear int2 := 0; BEGIN -- No valid start date has been specified IF jscstart IS NULL THEN RETURN NULL; END IF; -- The schedule is past its end date IF jscend IS NOT NULL AND jscend < now() THEN RETURN NULL; END IF; -- Get the time to find the next run after. It will just be the later of -- now() + 1m and the start date for the time being, however, we might want to -- do more complex things using this value in the future. IF date_trunc(''MINUTE'', jscstart) > date_trunc(''MINUTE'', (now() + ''1 Minute''::interval)) THEN runafter := date_trunc(''MINUTE'', jscstart); ELSE runafter := date_trunc(''MINUTE'', (now() + ''1 Minute''::interval)); END IF; -- -- Enter a loop, generating next run timestamps until we find one -- that falls on the required weekday, and is not matched by an exception -- WHILE bingo = FALSE LOOP -- -- Get the next run year -- nextyear := date_part(''YEAR'', runafter); -- -- Get the next run month -- nextmonth := date_part(''MONTH'', runafter); gotit := FALSE; FOR i IN (nextmonth) .. 12 LOOP IF jscmonths[i] = TRUE THEN nextmonth := i; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. (nextmonth - 1) LOOP IF jscmonths[i] = TRUE THEN nextmonth := i; -- Wrap into next year nextyear := nextyear + 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; -- -- Get the next run day -- -- If the year, or month have incremented, get the lowest day, -- otherwise look for the next day matching or after today. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter)) THEN nextday := 1; FOR i IN 1 .. 32 LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nextday := date_part(''DAY'', runafter); gotit := FALSE; FOR i IN nextday .. 32 LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. (nextday - 1) LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; -- Wrap into next month IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- Was the last day flag selected? IF nextday = 32 THEN IF nextmonth = 1 THEN nextday := 31; ELSIF nextmonth = 2 THEN IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN nextday := 29; ELSE nextday := 28; END IF; ELSIF nextmonth = 3 THEN nextday := 31; ELSIF nextmonth = 4 THEN nextday := 30; ELSIF nextmonth = 5 THEN nextday := 31; ELSIF nextmonth = 6 THEN nextday := 30; ELSIF nextmonth = 7 THEN nextday := 31; ELSIF nextmonth = 8 THEN nextday := 31; ELSIF nextmonth = 9 THEN nextday := 30; ELSIF nextmonth = 10 THEN nextday := 31; ELSIF nextmonth = 11 THEN nextday := 30; ELSIF nextmonth = 12 THEN nextday := 31; END IF; END IF; -- -- Get the next run hour -- -- If the year, month or day have incremented, get the lowest hour, -- otherwise look for the next hour matching or after the current one. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter) OR nextday > date_part(''DAY'', runafter) OR daytweak = TRUE) THEN nexthour := 0; FOR i IN 1 .. 24 LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nexthour := date_part(''HOUR'', runafter); gotit := FALSE; FOR i IN (nexthour + 1) .. 24 LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. nexthour LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; -- Wrap into next month IF (nextmonth = 1 OR nextmonth = 3 OR nextmonth = 5 OR nextmonth = 7 OR nextmonth = 8 OR nextmonth = 10 OR nextmonth = 12) THEN d = 31; ELSIF (nextmonth = 4 OR nextmonth = 6 OR nextmonth = 9 OR nextmonth = 11) THEN d = 30; ELSE IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN d := 29; ELSE d := 28; END IF; END IF; IF nextday = d THEN nextday := 1; IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; ELSE nextday := nextday + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- -- Get the next run minute -- -- If the year, month day or hour have incremented, get the lowest minute, -- otherwise look for the next minute matching or after the current one. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter) OR nextday > date_part(''DAY'', runafter) OR nexthour > date_part(''HOUR'', runafter) OR daytweak = TRUE) THEN nextminute := 0; IF minutetweak = TRUE THEN d := 1; ELSE d := date_part(''MINUTE'', runafter)::int2; END IF; FOR i IN d .. 60 LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nextminute := date_part(''MINUTE'', runafter); gotit := FALSE; FOR i IN (nextminute + 1) .. 60 LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. nextminute LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; -- Wrap into next hour IF (nextmonth = 1 OR nextmonth = 3 OR nextmonth = 5 OR nextmonth = 7 OR nextmonth = 8 OR nextmonth = 10 OR nextmonth = 12) THEN d = 31; ELSIF (nextmonth = 4 OR nextmonth = 6 OR nextmonth = 9 OR nextmonth = 11) THEN d = 30; ELSE IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN d := 29; ELSE d := 28; END IF; END IF; IF nexthour = 23 THEN nexthour = 0; IF nextday = d THEN nextday := 1; IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; ELSE nextday := nextday + 1; END IF; ELSE nexthour := nexthour + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- Build the result, and check it is not the same as runafter - this may -- happen if all array entries are set to false. In this case, add a minute. nextrun := (nextyear::varchar || ''-''::varchar || nextmonth::varchar || ''-'' || nextday::varchar || '' '' || nexthour::varchar || '':'' || nextminute::varchar)::timestamptz; IF nextrun = runafter AND foundval = FALSE THEN nextrun := nextrun + INTERVAL ''1 Minute''; END IF; -- If the result is past the end date, exit. IF nextrun > jscend THEN RETURN NULL; END IF; -- Check to ensure that the nextrun time is actually still valid. Its -- possible that wrapped values may have carried the nextrun onto an -- invalid time or date. IF ((jscminutes = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscminutes[date_part(''MINUTE'', nextrun) + 1] = TRUE) AND (jschours = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jschours[date_part(''HOUR'', nextrun) + 1] = TRUE) AND (jscmonthdays = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscmonthdays[date_part(''DAY'', nextrun)] = TRUE OR (jscmonthdays = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,t}'' AND ((date_part(''MONTH'', nextrun) IN (1,3,5,7,8,10,12) AND date_part(''DAY'', nextrun) = 31) OR (date_part(''MONTH'', nextrun) IN (4,6,9,11) AND date_part(''DAY'', nextrun) = 30) OR (date_part(''MONTH'', nextrun) = 2 AND ((pgagent.pga_is_leap_year(date_part(''YEAR'', nextrun)::int2) AND date_part(''DAY'', nextrun) = 29) OR date_part(''DAY'', nextrun) = 28))))) AND (jscmonths = ''{f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscmonths[date_part(''MONTH'', nextrun)] = TRUE)) THEN -- Now, check to see if the nextrun time found is a) on an acceptable -- weekday, and b) not matched by an exception. If not, set -- runafter = nextrun and try again. -- Check for a wildcard weekday gotit := FALSE; FOR i IN 1 .. 7 LOOP IF jscweekdays[i] = TRUE THEN gotit := TRUE; EXIT; END IF; END LOOP; -- OK, is the correct weekday selected, or a wildcard? IF (jscweekdays[date_part(''DOW'', nextrun) + 1] = TRUE OR gotit = FALSE) THEN -- Check for exceptions SELECT INTO d jexid FROM pgagent.pga_exception WHERE jexscid = jscid AND ((jexdate = nextrun::date AND jextime = nextrun::time) OR (jexdate = nextrun::date AND jextime IS NULL) OR (jexdate IS NULL AND jextime = nextrun::time)); IF FOUND THEN -- Nuts - found an exception. Increment the time and try again runafter := nextrun + INTERVAL ''1 Minute''; bingo := FALSE; minutetweak := TRUE; daytweak := FALSE; ELSE bingo := TRUE; END IF; ELSE -- We''re on the wrong week day - increment a day and try again. runafter := nextrun + INTERVAL ''1 Day''; bingo := FALSE; minutetweak := FALSE; daytweak := TRUE; END IF; ELSE runafter := nextrun + INTERVAL ''1 Minute''; bingo := FALSE; minutetweak := TRUE; daytweak := FALSE; END IF; END LOOP; RETURN nextrun; END; ' LANGUAGE 'plpgsql' VOLATILE; COMMENT ON FUNCTION pgagent.pga_next_schedule(int4, timestamptz, timestamptz, _bool, _bool, _bool, _bool, _bool) IS 'Calculates the next runtime for a given schedule'; pgagent-REL-4_2_2/sql/pgagent.sql000066400000000000000000000662001412006174200166740ustar00rootroot00000000000000/* // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // pgagent.sql - pgAgent tables and functions // */ BEGIN TRANSACTION; CREATE SCHEMA pgagent; COMMENT ON SCHEMA pgagent IS 'pgAgent system tables'; CREATE TABLE pgagent.pga_jobagent ( jagpid int4 NOT NULL PRIMARY KEY, jaglogintime timestamptz NOT NULL DEFAULT current_timestamp, jagstation text NOT NULL ) WITHOUT OIDS; COMMENT ON TABLE pgagent.pga_jobagent IS 'Active job agents'; CREATE TABLE pgagent.pga_jobclass ( jclid serial NOT NULL PRIMARY KEY, jclname text NOT NULL ) WITHOUT OIDS; CREATE UNIQUE INDEX pga_jobclass_name ON pgagent.pga_jobclass(jclname); COMMENT ON TABLE pgagent.pga_jobclass IS 'Job classification'; INSERT INTO pgagent.pga_jobclass (jclname) VALUES ('Routine Maintenance'); INSERT INTO pgagent.pga_jobclass (jclname) VALUES ('Data Import'); INSERT INTO pgagent.pga_jobclass (jclname) VALUES ('Data Export'); INSERT INTO pgagent.pga_jobclass (jclname) VALUES ('Data Summarisation'); INSERT INTO pgagent.pga_jobclass (jclname) VALUES ('Miscellaneous'); -- Be sure to update pg_extension_config_dump() below and in -- upgrade scripts etc, when adding new classes. CREATE TABLE pgagent.pga_job ( jobid serial NOT NULL PRIMARY KEY, jobjclid int4 NOT NULL REFERENCES pgagent.pga_jobclass (jclid) ON DELETE RESTRICT ON UPDATE RESTRICT, jobname text NOT NULL, jobdesc text NOT NULL DEFAULT '', jobhostagent text NOT NULL DEFAULT '', jobenabled bool NOT NULL DEFAULT true, jobcreated timestamptz NOT NULL DEFAULT current_timestamp, jobchanged timestamptz NOT NULL DEFAULT current_timestamp, jobagentid int4 NULL REFERENCES pgagent.pga_jobagent(jagpid) ON DELETE SET NULL ON UPDATE RESTRICT, jobnextrun timestamptz NULL, joblastrun timestamptz NULL ) WITHOUT OIDS; COMMENT ON TABLE pgagent.pga_job IS 'Job main entry'; COMMENT ON COLUMN pgagent.pga_job.jobagentid IS 'Agent that currently executes this job.'; CREATE TABLE pgagent.pga_jobstep ( jstid serial NOT NULL PRIMARY KEY, jstjobid int4 NOT NULL REFERENCES pgagent.pga_job (jobid) ON DELETE CASCADE ON UPDATE RESTRICT, jstname text NOT NULL, jstdesc text NOT NULL DEFAULT '', jstenabled bool NOT NULL DEFAULT true, jstkind char NOT NULL CHECK (jstkind IN ('b', 's')), -- batch, sql jstcode text NOT NULL, jstconnstr text NOT NULL DEFAULT '' CHECK ((jstconnstr != '' AND jstkind = 's' ) OR (jstconnstr = '' AND (jstkind = 'b' OR jstdbname != ''))), jstdbname name NOT NULL DEFAULT '' CHECK ((jstdbname != '' AND jstkind = 's' ) OR (jstdbname = '' AND (jstkind = 'b' OR jstconnstr != ''))), jstonerror char NOT NULL CHECK (jstonerror IN ('f', 's', 'i')) DEFAULT 'f', -- fail, success, ignore jscnextrun timestamptz NULL ) WITHOUT OIDS; CREATE INDEX pga_jobstep_jobid ON pgagent.pga_jobstep(jstjobid); COMMENT ON TABLE pgagent.pga_jobstep IS 'Job step to be executed'; COMMENT ON COLUMN pgagent.pga_jobstep.jstkind IS 'Kind of jobstep: s=sql, b=batch'; COMMENT ON COLUMN pgagent.pga_jobstep.jstonerror IS 'What to do if step returns an error: f=fail the job, s=mark step as succeeded and continue, i=mark as fail but ignore it and proceed'; CREATE TABLE pgagent.pga_schedule ( jscid serial NOT NULL PRIMARY KEY, jscjobid int4 NOT NULL REFERENCES pgagent.pga_job (jobid) ON DELETE CASCADE ON UPDATE RESTRICT, jscname text NOT NULL, jscdesc text NOT NULL DEFAULT '', jscenabled bool NOT NULL DEFAULT true, jscstart timestamptz NOT NULL DEFAULT current_timestamp, jscend timestamptz NULL, jscminutes bool[60] NOT NULL DEFAULT '{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}', jschours bool[24] NOT NULL DEFAULT '{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}', jscweekdays bool[7] NOT NULL DEFAULT '{f,f,f,f,f,f,f}', jscmonthdays bool[32] NOT NULL DEFAULT '{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}', jscmonths bool[12] NOT NULL DEFAULT '{f,f,f,f,f,f,f,f,f,f,f,f}', CONSTRAINT pga_schedule_jscminutes_size CHECK (array_upper(jscminutes, 1) = 60), CONSTRAINT pga_schedule_jschours_size CHECK (array_upper(jschours, 1) = 24), CONSTRAINT pga_schedule_jscweekdays_size CHECK (array_upper(jscweekdays, 1) = 7), CONSTRAINT pga_schedule_jscmonthdays_size CHECK (array_upper(jscmonthdays, 1) = 32), CONSTRAINT pga_schedule_jscmonths_size CHECK (array_upper(jscmonths, 1) = 12) ) WITHOUT OIDS; CREATE INDEX pga_jobschedule_jobid ON pgagent.pga_schedule(jscjobid); COMMENT ON TABLE pgagent.pga_schedule IS 'Schedule for a job'; CREATE TABLE pgagent.pga_exception ( jexid serial NOT NULL PRIMARY KEY, jexscid int4 NOT NULL REFERENCES pgagent.pga_schedule (jscid) ON DELETE CASCADE ON UPDATE RESTRICT, jexdate date NULL, jextime time NULL ) WITHOUT OIDS; CREATE INDEX pga_exception_jexscid ON pgagent.pga_exception (jexscid); CREATE UNIQUE INDEX pga_exception_datetime ON pgagent.pga_exception (jexdate, jextime); COMMENT ON TABLE pgagent.pga_schedule IS 'Job schedule exceptions'; CREATE TABLE pgagent.pga_joblog ( jlgid serial NOT NULL PRIMARY KEY, jlgjobid int4 NOT NULL REFERENCES pgagent.pga_job (jobid) ON DELETE CASCADE ON UPDATE RESTRICT, jlgstatus char NOT NULL CHECK (jlgstatus IN ('r', 's', 'f', 'i', 'd')) DEFAULT 'r', -- running, success, failed, internal failure, aborted jlgstart timestamptz NOT NULL DEFAULT current_timestamp, jlgduration interval NULL ) WITHOUT OIDS; CREATE INDEX pga_joblog_jobid ON pgagent.pga_joblog(jlgjobid); COMMENT ON TABLE pgagent.pga_joblog IS 'Job run logs.'; COMMENT ON COLUMN pgagent.pga_joblog.jlgstatus IS 'Status of job: r=running, s=successfully finished, f=failed, i=no steps to execute, d=aborted'; CREATE TABLE pgagent.pga_jobsteplog ( jslid serial NOT NULL PRIMARY KEY, jsljlgid int4 NOT NULL REFERENCES pgagent.pga_joblog (jlgid) ON DELETE CASCADE ON UPDATE RESTRICT, jsljstid int4 NOT NULL REFERENCES pgagent.pga_jobstep (jstid) ON DELETE CASCADE ON UPDATE RESTRICT, jslstatus char NOT NULL CHECK (jslstatus IN ('r', 's', 'i', 'f', 'd')) DEFAULT 'r', -- running, success, ignored, failed, aborted jslresult int4 NULL, jslstart timestamptz NOT NULL DEFAULT current_timestamp, jslduration interval NULL, jsloutput text ) WITHOUT OIDS; CREATE INDEX pga_jobsteplog_jslid ON pgagent.pga_jobsteplog(jsljlgid); COMMENT ON TABLE pgagent.pga_jobsteplog IS 'Job step run logs.'; COMMENT ON COLUMN pgagent.pga_jobsteplog.jslstatus IS 'Status of job step: r=running, s=successfully finished, f=failed stopping job, i=ignored failure, d=aborted'; COMMENT ON COLUMN pgagent.pga_jobsteplog.jslresult IS 'Return code of job step'; CREATE OR REPLACE FUNCTION pgagent.pgagent_schema_version() RETURNS int2 AS ' BEGIN -- RETURNS PGAGENT MAJOR VERSION -- WE WILL CHANGE THE MAJOR VERSION, ONLY IF THERE IS A SCHEMA CHANGE RETURN 4; END; ' LANGUAGE 'plpgsql' VOLATILE; CREATE OR REPLACE FUNCTION pgagent.pga_next_schedule(int4, timestamptz, timestamptz, _bool, _bool, _bool, _bool, _bool) RETURNS timestamptz AS ' DECLARE jscid ALIAS FOR $1; jscstart ALIAS FOR $2; jscend ALIAS FOR $3; jscminutes ALIAS FOR $4; jschours ALIAS FOR $5; jscweekdays ALIAS FOR $6; jscmonthdays ALIAS FOR $7; jscmonths ALIAS FOR $8; nextrun timestamp := ''1970-01-01 00:00:00-00''; runafter timestamp := ''1970-01-01 00:00:00-00''; bingo bool := FALSE; gotit bool := FALSE; foundval bool := FALSE; daytweak bool := FALSE; minutetweak bool := FALSE; i int2 := 0; d int2 := 0; nextminute int2 := 0; nexthour int2 := 0; nextday int2 := 0; nextmonth int2 := 0; nextyear int2 := 0; BEGIN -- No valid start date has been specified IF jscstart IS NULL THEN RETURN NULL; END IF; -- The schedule is past its end date IF jscend IS NOT NULL AND jscend < now() THEN RETURN NULL; END IF; -- Get the time to find the next run after. It will just be the later of -- now() + 1m and the start date for the time being, however, we might want to -- do more complex things using this value in the future. IF date_trunc(''MINUTE'', jscstart) > date_trunc(''MINUTE'', (now() + ''1 Minute''::interval)) THEN runafter := date_trunc(''MINUTE'', jscstart); ELSE runafter := date_trunc(''MINUTE'', (now() + ''1 Minute''::interval)); END IF; -- -- Enter a loop, generating next run timestamps until we find one -- that falls on the required weekday, and is not matched by an exception -- WHILE bingo = FALSE LOOP -- -- Get the next run year -- nextyear := date_part(''YEAR'', runafter); -- -- Get the next run month -- nextmonth := date_part(''MONTH'', runafter); gotit := FALSE; FOR i IN (nextmonth) .. 12 LOOP IF jscmonths[i] = TRUE THEN nextmonth := i; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. (nextmonth - 1) LOOP IF jscmonths[i] = TRUE THEN nextmonth := i; -- Wrap into next year nextyear := nextyear + 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; -- -- Get the next run day -- -- If the year, or month have incremented, get the lowest day, -- otherwise look for the next day matching or after today. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter)) THEN nextday := 1; FOR i IN 1 .. 32 LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nextday := date_part(''DAY'', runafter); gotit := FALSE; FOR i IN nextday .. 32 LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. (nextday - 1) LOOP IF jscmonthdays[i] = TRUE THEN nextday := i; -- Wrap into next month IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- Was the last day flag selected? IF nextday = 32 THEN IF nextmonth = 1 THEN nextday := 31; ELSIF nextmonth = 2 THEN IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN nextday := 29; ELSE nextday := 28; END IF; ELSIF nextmonth = 3 THEN nextday := 31; ELSIF nextmonth = 4 THEN nextday := 30; ELSIF nextmonth = 5 THEN nextday := 31; ELSIF nextmonth = 6 THEN nextday := 30; ELSIF nextmonth = 7 THEN nextday := 31; ELSIF nextmonth = 8 THEN nextday := 31; ELSIF nextmonth = 9 THEN nextday := 30; ELSIF nextmonth = 10 THEN nextday := 31; ELSIF nextmonth = 11 THEN nextday := 30; ELSIF nextmonth = 12 THEN nextday := 31; END IF; END IF; -- -- Get the next run hour -- -- If the year, month or day have incremented, get the lowest hour, -- otherwise look for the next hour matching or after the current one. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter) OR nextday > date_part(''DAY'', runafter) OR daytweak = TRUE) THEN nexthour := 0; FOR i IN 1 .. 24 LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nexthour := date_part(''HOUR'', runafter); gotit := FALSE; FOR i IN (nexthour + 1) .. 24 LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. nexthour LOOP IF jschours[i] = TRUE THEN nexthour := i - 1; -- Wrap into next month IF (nextmonth = 1 OR nextmonth = 3 OR nextmonth = 5 OR nextmonth = 7 OR nextmonth = 8 OR nextmonth = 10 OR nextmonth = 12) THEN d = 31; ELSIF (nextmonth = 4 OR nextmonth = 6 OR nextmonth = 9 OR nextmonth = 11) THEN d = 30; ELSE IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN d := 29; ELSE d := 28; END IF; END IF; IF nextday = d THEN nextday := 1; IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; ELSE nextday := nextday + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- -- Get the next run minute -- -- If the year, month day or hour have incremented, get the lowest minute, -- otherwise look for the next minute matching or after the current one. IF (nextyear > date_part(''YEAR'', runafter) OR nextmonth > date_part(''MONTH'', runafter) OR nextday > date_part(''DAY'', runafter) OR nexthour > date_part(''HOUR'', runafter) OR daytweak = TRUE) THEN nextminute := 0; IF minutetweak = TRUE THEN d := 1; ELSE d := date_part(''MINUTE'', runafter)::int2; END IF; FOR i IN d .. 60 LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; foundval := TRUE; EXIT; END IF; END LOOP; ELSE nextminute := date_part(''MINUTE'', runafter); gotit := FALSE; FOR i IN (nextminute + 1) .. 60 LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; IF gotit = FALSE THEN FOR i IN 1 .. nextminute LOOP IF jscminutes[i] = TRUE THEN nextminute := i - 1; -- Wrap into next hour IF (nextmonth = 1 OR nextmonth = 3 OR nextmonth = 5 OR nextmonth = 7 OR nextmonth = 8 OR nextmonth = 10 OR nextmonth = 12) THEN d = 31; ELSIF (nextmonth = 4 OR nextmonth = 6 OR nextmonth = 9 OR nextmonth = 11) THEN d = 30; ELSE IF pgagent.pga_is_leap_year(nextyear) = TRUE THEN d := 29; ELSE d := 28; END IF; END IF; IF nexthour = 23 THEN nexthour = 0; IF nextday = d THEN nextday := 1; IF nextmonth = 12 THEN nextyear := nextyear + 1; nextmonth := 1; ELSE nextmonth := nextmonth + 1; END IF; ELSE nextday := nextday + 1; END IF; ELSE nexthour := nexthour + 1; END IF; gotit := TRUE; foundval := TRUE; EXIT; END IF; END LOOP; END IF; END IF; -- Build the result, and check it is not the same as runafter - this may -- happen if all array entries are set to false. In this case, add a minute. nextrun := (nextyear::varchar || ''-''::varchar || nextmonth::varchar || ''-'' || nextday::varchar || '' '' || nexthour::varchar || '':'' || nextminute::varchar)::timestamptz; IF nextrun = runafter AND foundval = FALSE THEN nextrun := nextrun + INTERVAL ''1 Minute''; END IF; -- If the result is past the end date, exit. IF nextrun > jscend THEN RETURN NULL; END IF; -- Check to ensure that the nextrun time is actually still valid. Its -- possible that wrapped values may have carried the nextrun onto an -- invalid time or date. IF ((jscminutes = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscminutes[date_part(''MINUTE'', nextrun) + 1] = TRUE) AND (jschours = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jschours[date_part(''HOUR'', nextrun) + 1] = TRUE) AND (jscmonthdays = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscmonthdays[date_part(''DAY'', nextrun)] = TRUE OR (jscmonthdays = ''{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,t}'' AND ((date_part(''MONTH'', nextrun) IN (1,3,5,7,8,10,12) AND date_part(''DAY'', nextrun) = 31) OR (date_part(''MONTH'', nextrun) IN (4,6,9,11) AND date_part(''DAY'', nextrun) = 30) OR (date_part(''MONTH'', nextrun) = 2 AND ((pgagent.pga_is_leap_year(date_part(''YEAR'', nextrun)::int2) AND date_part(''DAY'', nextrun) = 29) OR date_part(''DAY'', nextrun) = 28))))) AND (jscmonths = ''{f,f,f,f,f,f,f,f,f,f,f,f}'' OR jscmonths[date_part(''MONTH'', nextrun)] = TRUE)) THEN -- Now, check to see if the nextrun time found is a) on an acceptable -- weekday, and b) not matched by an exception. If not, set -- runafter = nextrun and try again. -- Check for a wildcard weekday gotit := FALSE; FOR i IN 1 .. 7 LOOP IF jscweekdays[i] = TRUE THEN gotit := TRUE; EXIT; END IF; END LOOP; -- OK, is the correct weekday selected, or a wildcard? IF (jscweekdays[date_part(''DOW'', nextrun) + 1] = TRUE OR gotit = FALSE) THEN -- Check for exceptions SELECT INTO d jexid FROM pgagent.pga_exception WHERE jexscid = jscid AND ((jexdate = nextrun::date AND jextime = nextrun::time) OR (jexdate = nextrun::date AND jextime IS NULL) OR (jexdate IS NULL AND jextime = nextrun::time)); IF FOUND THEN -- Nuts - found an exception. Increment the time and try again runafter := nextrun + INTERVAL ''1 Minute''; bingo := FALSE; minutetweak := TRUE; daytweak := FALSE; ELSE bingo := TRUE; END IF; ELSE -- We''re on the wrong week day - increment a day and try again. runafter := nextrun + INTERVAL ''1 Day''; bingo := FALSE; minutetweak := FALSE; daytweak := TRUE; END IF; ELSE runafter := nextrun + INTERVAL ''1 Minute''; bingo := FALSE; minutetweak := TRUE; daytweak := FALSE; END IF; END LOOP; RETURN nextrun; END; ' LANGUAGE 'plpgsql' VOLATILE; COMMENT ON FUNCTION pgagent.pga_next_schedule(int4, timestamptz, timestamptz, _bool, _bool, _bool, _bool, _bool) IS 'Calculates the next runtime for a given schedule'; -- -- Test code -- -- SELECT pgagent.pga_next_schedule( -- 2, -- Schedule ID -- '2005-01-01 00:00:00', -- Start date -- '2006-10-01 00:00:00', -- End date -- '{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}', -- Minutes -- '{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}', -- Hours -- '{f,f,f,f,f,f,f}', -- Weekdays -- '{f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f}', -- Monthdays -- '{f,f,f,f,f,f,f,f,f,f,f,f}' -- Months -- ); CREATE OR REPLACE FUNCTION pgagent.pga_is_leap_year(int2) RETURNS bool AS ' BEGIN IF $1 % 4 != 0 THEN RETURN FALSE; END IF; IF $1 % 100 != 0 THEN RETURN TRUE; END IF; RETURN $1 % 400 = 0; END; ' LANGUAGE 'plpgsql' IMMUTABLE; COMMENT ON FUNCTION pgagent.pga_is_leap_year(int2) IS 'Returns TRUE if $1 is a leap year'; CREATE OR REPLACE FUNCTION pgagent.pga_job_trigger() RETURNS "trigger" AS ' BEGIN IF NEW.jobenabled THEN IF NEW.jobnextrun IS NULL THEN SELECT INTO NEW.jobnextrun MIN(pgagent.pga_next_schedule(jscid, jscstart, jscend, jscminutes, jschours, jscweekdays, jscmonthdays, jscmonths)) FROM pgagent.pga_schedule WHERE jscenabled AND jscjobid=OLD.jobid; END IF; ELSE NEW.jobnextrun := NULL; END IF; RETURN NEW; END; ' LANGUAGE 'plpgsql' VOLATILE; COMMENT ON FUNCTION pgagent.pga_job_trigger() IS 'Update the job''s next run time.'; CREATE TRIGGER pga_job_trigger BEFORE UPDATE ON pgagent.pga_job FOR EACH ROW EXECUTE PROCEDURE pgagent.pga_job_trigger(); COMMENT ON TRIGGER pga_job_trigger ON pgagent.pga_job IS 'Update the job''s next run time.'; CREATE OR REPLACE FUNCTION pgagent.pga_schedule_trigger() RETURNS trigger AS ' BEGIN IF TG_OP = ''DELETE'' THEN -- update pga_job from remaining schedules -- the actual calculation of jobnextrun will be performed in the trigger UPDATE pgagent.pga_job SET jobnextrun = NULL WHERE jobenabled AND jobid=OLD.jscjobid; RETURN OLD; ELSE UPDATE pgagent.pga_job SET jobnextrun = NULL WHERE jobenabled AND jobid=NEW.jscjobid; RETURN NEW; END IF; END; ' LANGUAGE 'plpgsql'; COMMENT ON FUNCTION pgagent.pga_schedule_trigger() IS 'Update the job''s next run time whenever a schedule changes'; CREATE TRIGGER pga_schedule_trigger AFTER INSERT OR UPDATE OR DELETE ON pgagent.pga_schedule FOR EACH ROW EXECUTE PROCEDURE pgagent.pga_schedule_trigger(); COMMENT ON TRIGGER pga_schedule_trigger ON pgagent.pga_schedule IS 'Update the job''s next run time whenever a schedule changes'; CREATE OR REPLACE FUNCTION pgagent.pga_exception_trigger() RETURNS "trigger" AS ' DECLARE v_jobid int4 := 0; BEGIN IF TG_OP = ''DELETE'' THEN SELECT INTO v_jobid jscjobid FROM pgagent.pga_schedule WHERE jscid = OLD.jexscid; -- update pga_job from remaining schedules -- the actual calculation of jobnextrun will be performed in the trigger UPDATE pgagent.pga_job SET jobnextrun = NULL WHERE jobenabled AND jobid = v_jobid; RETURN OLD; ELSE SELECT INTO v_jobid jscjobid FROM pgagent.pga_schedule WHERE jscid = NEW.jexscid; UPDATE pgagent.pga_job SET jobnextrun = NULL WHERE jobenabled AND jobid = v_jobid; RETURN NEW; END IF; END; ' LANGUAGE 'plpgsql' VOLATILE; COMMENT ON FUNCTION pgagent.pga_exception_trigger() IS 'Update the job''s next run time whenever an exception changes'; CREATE TRIGGER pga_exception_trigger AFTER INSERT OR UPDATE OR DELETE ON pgagent.pga_exception FOR EACH ROW EXECUTE PROCEDURE pgagent.pga_exception_trigger(); COMMENT ON TRIGGER pga_exception_trigger ON pgagent.pga_exception IS 'Update the job''s next run time whenever an exception changes'; -- Extension dump support. -- EXT SELECT pg_catalog.pg_extension_config_dump('pga_jobagent', ''); -- EXT SELECT pg_catalog.pg_extension_config_dump('pga_jobclass', $$WHERE jclname NOT IN ('Routine Maintenance', 'Data Import', 'Data Export', 'Data Summarisation', 'Miscellaneous')$$); -- EXT SELECT pg_catalog.pg_extension_config_dump('pga_job', ''); -- EXT SELECT pg_catalog.pg_extension_config_dump('pga_jobstep', ''); -- EXT SELECT pg_catalog.pg_extension_config_dump('pga_schedule', ''); -- EXT SELECT pg_catalog.pg_extension_config_dump('pga_exception', ''); -- EXT SELECT pg_catalog.pg_extension_config_dump('pga_joblog', ''); -- EXT SELECT pg_catalog.pg_extension_config_dump('pga_jobsteplog', ''); COMMIT TRANSACTION; pgagent-REL-4_2_2/test/000077500000000000000000000000001412006174200147025ustar00rootroot00000000000000pgagent-REL-4_2_2/test/Makefile000066400000000000000000000001351412006174200163410ustar00rootroot00000000000000PG_CONFIG = pg_config REGRESS = init job PGXS = $(shell $(PG_CONFIG) --pgxs) include $(PGXS) pgagent-REL-4_2_2/test/expected/000077500000000000000000000000001412006174200165035ustar00rootroot00000000000000pgagent-REL-4_2_2/test/expected/init.out000066400000000000000000000000321412006174200201720ustar00rootroot00000000000000CREATE EXTENSION pgagent; pgagent-REL-4_2_2/test/expected/job.out000066400000000000000000000023461412006174200200130ustar00rootroot00000000000000CREATE TABLE t ( t timestamptz ); WITH id AS (INSERT INTO pgagent.pga_job (jobjclid, jobname, jobdesc, jobenabled, jobhostagent) SELECT jcl.jclid, 'job1', '', true, '' FROM pgagent.pga_jobclass jcl WHERE jclname='Routine Maintenance' RETURNING jobid), insertstep AS (INSERT INTO pgagent.pga_jobstep (jstjobid, jstname, jstdesc, jstenabled, jstkind, jstonerror, jstcode, jstdbname, jstconnstr) SELECT id.jobid, 'step1', '', true, 's', 'f', 'INSERT INTO t VALUES (now())', 'contrib_regression', '' FROM id) INSERT INTO pgagent.pga_schedule (jscjobid, jscname, jscdesc, jscminutes, jschours, jscweekdays, jscmonthdays, jscmonths, jscenabled, jscstart, jscend) SELECT id.jobid, 'schedule1', '', '{t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t}', '{t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t}', '{t,t,t,t,t,t,t}', '{t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t}', '{t,t,t,t,t,t,t,t,t,t,t,t}', true, '2000-01-01 00:00:00', '2099-12-31 00:00:00' FROM id; \! ( pgagent -f -l 2 -s pgagent.out "user=$PGUSER dbname=contrib_regression" ) & sleep 80; kill $! 2> /dev/null || : SELECT count(*) > 0 AS job_run FROM t; job_run --------- t (1 row) pgagent-REL-4_2_2/test/sql/000077500000000000000000000000001412006174200155015ustar00rootroot00000000000000pgagent-REL-4_2_2/test/sql/init.sql000066400000000000000000000000321412006174200171600ustar00rootroot00000000000000CREATE EXTENSION pgagent; pgagent-REL-4_2_2/test/sql/job.sql000066400000000000000000000023061412006174200167750ustar00rootroot00000000000000CREATE TABLE t ( t timestamptz ); WITH id AS (INSERT INTO pgagent.pga_job (jobjclid, jobname, jobdesc, jobenabled, jobhostagent) SELECT jcl.jclid, 'job1', '', true, '' FROM pgagent.pga_jobclass jcl WHERE jclname='Routine Maintenance' RETURNING jobid), insertstep AS (INSERT INTO pgagent.pga_jobstep (jstjobid, jstname, jstdesc, jstenabled, jstkind, jstonerror, jstcode, jstdbname, jstconnstr) SELECT id.jobid, 'step1', '', true, 's', 'f', 'INSERT INTO t VALUES (now())', 'contrib_regression', '' FROM id) INSERT INTO pgagent.pga_schedule (jscjobid, jscname, jscdesc, jscminutes, jschours, jscweekdays, jscmonthdays, jscmonths, jscenabled, jscstart, jscend) SELECT id.jobid, 'schedule1', '', '{t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t}', '{t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t}', '{t,t,t,t,t,t,t}', '{t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t}', '{t,t,t,t,t,t,t,t,t,t,t,t}', true, '2000-01-01 00:00:00', '2099-12-31 00:00:00' FROM id; \! ( pgagent -f -l 2 -s pgagent.out "user=$PGUSER dbname=contrib_regression" ) & sleep 80; kill $! 2> /dev/null || : SELECT count(*) > 0 AS job_run FROM t; pgagent-REL-4_2_2/unix.cpp000066400000000000000000000077111412006174200154200ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // unix.cpp - pgAgent unix specific functions // ////////////////////////////////////////////////////////////////////////// #include "pgAgent.h" // *nix only!! #ifndef WIN32 #include #include #include static boost::mutex s_loggerLock; using namespace std; void printVersion(); void usage(const std::string &appName) { printVersion(); fprintf(stdout, "Usage:\n"); fprintf(stdout, "%s [options] \n", appName.c_str()); fprintf(stdout, "options:\n"); fprintf(stdout, "-v (display version info and then exit)\n"); fprintf(stdout, "-f run in the foreground (do not detach from the terminal)\n"); fprintf(stdout, "-t \n"); fprintf(stdout, "-r =10, default 30)>\n"); fprintf(stdout, "-s \n"); fprintf(stdout, "-l \n"); } void LogMessage(const std::string &msg, const int &level) { std::ofstream out; bool writeToStdOut = false; MutexLocker locker(&s_loggerLock); if (!logFile.empty()) { std::string log_file(logFile.begin(), logFile.end()); out.open((const char *)log_file.c_str(), ios::out | ios::app); if (!out.is_open()) { fprintf(stderr, "Can not open the logfile!"); return; } } else writeToStdOut = true; boost::gregorian::date current_date(boost::gregorian::day_clock::local_day()); std::string day_week = boost::lexical_cast(current_date.day_of_week()); std::string year = boost::lexical_cast(current_date.year()); std::string month = boost::lexical_cast(current_date.month()); std::string day = boost::lexical_cast(current_date.day()); boost::posix_time::ptime pt = boost::posix_time::second_clock::local_time(); std::string time_day = boost::lexical_cast(pt.time_of_day()); std::string logTimeString = ""; logTimeString = day_week + " " + month + " " + day + " " + time_day + " " + year + " "; switch (level) { case LOG_DEBUG: if (minLogLevel >= LOG_DEBUG) (writeToStdOut ? std::cout : out) << logTimeString << "DEBUG: " << msg << std::endl; break; case LOG_WARNING: if (minLogLevel >= LOG_WARNING) (writeToStdOut ? std::cout : out) << logTimeString << "WARNING: " << msg << std::endl; break; case LOG_ERROR: (writeToStdOut ? std::cout : out) << logTimeString << "ERROR: " << msg << std::endl; // On system exit, boost::mutex object calls // pthread_mutex_destroy(...) on the underlying native mutex object. // But - it returns errorcode 'BUSY' instead of 0. Because - it was // still keeping the lock on the resource. And, that results into // an assertion in debug mode. // // Hence - we need to unlock the mutex before calling system exit. locker = (boost::mutex *)NULL; exit(1); break; case LOG_STARTUP: (writeToStdOut ? std::cout : out) << logTimeString << "WARNING: " << msg << std::endl; break; } if (!logFile.empty()) { out.close(); } } // Shamelessly lifted from pg_autovacuum... static void daemonize(void) { pid_t pid; pid = fork(); if (pid == (pid_t)-1) { LogMessage("Cannot disassociate from controlling TTY", LOG_ERROR); exit(1); } else if (pid) exit(0); #ifdef HAVE_SETSID if (setsid() < 0) { LogMessage("Cannot disassociate from controlling TTY", LOG_ERROR); exit(1); } #endif } int main(int argc, char **argv) { setlocale(LC_ALL, ""); std::string executable; executable.assign(argv[0]); if (argc < 2) { usage(executable); return 1; } argc--; argv++; setOptions(argc, argv, executable); if (!runInForeground) daemonize(); MainLoop(); return 0; } #endif // !WIN32 pgagent-REL-4_2_2/win32.cpp000066400000000000000000000330701412006174200153740ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////// // // pgAgent - PostgreSQL Tools // // Copyright (C) 2002 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // win32.cpp - pgAgent win32 specific functions // ////////////////////////////////////////////////////////////////////////// #include "pgAgent.h" // This is for Win32 only!! #ifdef WIN32 #include using namespace std; // for debugging purposes, we can start the service paused #define START_SUSPENDED 0 static SERVICE_STATUS serviceStatus; static SERVICE_STATUS_HANDLE serviceStatusHandle; static std::wstring serviceName; static std::wstring user = L".\\Administrator", password; static HANDLE threadHandle = 0; static bool serviceIsRunning; static bool pgagentInitialized; static HANDLE serviceSync; static HANDLE eventHandle; bool stopService(); void printVersion(); // This will be called from MainLoop, if pgagent is initialized properly void Initialized() { pgagentInitialized = true; } // This will be called periodically to check if the service is to be paused. void CheckForInterrupt() { serviceIsRunning = false; long prevCount; ReleaseSemaphore(serviceSync, 1, &prevCount); // if prevCount is zero, the service should be paused. // We're waiting for the semaphore to get signaled again. if (!prevCount) WaitForSingleObject(serviceSync, INFINITE); serviceIsRunning = true; } void LogMessage(const std::string &_msg, const int &level) { const std::wstring msg = s2ws(_msg); if (eventHandle) { LPCWSTR tmp; tmp = _wcsdup(msg.c_str()); switch (level) { case LOG_DEBUG: if (minLogLevel >= LOG_DEBUG) ReportEventW(eventHandle, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, &tmp, NULL); break; case LOG_WARNING: if (minLogLevel >= LOG_WARNING) ReportEventW(eventHandle, EVENTLOG_WARNING_TYPE, 0, 0, NULL, 1, 0, &tmp, NULL); break; case LOG_ERROR: ReportEventW(eventHandle, EVENTLOG_ERROR_TYPE, 0, 0, NULL, 1, 0, &tmp, NULL); stopService(); // Set pgagent initialized to true, as initService // is waiting for it to be intialized pgagentInitialized = true; // Change service status serviceStatus.dwCheckPoint = 0; serviceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(serviceStatusHandle, &serviceStatus); break; // Log startup/connection warnings (valid for any log level) case LOG_STARTUP: ReportEventW(eventHandle, EVENTLOG_WARNING_TYPE, 0, 0, NULL, 1, 0, &tmp, NULL); break; } if (tmp) { free((void *)tmp); tmp = NULL; } } else { switch (level) { case LOG_DEBUG: if (minLogLevel >= LOG_DEBUG) wprintf(L"DEBUG: %s\n", msg.c_str()); break; case LOG_WARNING: if (minLogLevel >= LOG_WARNING) wprintf(L"WARNING: %s\n", msg.c_str()); break; case LOG_ERROR: wprintf(L"ERROR: %s\n", msg.c_str()); pgagentInitialized = true; exit(1); break; // Log startup/connection warnings (valid for any log level) case LOG_STARTUP: wprintf(L"WARNING: %s\n", msg.c_str()); break; } } } // The main working thread of the service unsigned int __stdcall threadProcedure(void *unused) { MainLoop(); return 0; } //////////////////////////////////////////////////////////// // a replacement popen for windows. // // _popen doesn't work in Win2K from a service so we have to // do it the fun way :-) HANDLE win32_popen_r(const WCHAR *command, HANDLE &handle) { HANDLE hWrite, hRead; SECURITY_ATTRIBUTES saAttr; BOOL ret = FALSE; PROCESS_INFORMATION piProcInfo; STARTUPINFOW siStartInfo; WCHAR *cmd; cmd = _wcsdup(command); // Set the bInheritHandle flag so pipe handles are inherited. saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // Create a pipe for the child process's STDOUT. if (!CreatePipe(&hRead, &hWrite, &saAttr, 0)) return NULL; // Ensure the read handle to the pipe for STDOUT is not inherited. SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0); // Now create the child process. ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdError = hWrite; siStartInfo.hStdOutput = hWrite; siStartInfo.dwFlags |= STARTF_USESTDHANDLES; ret = CreateProcessW(NULL, cmd, // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited 0, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &siStartInfo, // STARTUPINFO pointer &piProcInfo); // receives PROCESS_INFORMATION if (!ret) return NULL; else CloseHandle(piProcInfo.hThread); // Close the write end of the pipe and return the read end. if (!CloseHandle(hWrite)) return NULL; handle = piProcInfo.hProcess; return hRead; } //////////////////////////////////////////////////////////// // service control functions bool pauseService() { WaitForSingleObject(serviceSync, shortWait * 1000 - 30); if (!serviceIsRunning) { SuspendThread(threadHandle); return true; } return false; } bool continueService() { ReleaseSemaphore(serviceSync, 1, 0); ResumeThread(threadHandle); return true; } bool stopService() { pauseService(); CloseHandle(threadHandle); threadHandle = 0; return true; } bool initService() { serviceSync = CreateSemaphore(0, 1, 1, 0); unsigned int tid; pgagentInitialized = false; threadHandle = (HANDLE)_beginthreadex(0, 0, threadProcedure, 0, 0, &tid); while (!pgagentInitialized) { if (eventHandle) { serviceStatus.dwWaitHint += 1000; serviceStatus.dwCheckPoint++; SetServiceStatus(serviceStatusHandle, (LPSERVICE_STATUS)&serviceStatus); } Sleep(1000); } return (threadHandle != 0); } void CALLBACK serviceHandler(DWORD ctl) { switch (ctl) { case SERVICE_CONTROL_STOP: { serviceStatus.dwCheckPoint++; serviceStatus.dwCurrentState = SERVICE_STOP_PENDING; SetServiceStatus(serviceStatusHandle, &serviceStatus); stopService(); serviceStatus.dwCheckPoint = 0; serviceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(serviceStatusHandle, &serviceStatus); break; } case SERVICE_CONTROL_PAUSE: { pauseService(); serviceStatus.dwCurrentState = SERVICE_PAUSED; SetServiceStatus(serviceStatusHandle, &serviceStatus); break; } case SERVICE_CONTROL_CONTINUE: { continueService(); serviceStatus.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(serviceStatusHandle, &serviceStatus); break; } default: { break; } } } void CALLBACK serviceMain(DWORD argc, LPTSTR *argv) { serviceName = s2ws((const char *)argv[0]); serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; serviceStatus.dwCurrentState = SERVICE_START_PENDING; serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; serviceStatus.dwWin32ExitCode = 0; serviceStatus.dwCheckPoint = 0; serviceStatus.dwWaitHint = 15000; serviceStatusHandle = RegisterServiceCtrlHandlerW(serviceName.c_str(), serviceHandler); if (serviceStatusHandle) { SetServiceStatus(serviceStatusHandle, &serviceStatus); if (initService()) { serviceStatus.dwCurrentState = SERVICE_RUNNING; serviceStatus.dwWaitHint = 1000; } else serviceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(serviceStatusHandle, &serviceStatus); } } //////////////////////////////////////////////////////////// // installation and removal bool installService(const std::wstring &serviceName, const std::wstring &executable, const std::wstring &args, const std::wstring &displayname, const std::wstring &user, const std::wstring &password) { bool done = false; SC_HANDLE manager = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); if (manager) { std::wstring cmd = executable + L" " + args; std::wstring quser; if (user.find(L"\\") == std::string::npos) quser = L".\\" + user; else quser = user; SC_HANDLE service = CreateServiceW(manager, serviceName.c_str(), displayname.c_str(), SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, cmd.c_str(), 0, 0, 0, quser.c_str(), password.c_str()); if (service) { done = true; CloseServiceHandle(service); } else { LPVOID lpMsgBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL ); LogMessage(ws2s((boost::wformat(L"%s") % lpMsgBuf).str()), LOG_ERROR); } CloseServiceHandle(manager); } // Setup the event message DLL const std::wstring key_path(L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\" + serviceName); HKEY key; DWORD last_error = RegCreateKeyExW(HKEY_LOCAL_MACHINE, key_path.c_str(), 0, 0, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, 0, &key, 0); if (ERROR_SUCCESS == last_error) { std::size_t found = executable.find_last_of(L"/\\"); std::wstring path = executable.substr(0, found) + L"\\pgaevent.dll"; DWORD last_error; const DWORD types_supported = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; last_error = RegSetValueExW(key, L"EventMessageFile", 0, REG_SZ, (unsigned char *)(path.c_str()), (path.length() + 1)*sizeof(std::wstring)); if (ERROR_SUCCESS == last_error) { last_error = RegSetValueExW(key, L"TypesSupported", 0, REG_DWORD, (LPBYTE)&types_supported, sizeof(types_supported)); } if (ERROR_SUCCESS != last_error) { LogMessage( "Could not set the event message file registry value.", LOG_WARNING ); } RegCloseKey(key); } else { LogMessage( "Could not open the message source registry key.", LOG_WARNING ); } return done; } bool removeService(const std::wstring &serviceName) { bool done = false; SC_HANDLE manager = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); if (manager) { SC_HANDLE service = OpenServiceW(manager, serviceName.c_str(), SERVICE_ALL_ACCESS); if (service) { SERVICE_STATUS serviceStatus; ControlService(service, SERVICE_CONTROL_STOP, &serviceStatus); int retries; for (retries = 0; retries < 5; retries++) { if (QueryServiceStatus(service, &serviceStatus)) { if (serviceStatus.dwCurrentState == SERVICE_STOPPED) { DeleteService(service); done = true; break; } Sleep(1000L); } } CloseServiceHandle(service); } CloseServiceHandle(manager); } // Remove the event message DLL const std::wstring key_path(L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\" + serviceName); DWORD last_error = RegDeleteKeyW(HKEY_LOCAL_MACHINE, key_path.c_str()); if (ERROR_SUCCESS != last_error) { LogMessage("Failed to uninstall source", LOG_ERROR); } return done; } void usage(const std::string &executable) { printVersion(); printf("Usage:\n"); printf("%s REMOVE \n", executable.c_str()); printf("%s INSTALL [options] \n", executable.c_str()); printf("%s DEBUG [options] \n", executable.c_str()); printf("options:\n"); printf("-v (display version info and then exit)\n"); printf("-u \n"); printf("-p \n"); printf("-d \n"); printf("-t \n"); printf("-r =10, default 30)>\n"); printf("-l \n"); } //////////////////////////////////////////////////////////// void setupForRun(int argc, char **argv, bool debug, const std::wstring &executable) { if (!debug) { eventHandle = RegisterEventSourceW(0, serviceName.c_str()); if (!eventHandle) LogMessage("Couldn't register event handle.", LOG_ERROR); } setOptions(argc, argv, ws2s(executable)); } void main(int argc, char **argv) { std::string executable; executable.assign(*argv++); if (argc < 3) { usage(executable); return; } std::wstring command; command.assign(s2ws(*argv++)); if (command != L"DEBUG") { serviceName.assign(s2ws(*argv++)); argc -= 3; } else argc -= 2; if (command == L"INSTALL") { std::wstring displayname = L"PostgreSQL Scheduling Agent - " + serviceName; std::wstring args = L"RUN " + serviceName; while (argc-- > 0) { if (argv[0][0] == '-') { switch (argv[0][1]) { case 'u': { user = s2ws(getArg(argc, argv)); break; } case 'p': { password = s2ws(getArg(argc, argv)); break; } case 'd': { displayname = s2ws(getArg(argc, argv)); break; } default: { args += L" " + s2ws(*argv); break; } } } else { args += L" " + s2ws(*argv); } argv++; } bool rc = installService(serviceName, s2ws(executable), args, displayname, user, password); } else if (command == L"REMOVE") { bool rc = removeService(serviceName); } else if (command == L"DEBUG") { setupForRun(argc, argv, true, s2ws(executable)); initService(); #if START_SUSPENDED continueService(); #endif WaitForSingleObject(threadHandle, INFINITE); } else if (command == L"RUN") { std::string app = "pgAgent Service"; SERVICE_TABLE_ENTRY serviceTable[] = { (LPSTR)app.c_str(), serviceMain, 0, 0 }; setupForRun(argc, argv, false, s2ws(executable)); if (!StartServiceCtrlDispatcher(serviceTable)) { DWORD rc = GetLastError(); if (rc) { } } } else { usage(executable); } return; } #endif // WIN32