soci-3.2.3/0000755000000000000000000000000012511402516011147 5ustar rootrootsoci-3.2.3/cmake/0000755000000000000000000000000012511362240012226 5ustar rootrootsoci-3.2.3/cmake/resources/0000755000000000000000000000000012511362240014240 5ustar rootrootsoci-3.2.3/cmake/resources/vs2010-test-cmd-args.vcxproj.user.in0000644000000000000000000000061612511362240022645 0ustar rootroot @SOCI_TEST_CMD_ARGS@ WindowsLocalDebugger soci-3.2.3/cmake/modules/0000755000000000000000000000000012511401144013673 5ustar rootrootsoci-3.2.3/cmake/modules/FindFirebird.cmake0000644000000000000000000000165312511362240017234 0ustar rootroot############################################################## # Copyright (c) 2008 Daniel Pfeifer # # # # Distributed under the Boost Software License, Version 1.0. # ############################################################## # This module defines # FIREBIRD_INCLUDE_DIR - where to find ibase.h # FIREBIRD_LIBRARIES - the libraries to link against to use FIREBIRD # FIREBIRD_FOUND - true if FIREBIRD was found find_path(FIREBIRD_INCLUDE_DIR ibase.h /usr/include $ENV{ProgramFiles}/Firebird/*/include ) find_library(FIREBIRD_LIBRARIES NAMES fbclient fbclient_ms PATHS /usr/lib $ENV{ProgramFiles}/Firebird/*/lib ) # fbembed ? include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Firebird DEFAULT_MSG FIREBIRD_LIBRARIES FIREBIRD_INCLUDE_DIR) mark_as_advanced(FIREBIRD_INCLUDE_DIR FIREBIRD_LIBRARIES) soci-3.2.3/cmake/modules/FindMySQL.cmake0000644000000000000000000001055512511362240016454 0ustar rootroot# - Try to find MySQL / MySQL Embedded library # Find the MySQL includes and client library # This module defines # MYSQL_INCLUDE_DIR, where to find mysql.h # MYSQL_LIBRARIES, the libraries needed to use MySQL. # MYSQL_LIB_DIR, path to the MYSQL_LIBRARIES # MYSQL_EMBEDDED_LIBRARIES, the libraries needed to use MySQL Embedded. # MYSQL_EMBEDDED_LIB_DIR, path to the MYSQL_EMBEDDED_LIBRARIES # MYSQL_FOUND, If false, do not try to use MySQL. # MYSQL_EMBEDDED_FOUND, If false, do not try to use MySQL Embedded. # Copyright (c) 2006-2008, Jarosław Staniek # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. include(CheckCXXSourceCompiles) if(WIN32) find_path(MYSQL_INCLUDE_DIR mysql.h PATHS $ENV{MYSQL_INCLUDE_DIR} $ENV{MYSQL_DIR}/include $ENV{ProgramFiles}/MySQL/*/include $ENV{SystemDrive}/MySQL/*/include ) else(WIN32) find_path(MYSQL_INCLUDE_DIR mysql.h PATHS $ENV{MYSQL_INCLUDE_DIR} $ENV{MYSQL_DIR}/include /usr/local/mysql/include /opt/mysql/mysql/include PATH_SUFFIXES mysql ) endif(WIN32) if(WIN32) if (${CMAKE_BUILD_TYPE}) string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_TOLOWER) endif() # path suffix for debug/release mode # binary_dist: mysql binary distribution # build_dist: custom build if(CMAKE_BUILD_TYPE_TOLOWER MATCHES "debug") set(binary_dist debug) set(build_dist Debug) else(CMAKE_BUILD_TYPE_TOLOWER MATCHES "debug") ADD_DEFINITIONS(-DDBUG_OFF) set(binary_dist opt) set(build_dist Release) endif(CMAKE_BUILD_TYPE_TOLOWER MATCHES "debug") # find_library(MYSQL_LIBRARIES NAMES mysqlclient find_library(MYSQL_LIBRARIES NAMES libmysql PATHS $ENV{MYSQL_DIR}/lib/${binary_dist} $ENV{MYSQL_DIR}/libmysql/${build_dist} $ENV{MYSQL_DIR}/client/${build_dist} $ENV{ProgramFiles}/MySQL/*/lib/${binary_dist} $ENV{SystemDrive}/MySQL/*/lib/${binary_dist} ) else(WIN32) # find_library(MYSQL_LIBRARIES NAMES mysqlclient find_library(MYSQL_LIBRARIES NAMES libmysql PATHS $ENV{MYSQL_DIR}/libmysql_r/.libs $ENV{MYSQL_DIR}/lib $ENV{MYSQL_DIR}/lib/mysql /usr/local/mysql/lib /opt/mysql/mysql/lib PATH_SUFFIXES mysql ) endif(WIN32) if(WIN32) set(MYSQL_LIB_PATHS $ENV{MYSQL_DIR}/lib/opt $ENV{MYSQL_DIR}/client/release $ENV{ProgramFiles}/MySQL/*/lib/opt $ENV{SystemDrive}/MySQL/*/lib/opt ) find_library(MYSQL_LIBRARIES NAMES mysqlclient PATHS ${MYSQL_LIB_PATHS} ) else(WIN32) set(MYSQL_LIB_PATHS $ENV{MYSQL_DIR}/libmysql_r/.libs $ENV{MYSQL_DIR}/lib $ENV{MYSQL_DIR}/lib/mysql /usr/local/mysql/lib /opt/mysql/mysql/lib PATH_SUFFIXES mysql ) find_library(MYSQL_LIBRARIES NAMES mysqlclient PATHS ${MYSQL_LIB_PATHS} ) endif(WIN32) find_library(MYSQL_EMBEDDED_LIBRARIES NAMES mysqld PATHS ${MYSQL_LIB_PATHS} ) if(MYSQL_LIBRARIES) get_filename_component(MYSQL_LIB_DIR ${MYSQL_LIBRARIES} PATH) endif(MYSQL_LIBRARIES) if(MYSQL_EMBEDDED_LIBRARIES) get_filename_component(MYSQL_EMBEDDED_LIB_DIR ${MYSQL_EMBEDDED_LIBRARIES} PATH) endif(MYSQL_EMBEDDED_LIBRARIES) set( CMAKE_REQUIRED_INCLUDES ${MYSQL_INCLUDE_DIR} ) set( CMAKE_REQUIRED_LIBRARIES ${MYSQL_EMBEDDED_LIBRARIES} ) check_cxx_source_compiles( "#include \nint main() { int i = MYSQL_OPT_USE_EMBEDDED_CONNECTION; }" HAVE_MYSQL_OPT_EMBEDDED_CONNECTION ) if(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES) set(MYSQL_FOUND TRUE) message(STATUS "Found MySQL: ${MYSQL_INCLUDE_DIR}, ${MYSQL_LIBRARIES}") else(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES) set(MYSQL_FOUND FALSE) message(STATUS "MySQL not found.") endif(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES) if(MYSQL_INCLUDE_DIR AND MYSQL_EMBEDDED_LIBRARIES AND HAVE_MYSQL_OPT_EMBEDDED_CONNECTION) set(MYSQL_EMBEDDED_FOUND TRUE) message(STATUS "Found MySQL Embedded: ${MYSQL_INCLUDE_DIR}, ${MYSQL_EMBEDDED_LIBRARIES}") else(MYSQL_INCLUDE_DIR AND MYSQL_EMBEDDED_LIBRARIES AND HAVE_MYSQL_OPT_EMBEDDED_CONNECTION) set(MYSQL_EMBEDDED_FOUND FALSE) message(STATUS "MySQL Embedded not found.") endif(MYSQL_INCLUDE_DIR AND MYSQL_EMBEDDED_LIBRARIES AND HAVE_MYSQL_OPT_EMBEDDED_CONNECTION) mark_as_advanced(MYSQL_INCLUDE_DIR MYSQL_LIBRARIES MYSQL_EMBEDDED_LIBRARIES) soci-3.2.3/cmake/modules/FindDL.cmake0000644000000000000000000000106412511362240016001 0ustar rootrootif(DL_INCLUDE_DIR) set(DL_FIND_QUIETLY TRUE) endif() find_path(DL_INCLUDE_DIR dlfcn.h) find_library(DL_LIBRARY NAMES dl) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(DL DEFAULT_MSG DL_LIBRARY DL_INCLUDE_DIR) if(NOT DL_FOUND) # if dlopen can be found without linking in dl then, # dlopen is part of libc, so don't need to link extra libs. include(CheckFunctionExists) check_function_exists(dlopen DL_FOUND) set(DL_LIBRARY "") endif() set(DL_LIBRARIES ${DL_LIBRARY}) mark_as_advanced(DL_LIBRARY DL_INCLUDE_DIR) soci-3.2.3/cmake/modules/FindDB2.cmake0000644000000000000000000000603512511362240016054 0ustar rootroot############################################################################### # CMake module to search for DB2 client library # # On success, the macro sets the following variables: # DB2_FOUND = if the library found # DB2_LIBRARY = full path to the library # DB2_LIBRARIES = full path to the library # DB2_INCLUDE_DIR = where to find the library headers # # Copyright (c) 2013 Denis Chapligin # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # ############################################################################### if(UNIX) set(DB2_INSTALL_PATHS /opt/ibm/db2/V10.1 /opt/ibm/db2/V9.7 /opt/ibm/db2/V9.5 /opt/ibm/db2/V9.1) if(CMAKE_SIZEOF_VOID_P EQUAL 4) set(DB2_LIBDIRS "lib32" "lib") else() set(DB2_LIBDIRS "lib64") endif() set(DB2_FIND_INCLUDE_PATHS) set(DB2_FIND_LIB_PATHS) foreach(db2_install_path ${DB2_INSTALL_PATHS}) if (IS_DIRECTORY ${db2_install_path}/include) set(DB2_FIND_INCLUDE_PATHS ${DB2_FIND_INCLUDE_PATHS} ${db2_install_path}/include) endif() foreach(db2_libdir ${DB2_LIBDIRS}) if (IS_DIRECTORY ${db2_install_path}/${db2_libdir}) set(DB2_FIND_LIB_PATHS ${DB2_FIND_LIB_PATHS} ${db2_install_path}/${db2_libdir}) endif() endforeach(db2_libdir) endforeach(db2_install_path) elseif(WIN32) if (CMAKE_CL_64) # 64-bit build, DB2 64-bit installed set(DB2_FIND_INCLUDE_PATHS $ENV{ProgramW6432}/IBM/SQLLIB/include) set(DB2_FIND_LIB_PATHS $ENV{ProgramW6432}/IBM/SQLLIB/lib) else() # 32-bit build, DB2 64-bit or DB2 32-bit installed if(EXISTS "$ENV{ProgramW6432}/IBM/SQLLIB/lib") # On 64-bit Windows with DB2 64-bit installed: # LIB environment points to {DB2}/IBM/SQLLIB/lib with64-bit db2api.lib, # this flag prevents checking paths in LIB, so Win32 version can be detected set(DB2_FIND_LIB_NO_LIB NO_SYSTEM_ENVIRONMENT_PATH) endif() set(DB2_FIND_INCLUDE_PATHS $ENV{ProgramW6432}/IBM/SQLLIB/include $ENV{ProgramFiles}/IBM/SQLLIB/include) set(DB2_FIND_LIB_PATHS $ENV{ProgramFiles}/IBM/SQLLIB/lib $ENV{ProgramFiles}/IBM/SQLLIB/lib/win32 $ENV{ProgramW6432}/IBM/SQLLIB/lib/win32) endif() endif() find_path(DB2_INCLUDE_DIR sqlcli1.h $ENV{DB2_INCLUDE_DIR} $ENV{DB2_DIR}/include ${DB2_FIND_INCLUDE_PATHS}) find_library(DB2_LIBRARY NAMES db2 db2api PATHS ${DB2_FIND_LIB_PATHS} ${DB2_FIND_LIB_NO_LIB}) if(DB2_LIBRARY) get_filename_component(DB2_LIBRARY_DIR ${DB2_LIBRARY} PATH) endif() if(DB2_INCLUDE_DIR AND DB2_LIBRARY_DIR) set(DB2_FOUND TRUE) include_directories(${DB2_INCLUDE_DIR}) link_directories(${DB2_LIBRARY_DIR}) endif() set(DB2_LIBRARIES ${DB2_LIBRARY}) # Handle the QUIETLY and REQUIRED arguments and set DB2_FOUND to TRUE # if all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(DB2 DEFAULT_MSG DB2_INCLUDE_DIR DB2_LIBRARIES) mark_as_advanced(DB2_INCLUDE_DIR DB2_LIBRARIES) soci-3.2.3/cmake/modules/FindSQLite3.cmake0000644000000000000000000000354412511362240016733 0ustar rootroot############################################################################### # CMake module to search for SQLite 3 library # # On success, the macro sets the following variables: # SQLITE3_FOUND = if the library found # SQLITE3_LIBRARY = full path to the library # SQLITE3_LIBRARIES = full path to the library # SSQLITE3_INCLUDE_DIR = where to find the library headers # # Copyright (c) 2009 Mateusz Loskot # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # ############################################################################### find_path(SQLITE3_INCLUDE_DIR NAMES sqlite3.h PATH_PREFIXES sqlite sqlite3 PATHS /usr/include /usr/local/include $ENV{LIB_DIR}/include $ENV{LIB_DIR}/include/sqlite $ENV{LIB_DIR}/include/sqlite3 $ENV{ProgramFiles}/SQLite/*/include $ENV{ProgramFiles}/SQLite3/*/include $ENV{SystemDrive}/SQLite/*/include $ENV{SystemDrive}/SQLite3/*/include $ENV{SQLITE_ROOT}/include ${SQLITE_ROOT_DIR}/include $ENV{OSGEO4W_ROOT}/include) set(SQLITE3_NAMES sqlite3_i sqlite3) find_library(SQLITE3_LIBRARY NAMES ${SQLITE3_NAMES} PATHS /usr/lib /usr/local/lib $ENV{LIB_DIR}/lib $ENV{ProgramFiles}/SQLite/*/lib $ENV{ProgramFiles}/SQLite3/*/lib $ENV{SystemDrive}/SQLite/*/lib $ENV{SystemDrive}/SQLite3/*/lib $ENV{SQLITE_ROOT}/lib ${SQLITE_ROOT_DIR}/lib $ENV{OSGEO4W_ROOT}/lib) set(SQLITE3_LIBRARIES ${SQLITE3_LIBRARIES} ${SQLITE3_LIBRARY}) #message(STATUS ${SQLITE3_LIBRARY}) # Handle the QUIETLY and REQUIRED arguments and set SQLITE3_FOUND to TRUE # if all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(SQLITE3 DEFAULT_MSG SQLITE3_LIBRARIES SQLITE3_INCLUDE_DIR) mark_as_advanced(SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR SQLITE3_LIBRARIES) soci-3.2.3/cmake/modules/FindSoci.cmake0000644000000000000000000000566712511362240016414 0ustar rootroot############################################################################### # CMake module to search for SOCI library # # WARNING: This module is experimental work in progress. # # This module defines: # SOCI_INCLUDE_DIRS = include dirs to be used when using the soci library # SOCI_LIBRARY = full path to the soci library # SOCI_VERSION = the soci version found (not yet. soci does not provide that info.) # SOCI_FOUND = true if soci was found # # This module respects: # LIB_SUFFIX = (64|32|"") Specifies the suffix for the lib directory # # For each component you specify in find_package(), the following variables are set. # # SOCI_${COMPONENT}_PLUGIN = full path to the soci plugin # SOCI_${COMPONENT}_FOUND # # Copyright (c) 2011 Michael Jansen # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # ############################################################################### # ### Global Configuration Section # SET(_SOCI_ALL_PLUGINS mysql odbc postgresql sqlite3) SET(_SOCI_REQUIRED_VARS SOCI_INCLUDE_DIR SOCI_LIBRARY) # ### FIRST STEP: Find the soci headers. # FIND_PATH( SOCI_INCLUDE_DIR soci.h PATH "/usr/local" PATH_SUFFIXES "" "soci" DOC "Soci (http://soci.sourceforge.net) include directory") MARK_AS_ADVANCED(SOCI_INCLUDE_DIR) SET(SOCI_INCLUDE_DIRS ${SOCI_INCLUDE_DIR}) # ### SECOND STEP: Find the soci core library. Respect LIB_SUFFIX # FIND_LIBRARY( SOCI_LIBRARY NAMES soci_core HINTS ${SOCI_INCLUDE_DIR}/.. PATH_SUFFIXES lib${LIB_SUFFIX}) MARK_AS_ADVANCED(SOCI_LIBRARY) GET_FILENAME_COMPONENT(SOCI_LIBRARY_DIR ${SOCI_LIBRARY} PATH) MARK_AS_ADVANCED(SOCI_LIBRARY_DIR) # ### THIRD STEP: Find all installed plugins if the library was found # IF(SOCI_INCLUDE_DIR AND SOCI_LIBRARY) MESSAGE(STATUS "Soci found: Looking for plugins") FOREACH(plugin IN LISTS _SOCI_ALL_PLUGINS) FIND_LIBRARY( SOCI_${plugin}_PLUGIN NAMES soci_${plugin} HINTS ${SOCI_INCLUDE_DIR}/.. PATH_SUFFIXES lib${LIB_SUFFIX}) MARK_AS_ADVANCED(SOCI_${plugin}_PLUGIN) IF(SOCI_${plugin}_PLUGIN) MESSAGE(STATUS " * Plugin ${plugin} found ${SOCI_${plugin}_PLUGIN}.") SET(SOCI_${plugin}_FOUND True) ELSE() MESSAGE(STATUS " * Plugin ${plugin} not found.") SET(SOCI_${plugin}_FOUND False) ENDIF() ENDFOREACH() # ### FOURTH CHECK: Check if the required components were all found # FOREACH(component ${Soci_FIND_COMPONENTS}) IF(NOT SOCI_${component}_FOUND) MESSAGE(SEND_ERROR "Required component ${component} not found.") ENDIF() ENDFOREACH() ENDIF() # ### ADHERE TO STANDARDS # include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Soci DEFAULT_MSG ${_SOCI_REQUIRED_VARS}) soci-3.2.3/cmake/modules/FindPostgreSQL.cmake0000644000000000000000000000455512511362240017515 0ustar rootroot# - Find PostgreSQL # Find the PostgreSQL includes and client library # This module defines # POSTGRESQL_INCLUDE_DIR, where to find libpq-fe.h # POSTGRESQL_LIBRARIES, libraries needed to use PostgreSQL # POSTGRESQL_VERSION, if found, version of PostgreSQL # POSTGRESQL_FOUND, if false, do not try to use PostgreSQL # # Copyright (c) 2010, Mateusz Loskot, # Copyright (c) 2006, Jaroslaw Staniek, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. find_program(PG_CONFIG NAMES pg_config PATHS /usr/bin /usr/local/bin $ENV{ProgramFiles}/PostgreSQL/*/bin $ENV{SystemDrive}/PostgreSQL/*/bin DOC "Path to pg_config utility") if(PG_CONFIG) exec_program(${PG_CONFIG} ARGS "--version" OUTPUT_VARIABLE PG_CONFIG_VERSION) if(${PG_CONFIG_VERSION} MATCHES "^[A-Za-z]+[ ](.*)$") string(REGEX REPLACE "^[A-Za-z]+[ ](.*)$" "\\1" POSTGRESQL_VERSION "${PG_CONFIG_VERSION}") endif() exec_program(${PG_CONFIG} ARGS "--includedir" OUTPUT_VARIABLE PG_CONFIG_INCLUDEDIR) exec_program(${PG_CONFIG} ARGS "--libdir" OUTPUT_VARIABLE PG_CONFIG_LIBDIR) else() set(POSTGRESQL_VERSION "unknown") endif() find_path(POSTGRESQL_INCLUDE_DIR libpq-fe.h ${PG_CONFIG_INCLUDEDIR} /usr/include/server /usr/include/pgsql/server /usr/local/include/pgsql/server /usr/include/postgresql /usr/include/postgresql/server /usr/include/postgresql/*/server $ENV{ProgramFiles}/PostgreSQL/*/include $ENV{SystemDrive}/PostgreSQL/*/include) find_library(POSTGRESQL_LIBRARIES NAMES pq libpq PATHS ${PG_CONFIG_LIBDIR} /usr/lib /usr/local/lib /usr/lib/postgresql /usr/lib64 /usr/local/lib64 /usr/lib64/postgresql $ENV{ProgramFiles}/PostgreSQL/*/lib $ENV{SystemDrive}/PostgreSQL/*/lib $ENV{ProgramFiles}/PostgreSQL/*/lib/ms $ENV{SystemDrive}/PostgreSQL/*/lib/ms) if(POSTGRESQL_INCLUDE_DIR AND POSTGRESQL_LIBRARIES) set(POSTGRESQL_FOUND TRUE) else() set(POSTGRESQL_FOUND FALSE) endif() # Handle the QUIETLY and REQUIRED arguments and set POSTGRESQL_FOUND to TRUE # if all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(PostgreSQL DEFAULT_MSG POSTGRESQL_INCLUDE_DIR POSTGRESQL_LIBRARIES POSTGRESQL_VERSION) mark_as_advanced(POSTGRESQL_INCLUDE_DIR POSTGRESQL_LIBRARIES) soci-3.2.3/cmake/modules/FindOracle.cmake0000644000000000000000000000517712511362240016720 0ustar rootroot############################################################################### # # CMake module to search for Oracle client library (OCI) # # On success, the macro sets the following variables: # ORACLE_FOUND = if the library found # ORACLE_LIBRARY = full path to the library # ORACLE_LIBRARIES = full path to the library # ORACLE_INCLUDE_DIR = where to find the library headers also defined, # but not for general use are # ORACLE_VERSION = version of library which was found, e.g. "1.2.5" # # Copyright (c) 2009-2013 Mateusz Loskot # # Developed with inspiration from Petr Vanek # who wrote similar macro for TOra - http://torasql.com/ # # Module source: http://github.com/mloskot/workshop/tree/master/cmake/ # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # ############################################################################### # If ORACLE_HOME not defined, assume Oracle libraries not available if(DEFINED ENV{ORACLE_HOME}) set(ORACLE_HOME $ENV{ORACLE_HOME}) message(STATUS "ORACLE_HOME=${ORACLE_HOME}") find_path(ORACLE_INCLUDE_DIR NAMES oci.h PATHS ${ORACLE_HOME}/rdbms/public ${ORACLE_HOME}/include ${ORACLE_HOME}/sdk/include # Oracle SDK ${ORACLE_HOME}/OCI/include) # Oracle XE on Windows set(ORACLE_OCI_NAMES clntsh libclntsh oci) # Dirty trick might help on OSX, see issues/89 set(ORACLE_OCCI_NAMES libocci occi oraocci10 oraocci11) set(ORACLE_NNZ_NAMES nnz10 libnnz10 nnz11 libnnz11 nnz12 libnnz12 ociw32) set(ORACLE_LIB_DIR ${ORACLE_HOME} ${ORACLE_HOME}/lib ${ORACLE_HOME}/sdk/lib # Oracle SDK ${ORACLE_HOME}/sdk/lib/msvc ${ORACLE_HOME}/OCI/lib/msvc) # Oracle XE on Windows find_library(ORACLE_OCI_LIBRARY NAMES ${ORACLE_OCI_NAMES} PATHS ${ORACLE_LIB_DIR}) find_library(ORACLE_OCCI_LIBRARY NAMES ${ORACLE_OCCI_NAMES} PATHS ${ORACLE_LIB_DIR}) find_library(ORACLE_NNZ_LIBRARY NAMES ${ORACLE_NNZ_NAMES} PATHS ${ORACLE_LIB_DIR}) set(ORACLE_LIBRARY ${ORACLE_OCI_LIBRARY} ${ORACLE_OCCI_LIBRARY} ${ORACLE_NNZ_LIBRARY}) if(NOT WIN32) set(ORACLE_LIBRARY ${ORACLE_LIBRARY} ${ORACLE_CLNTSH_LIBRARY}) endif(NOT WIN32) set(ORACLE_LIBRARIES ${ORACLE_LIBRARY}) endif(DEFINED ENV{ORACLE_HOME}) # Handle the QUIETLY and REQUIRED arguments and set ORACLE_FOUND to TRUE # if all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(ORACLE DEFAULT_MSG ORACLE_LIBRARY ORACLE_INCLUDE_DIR) mark_as_advanced(ORACLE_INCLUDE_DIR ORACLE_LIBRARY) soci-3.2.3/cmake/modules/FindODBC.cmake0000644000000000000000000000372512511401144016214 0ustar rootroot# # Find the ODBC driver manager includes and library. # # ODBC is an open standard for connecting to different databases in a # semi-vendor-independent fashion. First you install the ODBC driver # manager. Then you need a driver for each separate database you want # to connect to (unless a generic one works). VTK includes neither # the driver manager nor the vendor-specific drivers: you have to find # those yourself. # # This module defines # ODBC_INCLUDE_DIR, where to find sql.h # ODBC_LIBRARIES, the libraries to link against to use ODBC # ODBC_FOUND. If false, you cannot build anything that requires MySQL. # also defined, but not for general use is # ODBC_LIBRARY, where to find the ODBC driver manager library. set(ODBC_FOUND FALSE) find_path(ODBC_INCLUDE_DIR sql.h /usr/include /usr/include/odbc /usr/local/include /usr/local/include/odbc /usr/local/odbc/include "C:/Program Files (x86)/Windows Kits/8.0/include/um" "C:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A/Include" "C:/Program Files/ODBC/include" "C:/Program Files/Microsoft SDKs/Windows/v7.0/include" "C:/Program Files/Microsoft SDKs/Windows/v6.0a/include" "C:/ODBC/include" DOC "Specify the directory containing sql.h." ) if(MSVC) # msvc knows where to find sdk libs set(ODBC_LIBRARY odbc32) else() find_library(ODBC_LIBRARY NAMES iodbc odbc odbcinst odbc32 PATHS /usr/lib /usr/lib/odbc /usr/local/lib /usr/local/lib/odbc /usr/local/odbc/lib "C:/Program Files (x86)/Windows Kits/8.0/Lib/win8/um/x86/" "C:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A/Lib" "C:/Program Files/ODBC/lib" "C:/ODBC/lib/debug" DOC "Specify the ODBC driver manager library here." ) endif() if(ODBC_LIBRARY) if(ODBC_INCLUDE_DIR) set( ODBC_FOUND 1 ) endif() endif() set(ODBC_LIBRARIES ${ODBC_LIBRARY}) mark_as_advanced(ODBC_FOUND ODBC_LIBRARY ODBC_EXTRA_LIBRARIES ODBC_INCLUDE_DIR) soci-3.2.3/cmake/SociUtilities.cmake0000644000000000000000000003350212511362240016024 0ustar rootroot################################################################################ # SociUtilities.cmake - part of CMake configuration of SOCI library # # Based on BoostUtilities.cmake from CMake configuration for Boost ################################################################################ # Copyright (C) 2007 Douglas Gregor # Copyright (C) 2007 Troy Straszheim # Copyright (C) 2010 Mateusz Loskot # # Distributed under the Boost Software License, Version 1.0. # See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt ################################################################################ # Macros in this module: # # list_contains: Determine whether a string value is in a list. # # car: Return the first element in a list # # cdr: Return all but the first element in a list # # parse_arguments: Parse keyword arguments for use in other macros. # # soci_check_package_found: Test varname-FOUND for case-insensitive varname # ################################################################################ # This utility macro determines whether a particular string value # occurs within a list of strings: # # list_contains(result string_to_find arg1 arg2 arg3 ... argn) # # This macro sets the variable named by result equal to TRUE if # string_to_find is found anywhere in the following arguments. macro(list_contains var value) set(${var}) foreach (value2 ${ARGN}) if (${value} STREQUAL ${value2}) set(${var} TRUE) endif (${value} STREQUAL ${value2}) endforeach (value2) endmacro(list_contains) # This utility macro extracts the first argument from the list of # arguments given, and places it into the variable named var. # # car(var arg1 arg2 ...) macro(car var) set(${var} ${ARGV1}) endmacro(car) # This utility macro extracts all of the arguments given except the # first, and places them into the variable named var. # # car(var arg1 arg2 ...) macro(cdr var junk) set(${var} ${ARGN}) endmacro(cdr) # The parse_arguments macro will take the arguments of another macro and # define several variables. The first argument to parse_arguments is a # prefix to put on all variables it creates. The second argument is a # list of names, and the third argument is a list of options. Both of # these lists should be quoted. The rest of parse_arguments are # arguments from another macro to be parsed. # # parse_arguments(prefix arg_names options arg1 arg2...) # # For each item in options, parse_arguments will create a variable with # that name, prefixed with prefix_. So, for example, if prefix is # MY_MACRO and options is OPTION1;OPTION2, then parse_arguments will # create the variables MY_MACRO_OPTION1 and MY_MACRO_OPTION2. These # variables will be set to true if the option exists in the command line # or false otherwise. # # For each item in arg_names, parse_arguments will create a variable # with that name, prefixed with prefix_. Each variable will be filled # with the arguments that occur after the given arg_name is encountered # up to the next arg_name or the end of the arguments. All options are # removed from these lists. parse_arguments also creates a # prefix_DEFAULT_ARGS variable containing the list of all arguments up # to the first arg_name encountered. macro(parse_arguments prefix arg_names option_names) set(DEFAULT_ARGS) foreach(arg_name ${arg_names}) set(${prefix}_${arg_name}) endforeach(arg_name) foreach(option ${option_names}) set(${prefix}_${option} FALSE) endforeach(option) set(current_arg_name DEFAULT_ARGS) set(current_arg_list) foreach(arg ${ARGN}) list_contains(is_arg_name ${arg} ${arg_names}) if (is_arg_name) set(${prefix}_${current_arg_name} ${current_arg_list}) set(current_arg_name ${arg}) set(current_arg_list) else (is_arg_name) list_contains(is_option ${arg} ${option_names}) if (is_option) set(${prefix}_${arg} TRUE) else (is_option) set(current_arg_list ${current_arg_list} ${arg}) endif (is_option) endif (is_arg_name) endforeach(arg) set(${prefix}_${current_arg_name} ${current_arg_list}) endmacro(parse_arguments) # Perform a reverse topological sort on the given LIST. # # topological_sort(my_list "MY_" "_EDGES") # # LIST is the name of a variable containing a list of elements to be # sorted in reverse topological order. Each element in the list has a # set of outgoing edges (for example, those other list elements that # it depends on). In the resulting reverse topological ordering # (written back into the variable named LIST), an element will come # later in the list than any of the elements that can be reached by # following its outgoing edges and the outgoing edges of any vertices # they target, recursively. Thus, if the edges represent dependencies # on build targets, for example, the reverse topological ordering is # the order in which one would build those targets. # # For each element E in this list, the edges for E are contained in # the variable named ${PREFIX}${E}${SUFFIX}, where E is the # upper-cased version of the element in the list. If no such variable # exists, then it is assumed that there are no edges. For example, if # my_list contains a, b, and c, one could provide a dependency graph # using the following variables: # # MY_A_EDGES b # MY_B_EDGES # MY_C_EDGES a b # # With the involcation of topological_sort shown above and these # variables, the resulting reverse topological ordering will be b, a, # c. function(topological_sort LIST PREFIX SUFFIX) # Clear the stack and output variable set(VERTICES "${${LIST}}") set(STACK) set(${LIST}) # Loop over all of the vertices, starting the topological sort from # each one. foreach(VERTEX ${VERTICES}) string(TOUPPER ${VERTEX} UPPER_VERTEX) # If we haven't already processed this vertex, start a depth-first # search from where. if (NOT FOUND_${UPPER_VERTEX}) # Push this vertex onto the stack with all of its outgoing edges string(REPLACE ";" " " NEW_ELEMENT "${VERTEX};${${PREFIX}${UPPER_VERTEX}${SUFFIX}}") list(APPEND STACK ${NEW_ELEMENT}) # We've now seen this vertex set(FOUND_${UPPER_VERTEX} TRUE) # While the depth-first search stack is not empty list(LENGTH STACK STACK_LENGTH) while(STACK_LENGTH GREATER 0) # Remove the vertex and its remaining out-edges from the top # of the stack list(GET STACK -1 OUT_EDGES) list(REMOVE_AT STACK -1) # Get the source vertex and the list of out-edges separate_arguments(OUT_EDGES) list(GET OUT_EDGES 0 SOURCE) list(REMOVE_AT OUT_EDGES 0) # While there are still out-edges remaining list(LENGTH OUT_EDGES OUT_DEGREE) while (OUT_DEGREE GREATER 0) # Pull off the first outgoing edge list(GET OUT_EDGES 0 TARGET) list(REMOVE_AT OUT_EDGES 0) string(TOUPPER ${TARGET} UPPER_TARGET) if (NOT FOUND_${UPPER_TARGET}) # We have not seen the target before, so we will traverse # its outgoing edges before coming back to our # source. This is the key to the depth-first traversal. # We've now seen this vertex set(FOUND_${UPPER_TARGET} TRUE) # Push the remaining edges for the current vertex onto the # stack string(REPLACE ";" " " NEW_ELEMENT "${SOURCE};${OUT_EDGES}") list(APPEND STACK ${NEW_ELEMENT}) # Setup the new source and outgoing edges set(SOURCE ${TARGET}) string(TOUPPER ${SOURCE} UPPER_SOURCE) set(OUT_EDGES ${${PREFIX}${UPPER_SOURCE}${SUFFIX}}) endif(NOT FOUND_${UPPER_TARGET}) list(LENGTH OUT_EDGES OUT_DEGREE) endwhile (OUT_DEGREE GREATER 0) # We have finished all of the outgoing edges for # SOURCE; add it to the resulting list. list(APPEND ${LIST} ${SOURCE}) # Check the length of the stack list(LENGTH STACK STACK_LENGTH) endwhile(STACK_LENGTH GREATER 0) endif (NOT FOUND_${UPPER_VERTEX}) endforeach(VERTEX) set(${LIST} ${${LIST}} PARENT_SCOPE) endfunction(topological_sort) # Small little hack that tweaks a component name (as used for CPack) # to make sure to avoid certain names that cause problems. Sets the # variable named varname to the "sanitized" name. # # FIXME: This is a complete hack. We probably need to fix the CPack # generators (NSIS in particular) to get rid of the need for this. macro(fix_cpack_component_name varname name) if (${name} STREQUAL "foreach") set(${varname} "boost_foreach") else() set(${varname} ${name}) endif() endmacro() # # A big shout out to the cmake gurus @ compiz # function (colormsg) string (ASCII 27 _escape) set(WHITE "29") set(GRAY "30") set(RED "31") set(GREEN "32") set(YELLOW "33") set(BLUE "34") set(MAG "35") set(CYAN "36") foreach (color WHITE GRAY RED GREEN YELLOW BLUE MAG CYAN) set(HI${color} "1\;${${color}}") set(LO${color} "2\;${${color}}") set(_${color}_ "4\;${${color}}") set(_HI${color}_ "1\;4\;${${color}}") set(_LO${color}_ "2\;4\;${${color}}") endforeach() set(str "") set(coloron FALSE) foreach(arg ${ARGV}) if (NOT ${${arg}} STREQUAL "") if (CMAKE_COLOR_MAKEFILE) set(str "${str}${_escape}[${${arg}}m") set(coloron TRUE) endif() else() set(str "${str}${arg}") if (coloron) set(str "${str}${_escape}[0m") set(coloron FALSE) endif() set(str "${str} ") endif() endforeach() message(STATUS ${str}) endfunction() # colormsg("Colors:" # WHITE "white" GRAY "gray" GREEN "green" # RED "red" YELLOW "yellow" BLUE "blue" MAG "mag" CYAN "cyan" # _WHITE_ "white" _GRAY_ "gray" _GREEN_ "green" # _RED_ "red" _YELLOW_ "yellow" _BLUE_ "blue" _MAG_ "mag" _CYAN_ "cyan" # _HIWHITE_ "white" _HIGRAY_ "gray" _HIGREEN_ "green" # _HIRED_ "red" _HIYELLOW_ "yellow" _HIBLUE_ "blue" _HIMAG_ "mag" _HICYAN_ "cyan" # HIWHITE "white" HIGRAY "gray" HIGREEN "green" # HIRED "red" HIYELLOW "yellow" HIBLUE "blue" HIMAG "mag" HICYAN "cyan" # "right?") # # pretty-prints the value of a variable so that the # equals signs align # function(boost_report_value NAME) string(LENGTH "${NAME}" varlen) # LOG #message(STATUS "boost_report_value: NAME=${NAME} (${varlen})") #message(STATUS "boost_report_value: \${NAME}=${${NAME}}") math(EXPR padding_len 40-${varlen}) string(SUBSTRING " " 0 ${padding_len} varpadding) colormsg("${NAME}${varpadding} = ${${NAME}}") endfunction() function(trace NAME) if(BOOST_CMAKE_TRACE) string(LENGTH "${NAME}" varlen) math(EXPR padding_len 40-${varlen}) string(SUBSTRING "........................................" 0 ${padding_len} varpadding) message("${NAME} ${varpadding} ${${NAME}}") endif() endfunction() # # pretty-prints the value of a variable so that the # equals signs align # function(boost_report_pretty PRETTYNAME VARNAME) string(LENGTH "${PRETTYNAME}" varlen) math(EXPR padding_len 30-${varlen}) string(SUBSTRING " " 0 ${padding_len} varpadding) message(STATUS "${PRETTYNAME}${varpadding} = ${${VARNAME}}") endfunction() # # assert that ARG is actually a library target # macro(dependency_check ARG) trace(ARG) if (NOT "${ARG}" STREQUAL "") get_target_property(deptype ${ARG} TYPE) if(NOT deptype MATCHES ".*_LIBRARY$") set(DEPENDENCY_OKAY FALSE) list(APPEND DEPENDENCY_FAILURES ${ARG}) endif() endif() endmacro() # # Tests package-FOUND for varname in three cases as given, lowercase and # uppercase. # macro(soci_check_package_found NAME SUCCESS) set(${SUCCESS} FALSE) set(VARNAME ${NAME}) set(VARNAME_SUCCESS ${${VARNAME}_FOUND}) # Test both, given original name and uppercase version too if(VARNAME_SUCCESS) set(${SUCCESS} TRUE) else() string(TOUPPER ${NAME} VARNAME) set(VARNAME_SUCCESS ${${VARNAME}_FOUND}) if(VARNAME_SUCCESS) set(${SUCCESS} TRUE) endif() endif() endmacro() # # Pretty-print of given property of current directory. # macro(soci_report_directory_property PROPNAME) get_directory_property(${PROPNAME} ${PROPNAME}) boost_report_value(${PROPNAME}) endmacro() # # Scans the current directory and returns a list of subdirectories. # Author: Robert Fleming # Source: http://www.cmake.org/pipermail/cmake/2008-February/020114.html # # Third parameter is 1 if you want relative paths returned. # Usage: list_subdirectories(the_list_is_returned_here /path/to/project TRUE) # macro(list_subdirectories retval curdir return_relative) file(GLOB sub-dir RELATIVE ${curdir} *) set(list_of_dirs "") foreach(dir ${sub-dir}) if(IS_DIRECTORY ${curdir}/${dir}) if (${return_relative}) set(list_of_dirs ${list_of_dirs} ${dir}) else() set(list_of_dirs ${list_of_dirs} ${curdir}/${dir}) endif() endif() endforeach() set(${retval} ${list_of_dirs}) endmacro() # # Generates output name for given target depending on platform and version. # For instance, on Windows, libraries get ABI version suffix soci_coreXY.{dll|lib}. # function(soci_target_output_name TARGET_NAME OUTPUT_NAME) if(NOT DEFINED TARGET_NAME) message(SEND_ERROR "Error, the variable TARGET_NAME is not defined!") endif() if(NOT DEFINED ${PROJECT_NAME}_VERSION) message(SEND_ERROR "Error, the variable ${${PROJECT_NAME}_VERSION} is not defined!") endif() # On Windows, ABI version is specified using binary file name suffix. # On Unix, suffix is empty and SOVERSION is used instead. if (WIN32) string(LENGTH "${${PROJECT_NAME}_ABI_VERSION}" abilen) if(abilen GREATER 0) set(SUFFIX "_${${PROJECT_NAME}_ABI_VERSION}") endif() endif() set(${OUTPUT_NAME} ${TARGET_NAME}${SUFFIX} PARENT_SCOPE) endfunction() soci-3.2.3/cmake/SociDependencies.cmake0000644000000000000000000000447112511362240016442 0ustar rootroot################################################################################ # SociDependencies.cmake - part of CMake configuration of SOCI library # # Based on BoostExternals.cmake from CMake configuration for Boost ################################################################################ # Copyright (C) 2010 Mateusz Loskot # Copyright (C) 2009 Troy Straszheim # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) ################################################################################ # Macros in this module: # # soci_backend - defines a database backend for SOCI library # ################################################################################ # # List of SOCI dependncies # set(SOCI_BACKENDS_DB_DEPENDENCIES MySQL ODBC Oracle PostgreSQL SQLite3 Firebird DB2) set(SOCI_BACKENDS_ALL_DEPENDENCIES Boost ${SOCI_BACKENDS_DB_DEPENDENCIES}) # # Perform checks # colormsg(_HIBLUE_ "Looking for SOCI dependencies:") macro(boost_external_report NAME) set(VARNAME ${NAME}) set(SUCCESS ${${VARNAME}_FOUND}) set(VARNAMES ${ARGV}) list(REMOVE_AT VARNAMES 0) # Test both, given original name and uppercase version too if(NOT SUCCESS) string(TOUPPER ${NAME} VARNAME) set(SUCCESS ${${VARNAME}_FOUND}) if(NOT SUCCESS) colormsg(_RED_ "WARNING:") colormsg(RED "${NAME} not found, some libraries or features will be disabled.") colormsg(RED "See the documentation for ${NAME} or manually set these variables:") endif() endif() foreach(variable ${VARNAMES}) boost_report_value(${VARNAME}_${variable}) endforeach() endmacro() # # Some externals default to OFF # option(WITH_VALGRIND "Run tests under valgrind" OFF) # # Detect available dependencies # foreach(external ${SOCI_BACKENDS_ALL_DEPENDENCIES}) string(TOUPPER "${external}" EXTERNAL) option(WITH_${EXTERNAL} "Attempt to find and configure ${external}" ON) if(WITH_${EXTERNAL}) colormsg(HICYAN "${external}:") include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/dependencies/${external}.cmake) else() set(${EXTERNAL}_FOUND FALSE CACHE BOOL "${external} found" FORCE) colormsg(HIRED "${external}:" RED "disabled, since WITH_${EXTERNAL}=OFF") endif() endforeach() soci-3.2.3/cmake/SociConfig.cmake0000644000000000000000000000353312511362240015257 0ustar rootroot################################################################################ # SociConfig.cmake - CMake build configuration of SOCI library ################################################################################ # Copyright (C) 2010 Mateusz Loskot # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) ################################################################################ # # Force compilation flags and set desired warnings level # if (MSVC) if (MSVC80 OR MSVC90 OR MSVC10) add_definitions(-D_CRT_SECURE_NO_DEPRECATE) add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_CRT_NONSTDC_NO_WARNING) add_definitions(-D_SCL_SECURE_NO_WARNINGS) endif() if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") endif() else() set(SOCI_GCC_CLANG_COMMON_FLAGS "-pedantic -ansi -Wall -Wpointer-arith -Wcast-align -Wcast-qual -Wfloat-equal -Wredundant-decls -Wno-long-long") if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC ${SOCI_GCC_CLANG_COMMON_FLAGS}") if (CMAKE_COMPILER_IS_GNUCXX) if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++98") else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98") endif() endif() elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_CXX_COMPILER}" MATCHES "clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SOCI_GCC_CLANG_COMMON_FLAGS}") else() message(FATAL_ERROR "CMake is unable to recognize compilation toolset to build SOCI for you!") endif() endif() soci-3.2.3/cmake/.gitignore0000644000000000000000000000027712511362240014224 0ustar rootroot*~ *.kdev[0-9] *.swp aclocal.m4 autom4te.cache confdefs.h config.guess config.log config.status config.sub configure depcomp install-sh libtool ltmain.sh m4 missing Makefile Makefile.in tmp soci-3.2.3/cmake/SociSystemInfo.cmake0000644000000000000000000000525712511362240016157 0ustar rootroot################################################################################ # SociSystemInfo.cmake - part of CMake configuration of SOCI library # # Based on idea taken from http://code.google.com/p/softart/ project ################################################################################ # Copyright (C) 2010 Mateusz Loskot # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) ################################################################################ # The following variables are defined: # SOCI_COMPILER_NAME - name of compiler toolset, follows Boost toolset naming. # SOCI_PLATFORM_NAME - target platform name: x64, x86 or win32 # # Based on the Pre-defined Compiler Macros # http://sourceforge.net/p/predef/wiki/Compilers/ ################################################################################ set(SOCI_COMPILER_NAME) set(SOCI_PLATFORM_NAME) if(MINGW OR UNIX) exec_program(${CMAKE_C_COMPILER} ARGS -dumpversion OUTPUT_VARIABLE GCC_VERSION) string(REPLACE "." "" GCC_VERSION_STR_FULL ${GCC_VERSION}) string(REGEX MATCH "[0-9]+\\.[0-9]+" GCC_VERSION_MAJOR_MINOR ${GCC_VERSION}) endif() if(WIN32) if(MSVC) if(MSVC_VERSION EQUAL 1200) set(SOCI_COMPILER_NAME "msvc-6.0") endif() if(MSVC_VERSION EQUAL 1300) set(SOCI_COMPILER_NAME "msvc-7.0") endif() if(MSVC_VERSION EQUAL 1310) set(SOCI_COMPILER_NAME "msvc-7.1") # Visual Studio 2003 endif() if(MSVC_VERSION EQUAL 1400) set(SOCI_COMPILER_NAME "msvc-8.0") # Visual Studio 2005 endif() if(MSVC_VERSION EQUAL 1500) set(SOCI_COMPILER_NAME "msvc-9.0") # Visual Studio 2008 endif() if(MSVC_VERSION EQUAL 1600) set(SOCI_COMPILER_NAME "msvc-10.0") # Visual Studio 2010 endif() if(MSVC_VERSION EQUAL 1700) set(SOCI_COMPILER_NAME "msvc-11.0") # Visual Studio 2012 endif() endif(MSVC) if(MINGW) set(SOCI_COMPILER_NAME "mingw-${GCC_VERSION}") endif( MINGW ) if(CMAKE_GENERATOR MATCHES "Win64") set(SOCI_PLATFORM_NAME "x64") else() set(SOCI_PLATFORM_NAME "win32") endif() endif(WIN32) if(UNIX) set(SOCI_COMPILER_NAME "gcc-${GCC_VERSION}") if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") set(SOCI_PLATFORM_NAME "x64") else() set(SOCI_PLATFORM_NAME "x86") endif() endif(UNIX) if(NOT SOCI_COMPILER_NAME) colormsg(_RED_ "WARNING:") colormsg(RED "Could not determine compiler toolset name to set SOCI_COMPILER_NAME variable.") endif() if(NOT SOCI_PLATFORM_NAME) colormsg(_RED_ "WARNING:") colormsg(RED "Could not determine platform name to set SOCI_PLATFORM_NAME variable.") endif() soci-3.2.3/cmake/SociBackend.cmake0000644000000000000000000002635212511362240015405 0ustar rootroot################################################################################ # SociBackend.cmake - part of CMake configuration of SOCI library ################################################################################ # Copyright (C) 2010 Mateusz Loskot # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) ################################################################################ # Macros in this module: # # soci_backend # - defines project of a database backend for SOCI library # # soci_backend_test # - defines test project of a database backend for SOCI library ################################################################################ # Defines project of a database backend for SOCI library # # soci_backend(backendname # HEADERS header1 header2 # DEPENDS dependency1 dependency2 # DESCRIPTION description # AUTHORS author1 author2 # MAINTAINERS maintainer1 maintainer2) # macro(soci_backend NAME) parse_arguments(THIS_BACKEND "HEADERS;DEPENDS;DESCRIPTION;AUTHORS;MAINTAINERS;" "" ${ARGN}) colormsg(HIGREEN "${NAME} - ${THIS_BACKEND_DESCRIPTION}") # Backend name variants utils string(TOLOWER "${PROJECT_NAME}" PROJECTNAMEL) string(TOLOWER "${NAME}" NAMEL) string(TOUPPER "${NAME}" NAMEU) # Backend option available to user set(THIS_BACKEND_OPTION SOCI_${NAMEU}) option(${THIS_BACKEND_OPTION} "Attempt to build ${PROJECT_NAME} backend for ${NAME}" ON) # Determine required dependencies set(THIS_BACKEND_DEPENDS_INCLUDE_DIRS) set(THIS_BACKEND_DEPENDS_LIBRARIES) set(THIS_BACKEND_DEPENDS_DEFS) set(DEPENDS_NOT_FOUND) # CMake 2.8+ syntax only: #foreach(dep IN LISTS THIS_BACKEND_DEPENDS) foreach(dep ${THIS_BACKEND_DEPENDS}) soci_check_package_found(${dep} DEPEND_FOUND) if(NOT DEPEND_FOUND) list(APPEND DEPENDS_NOT_FOUND ${dep}) else() string(TOUPPER "${dep}" DEPU) list(APPEND THIS_BACKEND_DEPENDS_INCLUDE_DIRS ${${DEPU}_INCLUDE_DIR}) list(APPEND THIS_BACKEND_DEPENDS_INCLUDE_DIRS ${${DEPU}_INCLUDE_DIRS}) list(APPEND THIS_BACKEND_DEPENDS_LIBRARIES ${${DEPU}_LIBRARIES}) list(APPEND THIS_BACKEND_DEPENDS_DEFS -DHAVE_${DEPU}=1) endif() endforeach() list(LENGTH DEPENDS_NOT_FOUND NOT_FOUND_COUNT) if (NOT_FOUND_COUNT GREATER 0) colormsg(_RED_ "WARNING:") colormsg(RED "Some required dependencies of ${NAME} backend not found:") if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} LESS 2.8) foreach(dep ${DEPENDS_NOT_FOUND}) colormsg(RED " ${dep}") endforeach() else() foreach(dep IN LISTS DEPENDS_NOT_FOUND) colormsg(RED " ${dep}") endforeach() endif() # TODO: Abort or warn compilation may fail? --mloskot colormsg(RED "Skipping") set(${THIS_BACKEND_OPTION} OFF) else(NOT_FOUND_COUNT GREATER 0) if(${THIS_BACKEND_OPTION}) # Backend-specific include directories list(APPEND THIS_BACKEND_DEPENDS_INCLUDE_DIRS ${SOCI_SOURCE_DIR}/core) set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES "${THIS_BACKEND_DEPENDS_INCLUDE_DIRS}") # Backend-specific preprocessor definitions add_definitions(${THIS_BACKEND_DEPENDS_DEFS}) # Backend installable headers and sources if (NOT THIS_BACKEND_HEADERS) file(GLOB THIS_BACKEND_HEADERS *.h) endif() file(GLOB THIS_BACKEND_SOURCES *.cpp) set(THIS_BACKEND_HEADERS_VAR SOCI_${NAMEU}_HEADERS) set(${THIS_BACKEND_HEADERS_VAR} ${THIS_BACKEND_HEADERS}) # Group source files for IDE source explorers (e.g. Visual Studio) source_group("Header Files" FILES ${THIS_BACKEND_HEADERS}) source_group("Source Files" FILES ${THIS_BACKEND_SOURCES}) source_group("CMake Files" FILES CMakeLists.txt) # Backend target set(THIS_BACKEND_TARGET ${PROJECTNAMEL}_${NAMEL}) set(THIS_BACKEND_TARGET_VAR SOCI_${NAMEU}_TARGET) set(${THIS_BACKEND_TARGET_VAR} ${THIS_BACKEND_TARGET}) soci_target_output_name(${THIS_BACKEND_TARGET} ${THIS_BACKEND_TARGET_VAR}_OUTPUT_NAME) set(THIS_BACKEND_TARGET_OUTPUT_NAME ${${THIS_BACKEND_TARGET_VAR}_OUTPUT_NAME}) set(THIS_BACKEND_TARGET_OUTPUT_NAME_VAR ${THIS_BACKEND_TARGET_VAR}_OUTPUT_NAME) # TODO: Extract as macros: soci_shared_lib_target and soci_static_lib_target --mloskot # Shared library target if (SOCI_SHARED) add_library(${THIS_BACKEND_TARGET} SHARED ${THIS_BACKEND_SOURCES} ${THIS_BACKEND_HEADERS}) target_link_libraries(${THIS_BACKEND_TARGET} ${SOCI_CORE_TARGET} ${THIS_BACKEND_DEPENDS_LIBRARIES}) if(WIN32) set_target_properties(${THIS_BACKEND_TARGET} PROPERTIES OUTPUT_NAME ${THIS_BACKEND_TARGET_OUTPUT_NAME} DEFINE_SYMBOL SOCI_DLL) else() set_target_properties(${THIS_BACKEND_TARGET} PROPERTIES SOVERSION ${${PROJECT_NAME}_SOVERSION} INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib) endif() set_target_properties(${THIS_BACKEND_TARGET} PROPERTIES VERSION ${${PROJECT_NAME}_VERSION} CLEAN_DIRECT_OUTPUT 1) endif() # Static library target if (SOCI_STATIC) set(THIS_BACKEND_TARGET_STATIC ${THIS_BACKEND_TARGET}_static) add_library(${THIS_BACKEND_TARGET_STATIC} STATIC ${THIS_BACKEND_SOURCES} ${THIS_BACKEND_HEADERS}) set_target_properties(${THIS_BACKEND_TARGET_STATIC} PROPERTIES OUTPUT_NAME ${THIS_BACKEND_TARGET_OUTPUT_NAME} PREFIX "lib" CLEAN_DIRECT_OUTPUT 1) endif() # Backend installation install(FILES ${THIS_BACKEND_HEADERS} DESTINATION ${INCLUDEDIR}/${PROJECTNAMEL}/${NAMEL}) if (SOCI_SHARED) install(TARGETS ${THIS_BACKEND_TARGET} RUNTIME DESTINATION ${BINDIR} LIBRARY DESTINATION ${LIBDIR} ARCHIVE DESTINATION ${LIBDIR}) endif() if (SOCI_SHARED) install(TARGETS ${THIS_BACKEND_TARGET_STATIC} RUNTIME DESTINATION ${BINDIR} LIBRARY DESTINATION ${LIBDIR} ARCHIVE DESTINATION ${LIBDIR}) endif() else() colormsg(HIRED "${NAME}" RED "backend disabled, since") endif() endif(NOT_FOUND_COUNT GREATER 0) boost_report_value(${THIS_BACKEND_OPTION}) if(${THIS_BACKEND_OPTION}) boost_report_value(${THIS_BACKEND_TARGET_VAR}) boost_report_value(${THIS_BACKEND_TARGET_OUTPUT_NAME_VAR}) boost_report_value(${THIS_BACKEND_HEADERS_VAR}) soci_report_directory_property(COMPILE_DEFINITIONS) endif() # LOG #message("soci_backend:") #message("NAME: ${NAME}") #message("${THIS_BACKEND_OPTION} = ${SOCI_BACKEND_SQLITE3}") #message("DEPENDS: ${THIS_BACKEND_DEPENDS}") #message("DESCRIPTION: ${THIS_BACKEND_DESCRIPTION}") #message("AUTHORS: ${THIS_BACKEND_AUTHORS}") #message("MAINTAINERS: ${THIS_BACKEND_MAINTAINERS}") #message("HEADERS: ${THIS_BACKEND_HEADERS}") #message("SOURCES: ${THIS_BACKEND_SOURCES}") #message("DEPENDS_LIBRARIES: ${THIS_BACKEND_DEPENDS_LIBRARIES}") #message("DEPENDS_INCLUDE_DIRS: ${THIS_BACKEND_DEPENDS_INCLUDE_DIRS}") endmacro() # Generates .vcxproj.user for target of each test. # # soci_backend_test_create_vcxproj_user( # PostgreSQLTest # "host=localhost dbname=soci_test user=mloskot") # function(soci_backend_test_create_vcxproj_user TARGET_NAME TEST_CMD_ARGS) if(MSVC) set(SYSTEM_NAME $ENV{USERDOMAIN}) set(USER_NAME $ENV{USERNAME}) set(SOCI_TEST_CMD_ARGS ${TEST_CMD_ARGS}) if(MSVC_VERSION EQUAL 1600) configure_file( ${SOCI_SOURCE_DIR}/cmake/resources/vs2010-test-cmd-args.vcxproj.user.in ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.vcxproj.user @ONLY) endif() endif() endfunction(soci_backend_test_create_vcxproj_user) # Defines test project of a database backend for SOCI library # # soci_backend_test(BACKEND mybackend SOURCE mytest1.cpp # NAME mytest1 # CONNSTR "my test connection" # DEPENDS library1 library2) # macro(soci_backend_test) parse_arguments(THIS_TEST "BACKEND;SOURCE;CONNSTR;NAME;DEPENDS;" "" ${ARGN}) # Test backend name string(TOUPPER "${THIS_TEST_BACKEND}" BACKENDU) string(TOLOWER "${THIS_TEST_BACKEND}" BACKENDL) if(SOCI_TESTS AND SOCI_${BACKENDU} AND NOT SOCI_${BACKENDU}_DO_NOT_TEST) # Test name if(THIS_TEST_NAME) string(TOUPPER "${THIS_TEST_NAME}" NAMEU) set(TEST_FULL_NAME SOCI_${BACKENDU}_TEST_${NAMEU}) else() set(TEST_FULL_NAME SOCI_${BACKENDU}_TEST) endif() set(TEST_CONNSTR_VAR ${TEST_FULL_NAME}_CONNSTR) set(${TEST_CONNSTR_VAR} "" CACHE STRING "Connection string for ${BACKENDU} test") if(NOT ${TEST_CONNSTR_VAR} AND THIS_TEST_CONNSTR) set(${TEST_CONNSTR_VAR} ${THIS_TEST_CONNSTR}) endif() boost_report_value(${TEST_CONNSTR_VAR}) include_directories(${SOCI_SOURCE_DIR}/core/test) include_directories(${SOCI_SOURCE_DIR}/backends/${BACKENDL}) # TODO: Find more generic way of adding Boost to core and backend tests only. # Ideally, from within Boost.cmake. set(SOCI_TEST_DEPENDENCIES) if(Boost_FOUND) include_directories(${Boost_INCLUDE_DIRS}) if(Boost_DATE_TIME_FOUND) set(SOCI_TEST_DEPENDENCIES ${Boost_DATE_TIME_LIBRARY}) add_definitions(-DHAVE_BOOST_DATE_TIME=1) endif() endif() string(TOLOWER "${TEST_FULL_NAME}" TEST_TARGET) set(TEST_HEADERS ${PROJECT_SOURCE_DIR}/core/test/common-tests.h) # Shared libraries test add_executable(${TEST_TARGET} ${TEST_HEADERS} ${THIS_TEST_SOURCE}) target_link_libraries(${TEST_TARGET} ${SOCI_CORE_TARGET} ${SOCI_${BACKENDU}_TARGET} ${${BACKENDU}_LIBRARIES} ${SOCI_TEST_DEPENDENCIES}) add_test(${TEST_TARGET} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TEST_TARGET} ${${TEST_CONNSTR_VAR}}) soci_backend_test_create_vcxproj_user(${TEST_TARGET} "\"${${TEST_CONNSTR_VAR}}\"") # Static libraries test if(SOCI_STATIC) set(TEST_TARGET_STATIC ${TEST_TARGET}_static) add_executable(${TEST_TARGET_STATIC} ${TEST_HEADERS} ${THIS_TEST_SOURCE}) target_link_libraries(${TEST_TARGET_STATIC} ${SOCI_CORE_TARGET_STATIC} ${SOCI_${BACKENDU}_TARGET}_static ${${BACKENDU}_LIBRARIES} ${SOCI_CORE_STATIC_DEPENDENCIES} ${SOCI_TEST_DEPENDENCIES}) add_test(${TEST_TARGET_STATIC} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TEST_TARGET_STATIC} ${${TEST_CONNSTR_VAR}}) soci_backend_test_create_vcxproj_user(${TEST_TARGET_STATIC} "\"${${TEST_CONNSTR_VAR}}\"") endif(SOCI_STATIC) # Ask make check to try to build tests first before executing them add_dependencies(check ${TEST_TARGET} ${TEST_TARGET_STATIC}) # Group source files for IDE source explorers (e.g. Visual Studio) source_group("Header Files" FILES ${TEST_HEADERS}) source_group("Source Files" FILES ${THIS_TEST_SOURCE}) source_group("CMake Files" FILES CMakeLists.txt) endif() # LOG #message("NAME=${NAME}") #message("THIS_TEST_NAME=${THIS_TEST_NAME}") #message("THIS_TEST_BACKEND=${THIS_TEST_BACKEND}") #message("THIS_TEST_CONNSTR=${THIS_TEST_CONNSTR}") #message("THIS_TEST_SOURCE=${THIS_TEST_SOURCE}") #message("THIS_TEST_OPTION=${THIS_TEST_OPTION}") endmacro() soci-3.2.3/cmake/SociVersion.cmake0000644000000000000000000000424212511362240015475 0ustar rootroot################################################################################ # SociVersion.cmake - part of CMake configuration of SOCI library ################################################################################ # Copyright (C) 2010 Mateusz Loskot # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) ################################################################################ # Macros in this module: # # soci_version - defines version information for SOCI library # ################################################################################ # Defines version information for SOCI library # # soci_version(MAJOR major_version MINOR minor_version PATCH patch_level) # # MAJOR.MINOR version is used to set SOVERSION # macro(soci_version) parse_arguments(THIS_VERSION "MAJOR;MINOR;PATCH;" "" ${ARGN}) # Set version components set(${PROJECT_NAME}_VERSION_MAJOR ${THIS_VERSION_MAJOR}) set(${PROJECT_NAME}_VERSION_MINOR ${THIS_VERSION_MINOR}) set(${PROJECT_NAME}_VERSION_PATCH ${THIS_VERSION_PATCH}) # Set VERSION string set(${PROJECT_NAME}_VERSION "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}") # Set SOVERSION based on major and minor set(${PROJECT_NAME}_SOVERSION "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}") # Set ABI version string used to name binary output and, by SOCI loader, to find binaries. # On Windows, ABI version is specified using binary file name suffix. # On Unix, suffix ix empty and SOVERSION is used instead. if (UNIX) set(${PROJECT_NAME}_ABI_VERSION ${${PROJECT_NAME}_SOVERSION}) elseif(WIN32) set(${PROJECT_NAME}_ABI_VERSION "${${PROJECT_NAME}_VERSION_MAJOR}_${${PROJECT_NAME}_VERSION_MINOR}") else() message(FATAL_ERROR "Ambiguous target platform with unknown ABI version scheme. Giving up.") endif() boost_report_value(${PROJECT_NAME}_VERSION) boost_report_value(${PROJECT_NAME}_ABI_VERSION) add_definitions(-DSOCI_ABI_VERSION="${${PROJECT_NAME}_ABI_VERSION}") endmacro() soci-3.2.3/cmake/CMakeLists.txt0000644000000000000000000000077612511362240015000 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2009 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### # install the cmake modules file(GLOB SOCI_CMAKE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.cmake") soci-3.2.3/cmake/dependencies/0000755000000000000000000000000012511362240014654 5ustar rootrootsoci-3.2.3/cmake/dependencies/SQLite3.cmake0000644000000000000000000000015412511362240017102 0ustar rootrootset(SQLITE3_FIND_QUIETLY TRUE) find_package(SQLite3) boost_external_report(SQLite3 INCLUDE_DIR LIBRARIES) soci-3.2.3/cmake/dependencies/Threads.cmake0000644000000000000000000000020512511362240017245 0ustar rootrootset(Threads_FIND_QUIETLY TRUE) find_package(Threads) message(STATUS "X: ${Threads_FOUND}") boost_external_report(Threads LIBRARIES) soci-3.2.3/cmake/dependencies/PostgreSQL.cmake0000644000000000000000000000017412511362240017663 0ustar rootrootset(PostgreSQL_FIND_QUIETLY TRUE) find_package(PostgreSQL) boost_external_report(PostgreSQL INCLUDE_DIR LIBRARIES VERSION)soci-3.2.3/cmake/dependencies/MySQL.cmake0000644000000000000000000000031612511362240016623 0ustar rootrootset(MySQL_FIND_QUIETLY TRUE) find_package(MySQL) boost_external_report(MySQL INCLUDE_DIR LIBRARIES) #if(MYSQL_FOUND) # include_directories(${MYSQL_INCLUDE_DIR}) # add_definitions(-DHAVE_MYSQL) #endif()soci-3.2.3/cmake/dependencies/Boost.cmake0000644000000000000000000000057512511362240016753 0ustar rootrootset(Boost_FIND_QUIETLY TRUE) set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) find_package(Boost 1.33.1 COMPONENTS date_time) if (NOT Boost_date_time_FOUND) find_package(Boost 1.33.1) endif() set(Boost_RELEASE_VERSION "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") boost_external_report(Boost RELEASE_VERSION INCLUDE_DIR LIBRARIES) soci-3.2.3/cmake/dependencies/Firebird.cmake0000644000000000000000000000017012511362240017402 0ustar rootrootset(Firebird_FIND_QUIETLY TRUE) find_package(Firebird) boost_external_report(Firebird INCLUDE_DIR LIBRARIES VERSION) soci-3.2.3/cmake/dependencies/ODBC.cmake0000644000000000000000000000014312511362240016363 0ustar rootrootset(ODBC_FIND_QUIETLY TRUE) find_package(ODBC) boost_external_report(ODBC INCLUDE_DIR LIBRARIES) soci-3.2.3/cmake/dependencies/Oracle.cmake0000644000000000000000000000015112511362240017060 0ustar rootrootset(ORACLE_FIND_QUIETLY TRUE) find_package(Oracle) boost_external_report(Oracle INCLUDE_DIR LIBRARIES) soci-3.2.3/cmake/dependencies/DB2.cmake0000644000000000000000000000014012511362240016220 0ustar rootrootset(DB2_FIND_QUIETLY TRUE) find_package(DB2) boost_external_report(DB2 INCLUDE_DIR LIBRARIES) soci-3.2.3/backends/0000755000000000000000000000000012511362240012720 5ustar rootrootsoci-3.2.3/backends/oracle/0000755000000000000000000000000012511362240014165 5ustar rootrootsoci-3.2.3/backends/oracle/error.h0000644000000000000000000000113312511361676015501 0ustar rootroot// // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_ORACLE_ERROR_H_INCLUDED #define SOCI_ORACLE_ERROR_H_INCLUDED #include "soci-oracle.h" namespace soci { namespace details { namespace oracle { void throw_oracle_soci_error(sword res, OCIError *errhp); void get_error_details(sword res, OCIError *errhp, std::string &msg, int &errNum); } // namespace oracle } // namespace details } // namespace soci #endif soci-3.2.3/backends/oracle/blob.cpp0000644000000000000000000000546012511361676015630 0ustar rootroot// // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci-oracle.h" #include "error.h" #include "statement.h" #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace soci::details::oracle; oracle_blob_backend::oracle_blob_backend(oracle_session_backend &session) : session_(session) { sword res = OCIDescriptorAlloc(session.envhp_, reinterpret_cast(&lobp_), OCI_DTYPE_LOB, 0, 0); if (res != OCI_SUCCESS) { throw soci_error("Cannot allocate the LOB locator"); } } oracle_blob_backend::~oracle_blob_backend() { OCIDescriptorFree(lobp_, OCI_DTYPE_LOB); } std::size_t oracle_blob_backend::get_len() { ub4 len; sword res = OCILobGetLength(session_.svchp_, session_.errhp_, lobp_, &len); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } return static_cast(len); } std::size_t oracle_blob_backend::read( std::size_t offset, char *buf, std::size_t toRead) { ub4 amt = static_cast(toRead); sword res = OCILobRead(session_.svchp_, session_.errhp_, lobp_, &amt, static_cast(offset), reinterpret_cast(buf), amt, 0, 0, 0, 0); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } return static_cast(amt); } std::size_t oracle_blob_backend::write( std::size_t offset, char const *buf, std::size_t toWrite) { ub4 amt = static_cast(toWrite); sword res = OCILobWrite(session_.svchp_, session_.errhp_, lobp_, &amt, static_cast(offset), reinterpret_cast(const_cast(buf)), amt, OCI_ONE_PIECE, 0, 0, 0, 0); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } return static_cast(amt); } std::size_t oracle_blob_backend::append(char const *buf, std::size_t toWrite) { ub4 amt = static_cast(toWrite); sword res = OCILobWriteAppend(session_.svchp_, session_.errhp_, lobp_, &amt, reinterpret_cast(const_cast(buf)), amt, OCI_ONE_PIECE, 0, 0, 0, 0); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } return static_cast(amt); } void oracle_blob_backend::trim(std::size_t newLen) { sword res = OCILobTrim(session_.svchp_, session_.errhp_, lobp_, static_cast(newLen)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } } soci-3.2.3/backends/oracle/statement.cpp0000644000000000000000000002147012511361676016715 0ustar rootroot// // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define soci_ORACLE_SOURCE #include "soci-oracle.h" #include "error.h" #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace soci::details::oracle; oracle_statement_backend::oracle_statement_backend(oracle_session_backend &session) : session_(session), stmtp_(NULL), boundByName_(false), boundByPos_(false), noData_(false) { } void oracle_statement_backend::alloc() { sword res = OCIHandleAlloc(session_.envhp_, reinterpret_cast(&stmtp_), OCI_HTYPE_STMT, 0, 0); if (res != OCI_SUCCESS) { throw soci_error("Cannot allocate statement handle"); } } void oracle_statement_backend::clean_up() { // deallocate statement handle if (stmtp_ != NULL) { OCIHandleFree(stmtp_, OCI_HTYPE_STMT); stmtp_ = NULL; } boundByName_ = false; boundByPos_ = false; } void oracle_statement_backend::prepare(std::string const &query, statement_type /* eType */) { sb4 stmtLen = static_cast(query.size()); sword res = OCIStmtPrepare(stmtp_, session_.errhp_, reinterpret_cast(const_cast(query.c_str())), stmtLen, OCI_V7_SYNTAX, OCI_DEFAULT); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } } statement_backend::exec_fetch_result oracle_statement_backend::execute(int number) { sword res = OCIStmtExecute(session_.svchp_, stmtp_, session_.errhp_, static_cast(number), 0, 0, 0, OCI_DEFAULT); if (res == OCI_SUCCESS || res == OCI_SUCCESS_WITH_INFO) { noData_ = false; return ef_success; } else if (res == OCI_NO_DATA) { noData_ = true; return ef_no_data; } else { throw_oracle_soci_error(res, session_.errhp_); return ef_no_data; // unreachable dummy return to please the compiler } } statement_backend::exec_fetch_result oracle_statement_backend::fetch(int number) { if (noData_) { return ef_no_data; } sword res = OCIStmtFetch(stmtp_, session_.errhp_, static_cast(number), OCI_FETCH_NEXT, OCI_DEFAULT); if (res == OCI_SUCCESS || res == OCI_SUCCESS_WITH_INFO) { return ef_success; } else if (res == OCI_NO_DATA) { noData_ = true; return ef_no_data; } else { throw_oracle_soci_error(res, session_.errhp_); return ef_no_data; // unreachable dummy return to please the compiler } } long long oracle_statement_backend::get_affected_rows() { ub4 row_count; sword res = OCIAttrGet(static_cast(stmtp_), OCI_HTYPE_STMT, &row_count, 0, OCI_ATTR_ROW_COUNT, session_.errhp_); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } return row_count; } int oracle_statement_backend::get_number_of_rows() { int rows; sword res = OCIAttrGet(static_cast(stmtp_), OCI_HTYPE_STMT, static_cast(&rows), 0, OCI_ATTR_ROWS_FETCHED, session_.errhp_); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } return rows; } std::string oracle_statement_backend::rewrite_for_procedure_call( std::string const &query) { std::string newQuery("begin "); newQuery += query; newQuery += "; end;"; return newQuery; } int oracle_statement_backend::prepare_for_describe() { sword res = OCIStmtExecute(session_.svchp_, stmtp_, session_.errhp_, 1, 0, 0, 0, OCI_DESCRIBE_ONLY); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } int cols; res = OCIAttrGet(static_cast(stmtp_), static_cast(OCI_HTYPE_STMT), static_cast(&cols), 0, static_cast(OCI_ATTR_PARAM_COUNT), session_.errhp_); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } return cols; } void oracle_statement_backend::describe_column(int colNum, data_type &type, std::string &columnName) { int size; int precision; int scale; ub2 dbtype; text* dbname; ub4 nameLength; ub2 dbsize; sb2 dbprec; ub1 dbscale; //sb2 in some versions of Oracle? // Get the column handle OCIParam* colhd; sword res = OCIParamGet(reinterpret_cast(stmtp_), static_cast(OCI_HTYPE_STMT), reinterpret_cast(session_.errhp_), reinterpret_cast(&colhd), static_cast(colNum)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // Get the column name res = OCIAttrGet(reinterpret_cast(colhd), static_cast(OCI_DTYPE_PARAM), reinterpret_cast(&dbname), reinterpret_cast(&nameLength), static_cast(OCI_ATTR_NAME), reinterpret_cast(session_.errhp_)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // Get the column type res = OCIAttrGet(reinterpret_cast(colhd), static_cast(OCI_DTYPE_PARAM), reinterpret_cast(&dbtype), 0, static_cast(OCI_ATTR_DATA_TYPE), reinterpret_cast(session_.errhp_)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // get the data size res = OCIAttrGet(reinterpret_cast(colhd), static_cast(OCI_DTYPE_PARAM), reinterpret_cast(&dbsize), 0, static_cast(OCI_ATTR_DATA_SIZE), reinterpret_cast(session_.errhp_)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // get the precision res = OCIAttrGet(reinterpret_cast(colhd), static_cast(OCI_DTYPE_PARAM), reinterpret_cast(&dbprec), 0, static_cast(OCI_ATTR_PRECISION), reinterpret_cast(session_.errhp_)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // get the scale res = OCIAttrGet(reinterpret_cast(colhd), static_cast(OCI_DTYPE_PARAM), reinterpret_cast(&dbscale), 0, static_cast(OCI_ATTR_SCALE), reinterpret_cast(session_.errhp_)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } columnName.assign(dbname, dbname + nameLength); size = static_cast(dbsize); precision = static_cast(dbprec); scale = static_cast(dbscale); switch (dbtype) { case SQLT_CHR: case SQLT_AFC: type = dt_string; break; case SQLT_NUM: if (scale > 0) { if (session_.get_option_decimals_as_strings()) type = dt_string; else type = dt_double; } else if (precision <= std::numeric_limits::digits10) { type = dt_integer; } else { type = dt_long_long; } break; case SQLT_DAT: type = dt_date; break; } } std::size_t oracle_statement_backend::column_size(int position) { // Note: we may want to optimize so that the OCI_DESCRIBE_ONLY call // happens only once per statement. // Possibly use existing statement::describe() / make column prop // access lazy at same time int colSize(0); sword res = OCIStmtExecute(session_.svchp_, stmtp_, session_.errhp_, 1, 0, 0, 0, OCI_DESCRIBE_ONLY); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // Get The Column Handle OCIParam* colhd; res = OCIParamGet(reinterpret_cast(stmtp_), static_cast(OCI_HTYPE_STMT), reinterpret_cast(session_.errhp_), reinterpret_cast(&colhd), static_cast(position)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // Get The Data Size res = OCIAttrGet(reinterpret_cast(colhd), static_cast(OCI_DTYPE_PARAM), reinterpret_cast(&colSize), 0, static_cast(OCI_ATTR_DATA_SIZE), reinterpret_cast(session_.errhp_)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } return static_cast(colSize); } soci-3.2.3/backends/oracle/vector-use-type.cpp0000644000000000000000000002555612511361676017775 0ustar rootroot// // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define soci_ORACLE_SOURCE #include "soci-oracle.h" #include "error.h" #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #define snprintf _snprintf #endif using namespace soci; using namespace soci::details; using namespace soci::details::oracle; void oracle_vector_use_type_backend::prepare_indicators(std::size_t size) { if (size == 0) { throw soci_error("Vectors of size 0 are not allowed."); } indOCIHolderVec_.resize(size); indOCIHolders_ = &indOCIHolderVec_[0]; } void oracle_vector_use_type_backend::prepare_for_bind( void *&data, sb4 &size, ub2 &oracleType) { switch (type_) { // simple cases case x_char: { oracleType = SQLT_AFC; size = sizeof(char); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_short: { oracleType = SQLT_INT; size = sizeof(short); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_integer: { oracleType = SQLT_INT; size = sizeof(int); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_double: { oracleType = SQLT_FLT; size = sizeof(double); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; // cases that require adjustments and buffer management case x_long_long: { std::vector *vp = static_cast *>(data); std::vector &v(*vp); std::size_t const vecSize = v.size(); std::size_t const entrySize = 100; // arbitrary std::size_t const bufSize = entrySize * vecSize; buf_ = new char[bufSize]; oracleType = SQLT_STR; data = buf_; size = entrySize; prepare_indicators(vecSize); } break; case x_unsigned_long_long: { std::vector *vp = static_cast *>(data); std::vector &v(*vp); std::size_t const vecSize = v.size(); std::size_t const entrySize = 100; // arbitrary std::size_t const bufSize = entrySize * vecSize; buf_ = new char[bufSize]; oracleType = SQLT_STR; data = buf_; size = entrySize; prepare_indicators(vecSize); } break; case x_stdstring: { std::vector *vp = static_cast *>(data); std::vector &v(*vp); std::size_t maxSize = 0; std::size_t const vecSize = v.size(); prepare_indicators(vecSize); for (std::size_t i = 0; i != vecSize; ++i) { std::size_t sz = v[i].length(); sizes_.push_back(static_cast(sz)); maxSize = sz > maxSize ? sz : maxSize; } buf_ = new char[maxSize * vecSize]; char *pos = buf_; for (std::size_t i = 0; i != vecSize; ++i) { strncpy(pos, v[i].c_str(), v[i].length()); pos += maxSize; } oracleType = SQLT_CHR; data = buf_; size = static_cast(maxSize); } break; case x_stdtm: { std::vector *vp = static_cast *>(data); prepare_indicators(vp->size()); sb4 const dlen = 7; // size of SQLT_DAT buf_ = new char[dlen * vp->size()]; oracleType = SQLT_DAT; data = buf_; size = dlen; } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } } void oracle_vector_use_type_backend::bind_by_pos(int &position, void *data, exchange_type type) { data_ = data; // for future reference type_ = type; // for future reference ub2 oracleType; sb4 size; prepare_for_bind(data, size, oracleType); ub2 *sizesP = 0; // used only for std::string if (type == x_stdstring) { sizesP = &sizes_[0]; } sword res = OCIBindByPos(statement_.stmtp_, &bindp_, statement_.session_.errhp_, position++, data, size, oracleType, indOCIHolders_, sizesP, 0, 0, 0, OCI_DEFAULT); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, statement_.session_.errhp_); } } void oracle_vector_use_type_backend::bind_by_name( std::string const &name, void *data, exchange_type type) { data_ = data; // for future reference type_ = type; // for future reference ub2 oracleType; sb4 size; prepare_for_bind(data, size, oracleType); ub2 *sizesP = 0; // used only for std::string if (type == x_stdstring) { sizesP = &sizes_[0]; } sword res = OCIBindByName(statement_.stmtp_, &bindp_, statement_.session_.errhp_, reinterpret_cast(const_cast(name.c_str())), static_cast(name.size()), data, size, oracleType, indOCIHolders_, sizesP, 0, 0, 0, OCI_DEFAULT); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, statement_.session_.errhp_); } } void oracle_vector_use_type_backend::pre_use(indicator const *ind) { // first deal with data if (type_ == x_stdstring) { // nothing to do - it's already done during bind // (and it's probably impossible to separate them, because // changes in the string size could not be handled here) } else if (type_ == x_long_long) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const entrySize = 100; // arbitrary, but consistent std::size_t const vecSize = v.size(); for (std::size_t i = 0; i != vecSize; ++i) { snprintf(pos, entrySize, "%" LL_FMT_FLAGS "d", v[i]); pos += entrySize; } } else if (type_ == x_unsigned_long_long) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const entrySize = 100; // arbitrary, but consistent std::size_t const vecSize = v.size(); for (std::size_t i = 0; i != vecSize; ++i) { snprintf(pos, entrySize, "%" LL_FMT_FLAGS "u", v[i]); pos += entrySize; } } else if (type_ == x_stdtm) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); ub1* pos = reinterpret_cast(buf_); std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { *pos++ = static_cast(100 + (1900 + v[i].tm_year) / 100); *pos++ = static_cast(100 + v[i].tm_year % 100); *pos++ = static_cast(v[i].tm_mon + 1); *pos++ = static_cast(v[i].tm_mday); *pos++ = static_cast(v[i].tm_hour + 1); *pos++ = static_cast(v[i].tm_min + 1); *pos++ = static_cast(v[i].tm_sec + 1); } } // then handle indicators if (ind != NULL) { std::size_t const vsize = size(); for (std::size_t i = 0; i != vsize; ++i, ++ind) { if (*ind == i_null) { indOCIHolderVec_[i] = -1; // null } else { indOCIHolderVec_[i] = 0; // value is OK } } } else { // no indicators - treat all fields as OK std::size_t const vsize = size(); for (std::size_t i = 0; i != vsize; ++i, ++ind) { indOCIHolderVec_[i] = 0; // value is OK } } } std::size_t oracle_vector_use_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type_) { // simple cases case x_char: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_short: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_integer: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_long_long: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_unsigned_long_long: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_double: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_stdstring: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_stdtm: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } return sz; } void oracle_vector_use_type_backend::clean_up() { if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } if (bindp_ != NULL) { OCIHandleFree(bindp_, OCI_HTYPE_DEFINE); bindp_ = NULL; } } soci-3.2.3/backends/oracle/standard-use-type.cpp0000644000000000000000000003172012511361676020261 0ustar rootroot// // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define soci_ORACLE_SOURCE #include "soci-oracle.h" #include "blob.h" #include "error.h" #include "rowid.h" #include "statement.h" #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #define snprintf _snprintf #endif using namespace soci; using namespace soci::details; using namespace soci::details::oracle; void oracle_standard_use_type_backend::prepare_for_bind( void *&data, sb4 &size, ub2 &oracleType, bool readOnly) { readOnly_ = readOnly; switch (type_) { // simple cases case x_char: oracleType = SQLT_AFC; size = sizeof(char); if (readOnly) { buf_ = new char[size]; data = buf_; } break; case x_short: oracleType = SQLT_INT; size = sizeof(short); if (readOnly) { buf_ = new char[size]; data = buf_; } break; case x_integer: oracleType = SQLT_INT; size = sizeof(int); if (readOnly) { buf_ = new char[size]; data = buf_; } break; case x_double: oracleType = SQLT_FLT; size = sizeof(double); if (readOnly) { buf_ = new char[size]; data = buf_; } break; // cases that require adjustments and buffer management case x_long_long: case x_unsigned_long_long: oracleType = SQLT_STR; size = 100; // arbitrary buffer length buf_ = new char[size]; data = buf_; break; case x_stdstring: oracleType = SQLT_STR; // 4000 is Oracle max VARCHAR2 size; 32768 is max LONG size size = 32769; buf_ = new char[size]; data = buf_; break; case x_stdtm: oracleType = SQLT_DAT; size = 7 * sizeof(ub1); buf_ = new char[size]; data = buf_; break; // cases that require special handling case x_statement: { oracleType = SQLT_RSET; statement *st = static_cast(data); st->alloc(); oracle_statement_backend *stbe = static_cast(st->get_backend()); size = 0; data = &stbe->stmtp_; } break; case x_rowid: { oracleType = SQLT_RDD; rowid *rid = static_cast(data); oracle_rowid_backend *rbe = static_cast(rid->get_backend()); size = 0; data = &rbe->rowidp_; } break; case x_blob: { oracleType = SQLT_BLOB; blob *b = static_cast(data); oracle_blob_backend *bbe = static_cast(b->get_backend()); size = 0; data = &bbe->lobp_; } break; } } void oracle_standard_use_type_backend::bind_by_pos( int &position, void *data, exchange_type type, bool readOnly) { if (statement_.boundByName_) { throw soci_error( "Binding for use elements must be either by position or by name."); } data_ = data; // for future reference type_ = type; // for future reference ub2 oracleType; sb4 size; prepare_for_bind(data, size, oracleType, readOnly); sword res = OCIBindByPos(statement_.stmtp_, &bindp_, statement_.session_.errhp_, position++, data, size, oracleType, &indOCIHolder_, 0, 0, 0, 0, OCI_DEFAULT); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, statement_.session_.errhp_); } statement_.boundByPos_ = true; } void oracle_standard_use_type_backend::bind_by_name( std::string const &name, void *data, exchange_type type, bool readOnly) { if (statement_.boundByPos_) { throw soci_error( "Binding for use elements must be either by position or by name."); } data_ = data; // for future reference type_ = type; // for future reference ub2 oracleType; sb4 size; prepare_for_bind(data, size, oracleType, readOnly); sword res = OCIBindByName(statement_.stmtp_, &bindp_, statement_.session_.errhp_, reinterpret_cast(const_cast(name.c_str())), static_cast(name.size()), data, size, oracleType, &indOCIHolder_, 0, 0, 0, 0, OCI_DEFAULT); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, statement_.session_.errhp_); } statement_.boundByName_ = true; } void oracle_standard_use_type_backend::pre_use(indicator const *ind) { // first deal with data switch (type_) { case x_char: if (readOnly_) { buf_[0] = *static_cast(data_); } break; case x_short: if (readOnly_) { *static_cast(static_cast(buf_)) = *static_cast(data_); } break; case x_integer: if (readOnly_) { *static_cast(static_cast(buf_)) = *static_cast(data_); } break; case x_long_long: { size_t const size = 100; // arbitrary, but consistent with prepare_for_bind snprintf(buf_, size, "%" LL_FMT_FLAGS "d", *static_cast(data_)); } break; case x_unsigned_long_long: { size_t const size = 100; // arbitrary, but consistent with prepare_for_bind snprintf(buf_, size, "%" LL_FMT_FLAGS "u", *static_cast(data_)); } break; case x_double: if (readOnly_) { *static_cast(static_cast(buf_)) = *static_cast(data_); } break; case x_stdstring: { std::string *s = static_cast(data_); // 4000 is Oracle max VARCHAR2 size; 32768 is max LONG size std::size_t const bufSize = 32769; std::size_t const sSize = s->size(); std::size_t const toCopy = sSize < bufSize -1 ? sSize + 1 : bufSize - 1; strncpy(buf_, s->c_str(), toCopy); buf_[toCopy] = '\0'; } break; case x_stdtm: { std::tm *t = static_cast(data_); ub1* pos = reinterpret_cast(buf_); *pos++ = static_cast(100 + (1900 + t->tm_year) / 100); *pos++ = static_cast(100 + t->tm_year % 100); *pos++ = static_cast(t->tm_mon + 1); *pos++ = static_cast(t->tm_mday); *pos++ = static_cast(t->tm_hour + 1); *pos++ = static_cast(t->tm_min + 1); *pos = static_cast(t->tm_sec + 1); } break; case x_statement: { statement *s = static_cast(data_); s->undefine_and_bind(); } break; case x_rowid: case x_blob: // nothing to do break; } // then handle indicators if (ind != NULL && *ind == i_null) { indOCIHolder_ = -1; // null } else { indOCIHolder_ = 0; // value is OK } } void oracle_standard_use_type_backend::post_use(bool gotData, indicator *ind) { // It is possible to have the bound element being overwritten // by the database. // // With readOnly_ == true the propagation of modification should *not* // take place and in addition the attempt of modification should be detected and reported. // first, deal with data if (gotData) { switch (type_) { case x_char: if (readOnly_) { const char original = *static_cast(data_); const char bound = buf_[0]; if (original != bound) { throw soci_error("Attempted modification of const use element"); } } break; case x_short: if (readOnly_) { const short original = *static_cast(data_); const short bound = *static_cast(static_cast(buf_)); if (original != bound) { throw soci_error("Attempted modification of const use element"); } } break; case x_integer: if (readOnly_) { const int original = *static_cast(data_); const int bound = *static_cast(static_cast(buf_)); if (original != bound) { throw soci_error("Attempted modification of const use element"); } } break; case x_long_long: if (readOnly_) { long long const original = *static_cast(data_); long long const bound = std::strtoll(buf_, NULL, 10); if (original != bound) { throw soci_error("Attempted modification of const use element"); } } break; case x_unsigned_long_long: if (readOnly_) { unsigned long long const original = *static_cast(data_); unsigned long long const bound = std::strtoull(buf_, NULL, 10); if (original != bound) { throw soci_error("Attempted modification of const use element"); } } break; case x_double: if (readOnly_) { const double original = *static_cast(data_); const double bound = *static_cast(static_cast(buf_)); if (original != bound) { throw soci_error("Attempted modification of const use element"); } } break; case x_stdstring: { std::string & original = *static_cast(data_); if (original != buf_) { if (readOnly_) { throw soci_error("Attempted modification of const use element"); } else { original = buf_; } } } break; case x_stdtm: { std::tm & original = *static_cast(data_); std::tm bound; ub1 *pos = reinterpret_cast(buf_); bound.tm_isdst = -1; bound.tm_year = (*pos++ - 100) * 100; bound.tm_year += *pos++ - 2000; bound.tm_mon = *pos++ - 1; bound.tm_mday = *pos++; bound.tm_hour = *pos++ - 1; bound.tm_min = *pos++ - 1; bound.tm_sec = *pos++ - 1; if (original.tm_year != bound.tm_year || original.tm_mon != bound.tm_mon || original.tm_mday != bound.tm_mday || original.tm_hour != bound.tm_hour || original.tm_min != bound.tm_min || original.tm_sec != bound.tm_sec) { if (readOnly_) { throw soci_error("Attempted modification of const use element"); } else { original = bound; // normalize and compute the remaining fields std::mktime(&original); } } } break; case x_statement: { statement *s = static_cast(data_); s->define_and_bind(); } break; case x_rowid: case x_blob: // nothing to do here break; } } if (ind != NULL) { if (gotData) { if (indOCIHolder_ == 0) { *ind = i_ok; } else if (indOCIHolder_ == -1) { *ind = i_null; } else { *ind = i_truncated; } } } } void oracle_standard_use_type_backend::clean_up() { if (bindp_ != NULL) { OCIHandleFree(bindp_, OCI_HTYPE_DEFINE); bindp_ = NULL; } if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } } soci-3.2.3/backends/oracle/session.cpp0000644000000000000000000001373612511361676016402 0ustar rootroot// // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ORACLE_SOURCE #include "soci-oracle.h" #include "error.h" #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace soci::details::oracle; oracle_session_backend::oracle_session_backend(std::string const & serviceName, std::string const & userName, std::string const & password, int mode, bool decimals_as_strings) : envhp_(NULL), srvhp_(NULL), errhp_(NULL), svchp_(NULL), usrhp_(NULL) , decimals_as_strings_(decimals_as_strings) { sword res; // create the environment res = OCIEnvCreate(&envhp_, OCI_THREADED | OCI_ENV_NO_MUTEX, 0, 0, 0, 0, 0, 0); if (res != OCI_SUCCESS) { throw soci_error("Cannot create environment"); } // create the server handle res = OCIHandleAlloc(envhp_, reinterpret_cast(&srvhp_), OCI_HTYPE_SERVER, 0, 0); if (res != OCI_SUCCESS) { clean_up(); throw soci_error("Cannot create server handle"); } // create the error handle res = OCIHandleAlloc(envhp_, reinterpret_cast(&errhp_), OCI_HTYPE_ERROR, 0, 0); if (res != OCI_SUCCESS) { clean_up(); throw soci_error("Cannot create error handle"); } // create the server context sb4 serviceNameLen = static_cast(serviceName.size()); res = OCIServerAttach(srvhp_, errhp_, reinterpret_cast(const_cast(serviceName.c_str())), serviceNameLen, OCI_DEFAULT); if (res != OCI_SUCCESS) { std::string msg; int errNum; get_error_details(res, errhp_, msg, errNum); clean_up(); throw oracle_soci_error(msg, errNum); } // create service context handle res = OCIHandleAlloc(envhp_, reinterpret_cast(&svchp_), OCI_HTYPE_SVCCTX, 0, 0); if (res != OCI_SUCCESS) { clean_up(); throw soci_error("Cannot create service context"); } // set the server attribute in the context handle res = OCIAttrSet(svchp_, OCI_HTYPE_SVCCTX, srvhp_, 0, OCI_ATTR_SERVER, errhp_); if (res != OCI_SUCCESS) { std::string msg; int errNum; get_error_details(res, errhp_, msg, errNum); clean_up(); throw oracle_soci_error(msg, errNum); } // allocate user session handle res = OCIHandleAlloc(envhp_, reinterpret_cast(&usrhp_), OCI_HTYPE_SESSION, 0, 0); if (res != OCI_SUCCESS) { clean_up(); throw soci_error("Cannot allocate user session handle"); } // set username attribute in the user session handle sb4 userNameLen = static_cast(userName.size()); res = OCIAttrSet(usrhp_, OCI_HTYPE_SESSION, reinterpret_cast(const_cast(userName.c_str())), userNameLen, OCI_ATTR_USERNAME, errhp_); if (res != OCI_SUCCESS) { clean_up(); throw soci_error("Cannot set username"); } // set password attribute sb4 passwordLen = static_cast(password.size()); res = OCIAttrSet(usrhp_, OCI_HTYPE_SESSION, reinterpret_cast(const_cast(password.c_str())), passwordLen, OCI_ATTR_PASSWORD, errhp_); if (res != OCI_SUCCESS) { clean_up(); throw soci_error("Cannot set password"); } // begin the session res = OCISessionBegin(svchp_, errhp_, usrhp_, OCI_CRED_RDBMS, mode); if (res != OCI_SUCCESS) { std::string msg; int errNum; get_error_details(res, errhp_, msg, errNum); clean_up(); throw oracle_soci_error(msg, errNum); } // set the session in the context handle res = OCIAttrSet(svchp_, OCI_HTYPE_SVCCTX, usrhp_, 0, OCI_ATTR_SESSION, errhp_); if (res != OCI_SUCCESS) { std::string msg; int errNum; get_error_details(res, errhp_, msg, errNum); clean_up(); throw oracle_soci_error(msg, errNum); } } oracle_session_backend::~oracle_session_backend() { clean_up(); } void oracle_session_backend::begin() { // This code is commented out because it causes one of the transaction // tests in common_tests::test10() to fail with error 'Invalid handle' // With the code commented out, all tests pass. // sword res = OCITransStart(svchp_, errhp_, 0, OCI_TRANS_NEW); // if (res != OCI_SUCCESS) // { // throworacle_soci_error(res, errhp_); // } } void oracle_session_backend::commit() { sword res = OCITransCommit(svchp_, errhp_, OCI_DEFAULT); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, errhp_); } } void oracle_session_backend::rollback() { sword res = OCITransRollback(svchp_, errhp_, OCI_DEFAULT); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, errhp_); } } void oracle_session_backend::clean_up() { if (svchp_ != NULL && errhp_ != NULL && usrhp_ != NULL) { OCISessionEnd(svchp_, errhp_, usrhp_, OCI_DEFAULT); } if (usrhp_) { OCIHandleFree(usrhp_, OCI_HTYPE_SESSION); } if (svchp_) { OCIHandleFree(svchp_, OCI_HTYPE_SVCCTX); } if (srvhp_) { OCIServerDetach(srvhp_, errhp_, OCI_DEFAULT); OCIHandleFree(srvhp_, OCI_HTYPE_SERVER); } if (errhp_) { OCIHandleFree(errhp_, OCI_HTYPE_ERROR); } if (envhp_) { OCIHandleFree(envhp_, OCI_HTYPE_ENV); } } oracle_statement_backend * oracle_session_backend::make_statement_backend() { return new oracle_statement_backend(*this); } oracle_rowid_backend * oracle_session_backend::make_rowid_backend() { return new oracle_rowid_backend(*this); } oracle_blob_backend * oracle_session_backend::make_blob_backend() { return new oracle_blob_backend(*this); } soci-3.2.3/backends/oracle/Makefile.basic0000644000000000000000000000520712511361676016725 0ustar rootroot# The following variable is specific to this backend and its correct # values might depend on your environment - feel free to set it accordingly. ORACLEINCLUDEDIR = -I/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/rdbms/public # The rest of the Makefile is indepentent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long CXXFLAGSSO = ${CXXFLAGS} -fPIC INCLUDEDIRS = -I../../core ${ORACLEINCLUDEDIR} OBJECTS = blob.o factory.o row-id.o session.o standard-into-type.o \ standard-use-type.o statement.o vector-into-type.o vector-use-type.o \ error.o OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \ standard-into-type-s.o standard-use-type-s.o statement-s.o \ vector-into-type-s.o vector-use-type-s.o error-s.o libsoci_oracle.a : ${OBJECTS} ar rv $@ $? rm *.o soci-oracle.o : soci-oracle.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} blob.o : blob.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} error.o : error.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} factory.o : factory.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} row-id.o : row-id.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} session.o : session.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-into-type.o : standard-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-use-type.o : standard-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} statement.o : statement.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-into-type.o : vector-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-use-type.o : vector-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} shared : ${OBJECTSSO} ${COMPILER} -shared -o libsoci_oracle.so ${OBJECTSSO} rm *.o blob-s.o : blob.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} error-s.o : error.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} factory-s.o : factory.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} row-id-s.o : row-id.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} session-s.o : session.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} standard-into-type-s.o : standard-into-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} standard-use-type-s.o : standard-use-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} statement-s.o : statement.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} vector-into-type-s.o : vector-into-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} vector-use-type-s.o : vector-use-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} clean : rm -f *.o libsoci_oracle.a libsoci_oracle.so soci-3.2.3/backends/oracle/soci-oracle.h0000644000000000000000000001770212511362240016545 0ustar rootroot// // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_ORACLE_H_INCLUDED #define SOCI_ORACLE_H_INCLUDED #ifdef _WIN32 # ifdef SOCI_DLL # ifdef SOCI_ORACLE_SOURCE # define SOCI_ORACLE_DECL __declspec(dllexport) # else # define SOCI_ORACLE_DECL __declspec(dllimport) # endif // SOCI_ORACLE_SOURCE # endif // SOCI_DLL #endif // _WIN32 // // If SOCI_ORACLE_DECL isn't defined yet define it now #ifndef SOCI_ORACLE_DECL # define SOCI_ORACLE_DECL #endif #include #include // OCI #include #ifdef _MSC_VER #pragma warning(disable:4512 4511) #endif namespace soci { class SOCI_ORACLE_DECL oracle_soci_error : public soci_error { public: oracle_soci_error(std::string const & msg, int errNum = 0); int err_num_; }; struct oracle_statement_backend; struct oracle_standard_into_type_backend : details::standard_into_type_backend { oracle_standard_into_type_backend(oracle_statement_backend &st) : statement_(st), defnp_(NULL), indOCIHolder_(0), data_(NULL), buf_(NULL) {} virtual void define_by_pos(int &position, void *data, details::exchange_type type); virtual void pre_fetch(); virtual void post_fetch(bool gotData, bool calledFromFetch, indicator *ind); virtual void clean_up(); oracle_statement_backend &statement_; OCIDefine *defnp_; sb2 indOCIHolder_; void *data_; char *buf_; // generic buffer details::exchange_type type_; ub2 rCode_; }; struct oracle_vector_into_type_backend : details::vector_into_type_backend { oracle_vector_into_type_backend(oracle_statement_backend &st) : statement_(st), defnp_(NULL), indOCIHolders_(NULL), data_(NULL), buf_(NULL) {} virtual void define_by_pos(int &position, void *data, details::exchange_type type); virtual void pre_fetch(); virtual void post_fetch(bool gotData, indicator *ind); virtual void resize(std::size_t sz); virtual std::size_t size(); virtual void clean_up(); // helper function for preparing indicators and sizes_ vectors // (as part of the define_by_pos) void prepare_indicators(std::size_t size); oracle_statement_backend &statement_; OCIDefine *defnp_; sb2 *indOCIHolders_; std::vector indOCIHolderVec_; void *data_; char *buf_; // generic buffer details::exchange_type type_; std::size_t colSize_; // size of the string column (used for strings) std::vector sizes_; // sizes of data fetched (used for strings) std::vector rCodes_; }; struct oracle_standard_use_type_backend : details::standard_use_type_backend { oracle_standard_use_type_backend(oracle_statement_backend &st) : statement_(st), bindp_(NULL), indOCIHolder_(0), data_(NULL), buf_(NULL) {} virtual void bind_by_pos(int &position, void *data, details::exchange_type type, bool readOnly); virtual void bind_by_name(std::string const &name, void *data, details::exchange_type type, bool readOnly); // common part for bind_by_pos and bind_by_name void prepare_for_bind(void *&data, sb4 &size, ub2 &oracleType, bool readOnly); virtual void pre_use(indicator const *ind); virtual void post_use(bool gotData, indicator *ind); virtual void clean_up(); oracle_statement_backend &statement_; OCIBind *bindp_; sb2 indOCIHolder_; void *data_; bool readOnly_; char *buf_; // generic buffer details::exchange_type type_; }; struct oracle_vector_use_type_backend : details::vector_use_type_backend { oracle_vector_use_type_backend(oracle_statement_backend &st) : statement_(st), bindp_(NULL), indOCIHolders_(NULL), data_(NULL), buf_(NULL) {} virtual void bind_by_pos(int &position, void *data, details::exchange_type type); virtual void bind_by_name(std::string const &name, void *data, details::exchange_type type); // common part for bind_by_pos and bind_by_name void prepare_for_bind(void *&data, sb4 &size, ub2 &oracleType); // helper function for preparing indicators and sizes_ vectors // (as part of the bind_by_pos and bind_by_name) void prepare_indicators(std::size_t size); virtual void pre_use(indicator const *ind); virtual std::size_t size(); virtual void clean_up(); oracle_statement_backend &statement_; OCIBind *bindp_; std::vector indOCIHolderVec_; sb2 *indOCIHolders_; void *data_; char *buf_; // generic buffer details::exchange_type type_; // used for strings only std::vector sizes_; std::size_t maxSize_; }; struct oracle_session_backend; struct oracle_statement_backend : details::statement_backend { oracle_statement_backend(oracle_session_backend &session); virtual void alloc(); virtual void clean_up(); virtual void prepare(std::string const &query, details::statement_type eType); virtual exec_fetch_result execute(int number); virtual exec_fetch_result fetch(int number); virtual long long get_affected_rows(); virtual int get_number_of_rows(); virtual std::string rewrite_for_procedure_call(std::string const &query); virtual int prepare_for_describe(); virtual void describe_column(int colNum, data_type &dtype, std::string &columnName); // helper for defining into vector std::size_t column_size(int position); virtual oracle_standard_into_type_backend * make_into_type_backend(); virtual oracle_standard_use_type_backend * make_use_type_backend(); virtual oracle_vector_into_type_backend * make_vector_into_type_backend(); virtual oracle_vector_use_type_backend * make_vector_use_type_backend(); oracle_session_backend &session_; OCIStmt *stmtp_; bool boundByName_; bool boundByPos_; bool noData_; }; struct oracle_rowid_backend : details::rowid_backend { oracle_rowid_backend(oracle_session_backend &session); ~oracle_rowid_backend(); OCIRowid *rowidp_; }; struct oracle_blob_backend : details::blob_backend { oracle_blob_backend(oracle_session_backend &session); ~oracle_blob_backend(); virtual std::size_t get_len(); virtual std::size_t read(std::size_t offset, char *buf, std::size_t toRead); virtual std::size_t write(std::size_t offset, char const *buf, std::size_t toWrite); virtual std::size_t append(char const *buf, std::size_t toWrite); virtual void trim(std::size_t newLen); oracle_session_backend &session_; OCILobLocator *lobp_; }; struct oracle_session_backend : details::session_backend { oracle_session_backend(std::string const & serviceName, std::string const & userName, std::string const & password, int mode, bool decimals_as_strings = false); ~oracle_session_backend(); virtual void begin(); virtual void commit(); virtual void rollback(); virtual std::string get_backend_name() const { return "oracle"; } void clean_up(); virtual oracle_statement_backend * make_statement_backend(); virtual oracle_rowid_backend * make_rowid_backend(); virtual oracle_blob_backend * make_blob_backend(); bool get_option_decimals_as_strings() { return decimals_as_strings_; } OCIEnv *envhp_; OCIServer *srvhp_; OCIError *errhp_; OCISvcCtx *svchp_; OCISession *usrhp_; bool decimals_as_strings_; }; struct oracle_backend_factory : backend_factory { oracle_backend_factory() {} virtual oracle_session_backend * make_session( connection_parameters const & parameters) const; }; extern SOCI_ORACLE_DECL oracle_backend_factory const oracle; extern "C" { // for dynamic backend loading SOCI_ORACLE_DECL backend_factory const * factory_oracle(); SOCI_ORACLE_DECL void register_factory_oracle(); } // extern "C" } // namespace soci #endif soci-3.2.3/backends/oracle/error.cpp0000644000000000000000000000265612511361676016047 0ustar rootroot// // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ORACLE_SOURCE #include "soci-oracle.h" #include "error.h" #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace soci::details::oracle; oracle_soci_error::oracle_soci_error(std::string const & msg, int errNum) : soci_error(msg), err_num_(errNum) { } void soci::details::oracle::get_error_details(sword res, OCIError *errhp, std::string &msg, int &errNum) { text errbuf[512]; sb4 errcode; errNum = 0; switch (res) { case OCI_NO_DATA: msg = "soci error: No data"; break; case OCI_ERROR: OCIErrorGet(errhp, 1, 0, &errcode, errbuf, sizeof(errbuf), OCI_HTYPE_ERROR); msg = reinterpret_cast(errbuf); errNum = static_cast(errcode); break; case OCI_INVALID_HANDLE: msg = "soci error: Invalid handle"; break; default: msg = "soci error: Unknown error code"; } } void soci::details::oracle::throw_oracle_soci_error(sword res, OCIError *errhp) { std::string msg; int errNum; get_error_details(res, errhp, msg, errNum); throw oracle_soci_error(msg, errNum); } soci-3.2.3/backends/oracle/factory.cpp0000644000000000000000000000710712511361676016361 0ustar rootroot// // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ORACLE_SOURCE #include "soci-oracle.h" #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; // retrieves service name, user name and password from the // uniform connect string void chop_connect_string(std::string const & connectString, std::string & serviceName, std::string & userName, std::string & password, int & mode, bool & decimals_as_strings) { // transform the connect string into a sequence of tokens // separated by spaces, this is done by replacing each first '=' // in each original token with space // note: each original token is a key=value pair and only the first // '=' there is replaced with space, so that potential '=' signs // in the value part are left intact std::string tmp; bool in_value = false; for (std::string::const_iterator i = connectString.begin(), end = connectString.end(); i != end; ++i) { if (*i == '=' && in_value == false) { // this is the first '=' in the key=value pair tmp += ' '; in_value = true; } else { tmp += *i; if (*i == ' ' || *i == '\t') { // follow with the next key=value pair in_value = false; } } } serviceName.clear(); userName.clear(); password.clear(); mode = OCI_DEFAULT; decimals_as_strings = false; std::istringstream iss(tmp); std::string key, value; while (iss >> key >> value) { if (key == "service") { serviceName = value; } else if (key == "user") { userName = value; } else if (key == "password") { password = value; } else if (key == "mode") { if (value == "sysdba") { mode = OCI_SYSDBA; } else if (value == "sysoper") { mode = OCI_SYSOPER; } else if (value == "default") { mode = OCI_DEFAULT; } else { throw soci_error("Invalid connection mode."); } } else if (key == "decimals_as_strings") { decimals_as_strings = value == "1" || value == "Y" || value == "y"; } } } // concrete factory for Empty concrete strategies oracle_session_backend * oracle_backend_factory::make_session( connection_parameters const & parameters) const { std::string serviceName, userName, password; int mode; bool decimals_as_strings; chop_connect_string(parameters.get_connect_string(), serviceName, userName, password, mode, decimals_as_strings); return new oracle_session_backend(serviceName, userName, password, mode, decimals_as_strings); } oracle_backend_factory const soci::oracle; extern "C" { // for dynamic backend loading SOCI_ORACLE_DECL backend_factory const * factory_oracle() { return &soci::oracle; } SOCI_ORACLE_DECL void register_factory_oracle() { soci::dynamic_backends::register_backend("oracle", soci::oracle); } } // extern "C" soci-3.2.3/backends/oracle/row-id.cpp0000644000000000000000000000151612511361676016111 0ustar rootroot// // Copyright (C) 2013 Mateusz Loskot // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ORACLE_SOURCE #include "soci-oracle.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; oracle_rowid_backend::oracle_rowid_backend(oracle_session_backend &session) { sword res = OCIDescriptorAlloc(session.envhp_, reinterpret_cast(&rowidp_), OCI_DTYPE_ROWID, 0, 0); if (res != OCI_SUCCESS) { throw soci_error("Cannot allocate the ROWID descriptor"); } } oracle_rowid_backend::~oracle_rowid_backend() { OCIDescriptorFree(rowidp_, OCI_DTYPE_ROWID); } soci-3.2.3/backends/oracle/standard-into-type.cpp0000644000000000000000000001547512511361676020447 0ustar rootroot// // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ORACLE_SOURCE #include "soci-oracle.h" #include "blob.h" #include "error.h" #include "rowid.h" #include "statement.h" #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace soci::details::oracle; oracle_standard_into_type_backend * oracle_statement_backend::make_into_type_backend() { return new oracle_standard_into_type_backend(*this); } oracle_standard_use_type_backend * oracle_statement_backend::make_use_type_backend() { return new oracle_standard_use_type_backend(*this); } oracle_vector_into_type_backend * oracle_statement_backend::make_vector_into_type_backend() { return new oracle_vector_into_type_backend(*this); } oracle_vector_use_type_backend * oracle_statement_backend::make_vector_use_type_backend() { return new oracle_vector_use_type_backend(*this); } void oracle_standard_into_type_backend::define_by_pos( int &position, void *data, exchange_type type) { data_ = data; // for future reference type_ = type; // for future reference ub2 oracleType = 0; // dummy initialization to please the compiler sb4 size = 0; // also dummy switch (type) { // simple cases case x_char: oracleType = SQLT_AFC; size = sizeof(char); break; case x_short: oracleType = SQLT_INT; size = sizeof(short); break; case x_integer: oracleType = SQLT_INT; size = sizeof(int); break; case x_double: oracleType = SQLT_FLT; size = sizeof(double); break; // cases that require adjustments and buffer management case x_long_long: case x_unsigned_long_long: oracleType = SQLT_STR; size = 100; // arbitrary buffer length buf_ = new char[size]; data = buf_; break; case x_stdstring: oracleType = SQLT_STR; size = 32769; // support selecting strings from LONG columns buf_ = new char[size]; data = buf_; break; case x_stdtm: oracleType = SQLT_DAT; size = 7 * sizeof(ub1); buf_ = new char[size]; data = buf_; break; // cases that require special handling case x_statement: { oracleType = SQLT_RSET; statement *st = static_cast(data); st->alloc(); oracle_statement_backend *stbe = static_cast(st->get_backend()); size = 0; data = &stbe->stmtp_; } break; case x_rowid: { oracleType = SQLT_RDD; rowid *rid = static_cast(data); oracle_rowid_backend *rbe = static_cast(rid->get_backend()); size = 0; data = &rbe->rowidp_; } break; case x_blob: { oracleType = SQLT_BLOB; blob *b = static_cast(data); oracle_blob_backend *bbe = static_cast(b->get_backend()); size = 0; data = &bbe->lobp_; } break; } sword res = OCIDefineByPos(statement_.stmtp_, &defnp_, statement_.session_.errhp_, position++, data, size, oracleType, &indOCIHolder_, 0, &rCode_, OCI_DEFAULT); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, statement_.session_.errhp_); } } void oracle_standard_into_type_backend::pre_fetch() { // nothing to do except with Statement into objects if (type_ == x_statement) { statement *st = static_cast(data_); st->undefine_and_bind(); } } void oracle_standard_into_type_backend::post_fetch( bool gotData, bool calledFromFetch, indicator *ind) { // first, deal with data if (gotData) { // only std::string, std::tm and Statement need special handling if (type_ == x_stdstring) { if (indOCIHolder_ != -1) { std::string *s = static_cast(data_); *s = buf_; } } else if (type_ == x_long_long) { if (indOCIHolder_ != -1) { long long *v = static_cast(data_); *v = std::strtoll(buf_, NULL, 10); } } else if (type_ == x_unsigned_long_long) { if (indOCIHolder_ != -1) { unsigned long long *v = static_cast(data_); *v = std::strtoull(buf_, NULL, 10); } } else if (type_ == x_stdtm) { if (indOCIHolder_ != -1) { std::tm *t = static_cast(data_); ub1 *pos = reinterpret_cast(buf_); t->tm_isdst = -1; t->tm_year = (*pos++ - 100) * 100; t->tm_year += *pos++ - 2000; t->tm_mon = *pos++ - 1; t->tm_mday = *pos++; t->tm_hour = *pos++ - 1; t->tm_min = *pos++ - 1; t->tm_sec = *pos++ - 1; // normalize and compute the remaining fields std::mktime(t); } } else if (type_ == x_statement) { statement *st = static_cast(data_); st->define_and_bind(); } } // then - deal with indicators if (calledFromFetch == true && gotData == false) { // this is a normal end-of-rowset condition, // no need to set anything (fetch() will return false) return; } if (ind != NULL) { if (gotData) { if (indOCIHolder_ == 0) { *ind = i_ok; } else if (indOCIHolder_ == -1) { *ind = i_null; } else { *ind = i_truncated; } } } else { if (indOCIHolder_ == -1) { // fetched null and no indicator - programming error! throw soci_error("Null value fetched and no indicator defined."); } } } void oracle_standard_into_type_backend::clean_up() { if (defnp_ != NULL) { OCIHandleFree(defnp_, OCI_HTYPE_DEFINE); defnp_ = NULL; } if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } } soci-3.2.3/backends/oracle/test/0000755000000000000000000000000012511362240015144 5ustar rootrootsoci-3.2.3/backends/oracle/test/test-oracle.cpp0000644000000000000000000010056712511362240020103 0ustar rootroot// // // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci.h" #include "soci-oracle.h" #include "common-tests.h" #include #include #include #include #include using namespace soci; using namespace soci::tests; std::string connectString; backend_factory const &backEnd = *soci::factory_oracle(); // Extra tests for date/time void test1() { session sql(backEnd, connectString); { std::time_t now = std::time(NULL); std::tm t1, t2; t2 = *std::localtime(&now); sql << "select t from (select :t as t from dual)", into(t1), use(t2); assert(t1.tm_sec == t2.tm_sec); assert(t1.tm_min == t2.tm_min); assert(t1.tm_hour == t2.tm_hour); assert(t1.tm_mday == t2.tm_mday); assert(t1.tm_mon == t2.tm_mon); assert(t1.tm_year == t2.tm_year); assert(t1.tm_wday == t2.tm_wday); assert(t1.tm_yday == t2.tm_yday); assert(t1.tm_isdst == t2.tm_isdst); // make sure the date is stored properly in Oracle char buf[25]; strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &t2); std::string t_out; std::string format("MM-DD-YYYY HH24:MI:SS"); sql << "select to_char(t, :format) from (select :t as t from dual)", into(t_out), use(format), use(t2); assert(t_out == std::string(buf)); } { // date and time - before year 2000 std::time_t then = std::time(NULL) - 17*365*24*60*60; std::tm t1, t2; t2 = *std::localtime(&then); sql << "select t from (select :t as t from dual)", into(t1), use(t2); assert(t1.tm_sec == t2.tm_sec); assert(t1.tm_min == t2.tm_min); assert(t1.tm_hour == t2.tm_hour); assert(t1.tm_mday == t2.tm_mday); assert(t1.tm_mon == t2.tm_mon); assert(t1.tm_year == t2.tm_year); assert(t1.tm_wday == t2.tm_wday); assert(t1.tm_yday == t2.tm_yday); assert(t1.tm_isdst == t2.tm_isdst); // make sure the date is stored properly in Oracle char buf[25]; strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &t2); std::string t_out; std::string format("MM-DD-YYYY HH24:MI:SS"); sql << "select to_char(t, :format) from (select :t as t from dual)", into(t_out), use(format), use(t2); assert(t_out == std::string(buf)); } std::cout << "test 1 passed" << std::endl; } // explicit calls test void test2() { session sql(backEnd, connectString); statement st(sql); st.alloc(); int i = 0; st.exchange(into(i)); st.prepare("select 7 from dual"); st.define_and_bind(); st.execute(1); assert(i == 7); std::cout << "test 2 passed" << std::endl; } // DDL + blob test struct blob_table_creator : public table_creator_base { blob_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test (" " id number(10) not null," " img blob" ")"; } }; void test3() { session sql(backEnd, connectString); blob_table_creator tableCreator(sql); char buf[] = "abcdefghijklmnopqrstuvwxyz"; sql << "insert into soci_test (id, img) values (7, empty_blob())"; { blob b(sql); oracle_session_backend *sessionBackEnd = static_cast(sql.get_backend()); oracle_blob_backend *blobBackEnd = static_cast(b.get_backend()); OCILobDisableBuffering(sessionBackEnd->svchp_, sessionBackEnd->errhp_, blobBackEnd->lobp_); sql << "select img from soci_test where id = 7", into(b); assert(b.get_len() == 0); // note: blob offsets start from 1 b.write(1, buf, sizeof(buf)); assert(b.get_len() == sizeof(buf)); b.trim(10); assert(b.get_len() == 10); // append does not work (Oracle bug #886191 ?) //b.append(buf, sizeof(buf)); //assert(b.get_len() == sizeof(buf) + 10); sql.commit(); } { blob b(sql); sql << "select img from soci_test where id = 7", into(b); //assert(b.get_len() == sizeof(buf) + 10); assert(b.get_len() == 10); char buf2[100]; b.read(1, buf2, 10); assert(strncmp(buf2, "abcdefghij", 10) == 0); } std::cout << "test 3 passed" << std::endl; } // nested statement test // (the same syntax is used for output cursors in PL/SQL) struct basic_table_creator : public table_creator_base { basic_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test (" " id number(5) not null," " name varchar2(100)," " code number(5)" ")"; } }; void test4() { session sql(backEnd, connectString); basic_table_creator tableCreator(sql); int id; std::string name; { statement st1 = (sql.prepare << "insert into soci_test (id, name) values (:id, :name)", use(id), use(name)); id = 1; name = "John"; st1.execute(1); id = 2; name = "Anna"; st1.execute(1); id = 3; name = "Mike"; st1.execute(1); } statement stInner(sql); statement stOuter = (sql.prepare << "select cursor(select name from soci_test order by id)" " from soci_test where id = 1", into(stInner)); stInner.exchange(into(name)); stOuter.execute(); stOuter.fetch(); std::vector names; while (stInner.fetch()) { names.push_back(name); } assert(names.size() == 3); assert(names[0] == "John"); assert(names[1] == "Anna"); assert(names[2] == "Mike"); std::cout << "test 4 passed" << std::endl; } // ROWID test void test5() { session sql(backEnd, connectString); basic_table_creator tableCreator(sql); sql << "insert into soci_test(id, name) values(7, \'John\')"; rowid rid(sql); sql << "select rowid from soci_test where id = 7", into(rid); int id; std::string name; sql << "select id, name from soci_test where rowid = :rid", into(id), into(name), use(rid); assert(id == 7); assert(name == "John"); std::cout << "test 5 passed" << std::endl; } // Stored procedures struct procedure_creator : procedure_creator_base { procedure_creator(session & sql) : procedure_creator_base(sql) { sql << "create or replace procedure soci_test(output out varchar2," "input in varchar2) as " "begin output := input; end;"; } }; void test6() { { session sql(backEnd, connectString); procedure_creator procedure_creator(sql); std::string in("my message"); std::string out; statement st = (sql.prepare << "begin soci_test(:output, :input); end;", use(out, "output"), use(in, "input")); st.execute(1); assert(out == in); // explicit procedure syntax { std::string in("my message2"); std::string out; procedure proc = (sql.prepare << "soci_test(:output, :input)", use(out, "output"), use(in, "input")); proc.execute(1); assert(out == in); } } std::cout << "test 6 passed" << std::endl; } // bind into user-defined objects struct string_holder { string_holder() {} string_holder(const char* s) : s_(s) {} string_holder(std::string s) : s_(s) {} std::string get() const { return s_; } private: std::string s_; }; namespace soci { template <> struct type_conversion { typedef std::string base_type; static void from_base(const std::string &s, indicator /* ind */, string_holder &sh) { sh = string_holder(s); } static void to_base(const string_holder &sh, std::string &s, indicator &ind) { s = sh.get(); ind = i_ok; } }; } struct in_out_procedure_creator : public procedure_creator_base { in_out_procedure_creator(session & sql) : procedure_creator_base(sql) { sql << "create or replace procedure soci_test(s in out varchar2)" " as begin s := s || s; end;"; } }; struct returns_null_procedure_creator : public procedure_creator_base { returns_null_procedure_creator(session & sql) : procedure_creator_base(sql) { sql << "create or replace procedure soci_test(s in out varchar2)" " as begin s := NULL; end;"; } }; void test7() { { session sql(backEnd, connectString); { basic_table_creator tableCreator(sql); int id(1); string_holder in("my string"); sql << "insert into soci_test(id, name) values(:id, :name)", use(id), use(in); string_holder out; sql << "select name from soci_test", into(out); assert(out.get() == "my string"); row r; sql << "select * from soci_test", into(r); string_holder dynamicOut = r.get(1); assert(dynamicOut.get() == "my string"); } } std::cout << "test 7 passed" << std::endl; } void test7inout() { { session sql(backEnd, connectString); // test procedure with user-defined type as in-out parameter { in_out_procedure_creator procedureCreator(sql); std::string sh("test"); procedure proc = (sql.prepare << "soci_test(:s)", use(sh)); proc.execute(1); assert(sh == "testtest"); } // test procedure with user-defined type as in-out parameter { in_out_procedure_creator procedureCreator(sql); string_holder sh("test"); procedure proc = (sql.prepare << "soci_test(:s)", use(sh)); proc.execute(1); assert(sh.get() == "testtest"); } } std::cout << "test 7-inout passed" << std::endl; } void test7outnull() { { session sql(backEnd, connectString); // test procedure which returns null { returns_null_procedure_creator procedureCreator(sql); string_holder sh; indicator ind = i_ok; procedure proc = (sql.prepare << "soci_test(:s)", use(sh, ind)); proc.execute(1); assert(ind == i_null); } } std::cout << "test 7-outnull passed" << std::endl; } // test bulk insert features void test8() { session sql(backEnd, connectString); basic_table_creator tableCreator(sql); // verify exception is thrown if vectors of unequal size are passed in { std::vector ids; ids.push_back(1); ids.push_back(2); std::vector codes; codes.push_back(1); std::string error; try { sql << "insert into soci_test(id,code) values(:id,:code)", use(ids), use(codes); } catch (soci_error const &e) { error = e.what(); } assert(error.find("Bind variable size mismatch") != std::string::npos); try { sql << "select from soci_test", into(ids), into(codes); } catch (std::exception const &e) { error = e.what(); } assert(error.find("Bind variable size mismatch") != std::string::npos); } // verify partial insert occurs when one of the records is bad { std::vector ids; ids.push_back(100); ids.push_back(1000000); // too big for column std::string error; try { sql << "insert into soci_test (id) values(:id)", use(ids, "id"); } catch (soci_error const &e) { error = e.what(); //TODO e could be made to tell which row(s) failed } sql.commit(); assert(error.find("ORA-01438") != std::string::npos); int count(7); sql << "select count(*) from soci_test", into(count); assert(count == 1); sql << "delete from soci_test"; } // test insert { std::vector ids; for (int i = 0; i != 3; ++i) { ids.push_back(i+10); } statement st = (sql.prepare << "insert into soci_test(id) values(:id)", use(ids)); st.execute(1); int count; sql << "select count(*) from soci_test", into(count); assert(count == 3); } //verify an exception is thrown if into vector is zero length { std::vector ids; bool caught(false); try { sql << "select id from soci_test", into(ids); } catch (soci_error const &) { caught = true; } assert(caught); } // verify an exception is thrown if use vector is zero length { std::vector ids; bool caught(false); try { sql << "insert into soci_test(id) values(:id)", use(ids); } catch (soci_error const &) { caught = true; } assert(caught); } // test "no data" condition { std::vector inds(3); std::vector ids_out(3); statement st = (sql.prepare << "select id from soci_test where 1=0", into(ids_out, inds)); // false return value means "no data" assert(st.execute(1) == false); // that's it - nothing else is guaranteed // and nothing else is to be tested here } // test NULL indicators { std::vector ids(3); sql << "select id from soci_test", into(ids); std::vector inds_in; inds_in.push_back(i_ok); inds_in.push_back(i_null); inds_in.push_back(i_ok); std::vector new_codes; new_codes.push_back(10); new_codes.push_back(11); new_codes.push_back(10); sql << "update soci_test set code = :code where id = :id", use(new_codes, inds_in), use(ids); std::vector inds_out(3); std::vector codes(3); sql << "select code from soci_test", into(codes, inds_out); assert(codes.size() == 3 && inds_out.size() == 3); assert(codes[0] == 10 && codes[2] == 10); assert(inds_out[0] == i_ok && inds_out[1] == i_null && inds_out[2] == i_ok); } // verify an exception is thrown if null is selected // and no indicator was provided { std::string msg; std::vector intos(3); try { sql << "select code from soci_test", into(intos); } catch (soci_error const &e) { msg = e.what(); } assert(msg == "Null value fetched and no indicator defined." ); } // test basic select { const size_t sz = 3; std::vector inds(sz); std::vector ids_out(sz); statement st = (sql.prepare << "select id from soci_test", into(ids_out, inds)); const bool gotData = st.execute(true); assert(gotData); assert(ids_out.size() == sz); assert(ids_out[0] == 10); assert(ids_out[2] == 12); assert(inds.size() == 3 && inds[0] == i_ok && inds[1] == i_ok && inds[2] == i_ok); } // verify execute(0) { std::vector ids_out(2); statement st = (sql.prepare << "select id from soci_test", into(ids_out)); st.execute(); assert(ids_out.size() == 2); bool gotData = st.fetch(); assert(gotData); assert(ids_out.size() == 2 && ids_out[0] == 10 && ids_out[1] == 11); gotData = st.fetch(); assert(gotData); assert(ids_out.size() == 1 && ids_out[0] == 12); gotData = st.fetch(); assert(gotData == false); } // verify resizing happens if vector is larger // than number of rows returned { std::vector ids_out(4); // one too many statement st2 = (sql.prepare << "select id from soci_test", into(ids_out)); bool gotData = st2.execute(true); assert(gotData); assert(ids_out.size() == 3); assert(ids_out[0] == 10); assert(ids_out[2] == 12); } // verify resizing happens properly during fetch() { std::vector more; more.push_back(13); more.push_back(14); sql << "insert into soci_test(id) values(:id)", use(more); std::vector ids(2); statement st3 = (sql.prepare << "select id from soci_test", into(ids)); bool gotData = st3.execute(true); assert(gotData); assert(ids[0] == 10); assert(ids[1] == 11); gotData = st3.fetch(); assert(gotData); assert(ids[0] == 12); assert(ids[1] == 13); gotData = st3.fetch(); assert(gotData); assert(ids.size() == 1); assert(ids[0] == 14); gotData = st3.fetch(); assert(gotData == false); } std::cout << "test 8 passed" << std::endl; } // more tests for bulk fetch void test9() { session sql(backEnd, connectString); basic_table_creator tableCreator(sql); std::vector in; for (int i = 1; i <= 10; ++i) { in.push_back(i); } sql << "insert into soci_test (id) values(:id)", use(in); int count(0); sql << "select count(*) from soci_test", into(count); assert(count == 10); // verify that the exception is thrown when trying to resize // the output vector to the size that is bigger than that // at the time of binding { std::vector out(4); statement st = (sql.prepare << "select id from soci_test", into(out)); st.execute(); st.fetch(); assert(out.size() == 4); assert(out[0] == 1); assert(out[1] == 2); assert(out[2] == 3); assert(out[3] == 4); out.resize(5); // this should be detected as error try { st.fetch(); assert(false); // should never reach here } catch (soci_error const &e) { assert(std::string(e.what()) == "Increasing the size of the output vector is not supported."); } } // on the other hand, downsizing is OK { std::vector out(4); statement st = (sql.prepare << "select id from soci_test", into(out)); st.execute(); st.fetch(); assert(out.size() == 4); assert(out[0] == 1); assert(out[1] == 2); assert(out[2] == 3); assert(out[3] == 4); out.resize(3); // ok st.fetch(); assert(out.size() == 3); assert(out[0] == 5); assert(out[1] == 6); assert(out[2] == 7); out.resize(4); // ok, not bigger than initially st.fetch(); assert(out.size() == 3); // downsized because of end of data assert(out[0] == 8); assert(out[1] == 9); assert(out[2] == 10); bool gotData = st.fetch(); assert(gotData == false); // end of data } std::cout << "test 9 passed" << std::endl; } struct person { int id; std::string firstName; string_holder lastName; //test mapping of type_conversion-based types std::string gender; }; // Object-Relational Mapping // Note: Use the values class as shown below in type_conversions // to achieve object relational mapping. The values class should // not be used directly in any other fashion. namespace soci { // name-based conversion template<> struct type_conversion { typedef values base_type; static void from_base(values const &v, indicator /* ind */, person &p) { // ignoring possibility that the whole object might be NULL p.id = v.get("ID"); p.firstName = v.get("FIRST_NAME"); p.lastName = v.get("LAST_NAME"); p.gender = v.get("GENDER", "unknown"); } static void to_base(person const & p, values & v, indicator & ind) { v.set("ID", p.id); v.set("FIRST_NAME", p.firstName); v.set("LAST_NAME", p.lastName); v.set("GENDER", p.gender, p.gender.empty() ? i_null : i_ok); ind = i_ok; } }; } struct person_table_creator : public table_creator_base { person_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(id numeric(5,0) NOT NULL," << " last_name varchar2(20), first_name varchar2(20), " " gender varchar2(10))"; } }; struct times100_procedure_creator : public procedure_creator_base { times100_procedure_creator(session & sql) : procedure_creator_base(sql) { sql << "create or replace procedure soci_test(id in out number)" " as begin id := id * 100; end;"; } }; void test10() { session sql(backEnd, connectString); { person_table_creator tableCreator(sql); person p; p.id = 1; p.lastName = "Smith"; p.firstName = "Pat"; sql << "insert into soci_test(id, first_name, last_name, gender) " << "values(:ID, :FIRST_NAME, :LAST_NAME, :GENDER)", use(p); // p should be unchanged assert(p.id == 1); assert(p.firstName == "Pat"); assert(p.lastName.get() == "Smith"); person p1; sql << "select * from soci_test", into(p1); assert(p1.id == 1); assert(p1.firstName + p1.lastName.get() == "PatSmith"); assert(p1.gender == "unknown"); p.firstName = "Patricia"; sql << "update soci_test set first_name = :FIRST_NAME " "where id = :ID", use(p); // p should be unchanged assert(p.id == 1); assert(p.firstName == "Patricia"); assert(p.lastName.get() == "Smith"); // Note: gender is now "unknown" because of the mapping, not "" assert(p.gender == "unknown"); person p2; sql << "select * from soci_test", into(p2); assert(p2.id == 1); assert(p2.firstName + p2.lastName.get() == "PatriciaSmith"); // insert a second row so we can test fetching person p3; p3.id = 2; p3.firstName = "Joe"; p3.lastName = "Smith"; sql << "insert into soci_test(id, first_name, last_name, gender) " << "values(:ID, :FIRST_NAME, :LAST_NAME, :GENDER)", use(p3); person p4; statement st = (sql.prepare << "select * from soci_test order by id", into(p4)); st.execute(); bool gotData = st.fetch(); assert(gotData); assert(p4.id == 1); assert(p4.firstName == "Patricia"); gotData = st.fetch(); assert(gotData); assert(p4.id == 2); assert(p4.firstName == "Joe"); gotData = st.fetch(); assert(gotData == false); } // test with stored procedure { times100_procedure_creator procedureCreator(sql); person p; p.id = 1; p.firstName = "Pat"; p.lastName = "Smith"; procedure proc = (sql.prepare << "soci_test(:ID)", use(p)); proc.execute(1); assert(p.id == 100); assert(p.firstName == "Pat"); assert(p.lastName.get() == "Smith"); } // test with stored procedure which returns null { returns_null_procedure_creator procedureCreator(sql); std::string msg; person p; try { procedure proc = (sql.prepare << "soci_test(:FIRST_NAME)", use(p)); proc.execute(1); } catch (soci_error& e) { msg = e.what(); } assert(msg == "Null value not allowed for this type"); procedure proc = (sql.prepare << "soci_test(:GENDER)", use(p)); proc.execute(1); assert(p.gender == "unknown"); } std::cout << "test 10 passed" << std::endl; } // Experimental support for position based O/R Mapping // additional type for position-based test struct person2 { int id; std::string firstName; std::string lastName; std::string gender; }; // additional type for stream-like test struct person3 : person2 {}; namespace soci { // position-based conversion template<> struct type_conversion { typedef values base_type; static void from_base(values const &v, indicator /* ind */, person2 &p) { p.id = v.get(0); p.firstName = v.get(1); p.lastName = v.get(2); p.gender = v.get(3, "whoknows"); } // What about the "to" part? Does it make any sense to have it? }; // stream-like conversion template<> struct type_conversion { typedef values base_type; static void from_base(values const &v, indicator /* ind */, person3 &p) { v >> p.id >> p.firstName >> p.lastName >> p.gender; } // TODO: The "to" part is certainly needed. }; } void test11() { session sql(backEnd, connectString); person_table_creator tableCreator(sql); person p; p.id = 1; p.lastName = "Smith"; p.firstName = "Patricia"; sql << "insert into soci_test(id, first_name, last_name, gender) " << "values(:ID, :FIRST_NAME, :LAST_NAME, :GENDER)", use(p); // test position-based conversion person2 p3; sql << "select id, first_name, last_name, gender from soci_test", into(p3); assert(p3.id == 1); assert(p3.firstName + p3.lastName == "PatriciaSmith"); assert(p3.gender == "whoknows"); sql << "update soci_test set gender = 'F' where id = 1"; // additional test for stream-like conversion person3 p4; sql << "select id, first_name, last_name, gender from soci_test", into(p4); assert(p4.id == 1); assert(p4.firstName + p4.lastName == "PatriciaSmith"); assert(p4.gender == "F"); std::cout << "test 11 passed" << std::endl; } // // Backwards compatibility - support use of large strings with // columns of type LONG /// struct long_table_creator : public table_creator_base { long_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(l long)"; } }; void test12() { session sql(backEnd, connectString); long_table_creator creator(sql); const std::string::size_type max = 32768; std::string in(max, 'X'); sql << "insert into soci_test values(:l)", use(in); std::string out; sql << "select l from soci_test", into(out); assert(out.size() == max); assert(in == out); std::cout << "test 12 passed" << std::endl; } // test for modifiable and const use elements void test13() { session sql(backEnd, connectString); int i = 7; sql << "begin " "select 2 * :i into :i from dual; " "end;", use(i); assert(i == 14); const int j = 7; try { sql << "begin " "select 2 * :i into :i from dual;" " end;", use(j); assert(false); // should never get here } catch (soci_error const & e) { const std::string msg = e.what(); assert(msg == "Attempted modification of const use element"); } std::cout << "test 13 passed" << std::endl; } struct longlong_table_creator : table_creator_base { longlong_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val number(20))"; } }; // long long test void test14() { { session sql(backEnd, connectString); longlong_table_creator tableCreator(sql); long long v1 = 1000000000000LL; assert(v1 / 1000000 == 1000000); sql << "insert into soci_test(val) values(:val)", use(v1); long long v2 = 0LL; sql << "select val from soci_test", into(v2); assert(v2 == v1); } // vector { session sql(backEnd, connectString); longlong_table_creator tableCreator(sql); std::vector v1; v1.push_back(1000000000000LL); v1.push_back(1000000000001LL); v1.push_back(1000000000002LL); v1.push_back(1000000000003LL); v1.push_back(1000000000004LL); sql << "insert into soci_test(val) values(:val)", use(v1); std::vector v2(10); sql << "select val from soci_test order by val desc", into(v2); assert(v2.size() == 5); assert(v2[0] == 1000000000004LL); assert(v2[1] == 1000000000003LL); assert(v2[2] == 1000000000002LL); assert(v2[3] == 1000000000001LL); assert(v2[4] == 1000000000000LL); } std::cout << "test 14 passed" << std::endl; } // // Support for soci Common Tests // struct table_creator_one : public table_creator_base { table_creator_one(session & sql) : table_creator_base(sql) { sql << "create table soci_test(id number(10,0), val number(4,0), c char, " "str varchar2(20), sh number, ul number, d number, " "tm date, i1 number, i2 number, i3 number, name varchar2(20))"; } }; struct table_creator_two : public table_creator_base { table_creator_two(session & sql) : table_creator_base(sql) { sql << "create table soci_test(num_float number, num_int numeric(4,0)," " name varchar2(20), sometime date, chr char)"; } }; struct table_creator_three : public table_creator_base { table_creator_three(session & sql) : table_creator_base(sql) { sql << "create table soci_test(name varchar2(100) not null, " "phone varchar2(15))"; } }; struct table_creator_four : public table_creator_base { table_creator_four(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val number)"; } }; class test_context :public test_context_base { public: test_context(backend_factory const &backEnd, std::string const &connectString) : test_context_base(backEnd, connectString) {} table_creator_base* table_creator_1(session& s) const { return new table_creator_one(s); } table_creator_base* table_creator_2(session& s) const { return new table_creator_two(s); } table_creator_base* table_creator_3(session& s) const { return new table_creator_three(s); } table_creator_base* table_creator_4(session& s) const { return new table_creator_four(s); } std::string to_date_time(std::string const &datdt_string) const { return "to_date('" + datdt_string + "', 'YYYY-MM-DD HH24:MI:SS')"; } }; int main(int argc, char** argv) { #ifdef _MSC_VER // Redirect errors, unrecoverable problems, and assert() failures to STDERR, // instead of debug message window. // This hack is required to run asser()-driven tests by Buildbot. // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); #endif //_MSC_VER if (argc == 2) { connectString = argv[1]; } else { std::cout << "usage: " << argv[0] << " connectstring\n" << "example: " << argv[0] << " \'service=orcl user=scott password=tiger\'\n"; std::exit(1); } try { test_context tc(backEnd, connectString); common_tests tests(tc); tests.run(); std::cout << "\nsoci Oracle tests:\n\n"; test1(); test2(); test3(); test4(); test5(); test6(); test7(); test7inout(); test7outnull(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; } catch (std::exception const & e) { std::cout << e.what() << '\n'; } return EXIT_FAILURE; } soci-3.2.3/backends/oracle/test/Makefile.basic0000644000000000000000000000147412511361676017706 0ustar rootroot# The following variable is specific to this backend and its correct # values might depend on your environment - feel free to set it accordingly. ORACLEINCLUDEDIR = -I/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/rdbms/public ORACLELIBDIR = -L/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/lib ORACLELIBS = -lclntsh -lnnz10 # The rest of the Makefile is indepentent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long INCLUDEDIRS = -I.. -I../../../core -I../../../core/test ${ORACLEINCLUDEDIR} LIBDIRS = -L.. -L../../../core ${ORACLELIBDIR} LIBS = -lsoci_core -lsoci_oracle -ldl -lboost_date_time ${ORACLELIBS} test-oracle : test-oracle.cpp #../../../core/test/common-tests.h ${COMPILER} -o $@ $? ${CXXFLAGS} ${INCLUDEDIRS} ${LIBDIRS} ${LIBS} clean : rm -f *.o test-oracle soci-3.2.3/backends/oracle/test/CMakeLists.txt0000644000000000000000000000075612511361676017730 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend_test( BACKEND Oracle SOURCE test-oracle.cpp CONNSTR "dummy")soci-3.2.3/backends/oracle/vector-into-type.cpp0000644000000000000000000003110212511361676020132 0ustar rootroot// // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define soci_ORACLE_SOURCE #include "soci-oracle.h" #include "statement.h" #include "error.h" #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace soci::details::oracle; void oracle_vector_into_type_backend::prepare_indicators(std::size_t size) { if (size == 0) { throw soci_error("Vectors of size 0 are not allowed."); } indOCIHolderVec_.resize(size); indOCIHolders_ = &indOCIHolderVec_[0]; sizes_.resize(size); rCodes_.resize(size); } void oracle_vector_into_type_backend::define_by_pos( int &position, void *data, exchange_type type) { data_ = data; // for future reference type_ = type; // for future reference ub2 oracleType = 0; // dummy initialization to please the compiler sb4 size = 0; // also dummy switch (type) { // simple cases case x_char: { oracleType = SQLT_AFC; size = sizeof(char); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_short: { oracleType = SQLT_INT; size = sizeof(short); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_integer: { oracleType = SQLT_INT; size = sizeof(int); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_double: { oracleType = SQLT_FLT; size = sizeof(double); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; // cases that require adjustments and buffer management case x_long_long: { oracleType = SQLT_STR; std::vector *v = static_cast *>(data); colSize_ = 100; // arbitrary buffer size for each entry std::size_t const bufSize = colSize_ * v->size(); buf_ = new char[bufSize]; prepare_indicators(v->size()); size = static_cast(colSize_); data = buf_; } break; case x_unsigned_long_long: { oracleType = SQLT_STR; std::vector *v = static_cast *>(data); colSize_ = 100; // arbitrary buffer size for each entry std::size_t const bufSize = colSize_ * v->size(); buf_ = new char[bufSize]; prepare_indicators(v->size()); size = static_cast(colSize_); data = buf_; } break; case x_stdstring: { oracleType = SQLT_CHR; std::vector *v = static_cast *>(data); colSize_ = statement_.column_size(position) + 1; std::size_t bufSize = colSize_ * v->size(); buf_ = new char[bufSize]; prepare_indicators(v->size()); size = static_cast(colSize_); data = buf_; } break; case x_stdtm: { oracleType = SQLT_DAT; std::vector *v = static_cast *>(data); prepare_indicators(v->size()); size = 7; // 7 is the size of SQLT_DAT std::size_t bufSize = size * v->size(); buf_ = new char[bufSize]; data = buf_; } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } sword res = OCIDefineByPos(statement_.stmtp_, &defnp_, statement_.session_.errhp_, position++, data, size, oracleType, indOCIHolders_, &sizes_[0], &rCodes_[0], OCI_DEFAULT); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, statement_.session_.errhp_); } } void oracle_vector_into_type_backend::pre_fetch() { // nothing to do for the supported types } void oracle_vector_into_type_backend::post_fetch(bool gotData, indicator *ind) { if (gotData) { // first, deal with data // only std::string, std::tm, long long and Statement need special handling if (type_ == x_stdstring) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { if (indOCIHolderVec_[i] != -1) { v[i].assign(pos, sizes_[i]); } pos += colSize_; } } else if (type_ == x_long_long) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { if (indOCIHolderVec_[i] != -1) { v[i] = std::strtoll(pos, NULL, 10); } pos += colSize_; } } else if (type_ == x_unsigned_long_long) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { if (indOCIHolderVec_[i] != -1) { v[i] = std::strtoull(pos, NULL, 10); } pos += colSize_; } } else if (type_ == x_stdtm) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); ub1 *pos = reinterpret_cast(buf_); std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { if (indOCIHolderVec_[i] == -1) { pos += 7; // size of SQLT_DAT } else { std::tm t; t.tm_isdst = -1; t.tm_year = (*pos++ - 100) * 100; t.tm_year += *pos++ - 2000; t.tm_mon = *pos++ - 1; t.tm_mday = *pos++; t.tm_hour = *pos++ - 1; t.tm_min = *pos++ - 1; t.tm_sec = *pos++ - 1; // normalize and compute the remaining fields std::mktime(&t); v[i] = t; } } } else if (type_ == x_statement) { statement *st = static_cast(data_); st->define_and_bind(); } // then - deal with indicators if (ind != NULL) { std::size_t const indSize = statement_.get_number_of_rows(); for (std::size_t i = 0; i != indSize; ++i) { if (indOCIHolderVec_[i] == 0) { ind[i] = i_ok; } else if (indOCIHolderVec_[i] == -1) { ind[i] = i_null; } else { ind[i] = i_truncated; } } } else { std::size_t const indSize = indOCIHolderVec_.size(); for (std::size_t i = 0; i != indSize; ++i) { if (indOCIHolderVec_[i] == -1) { // fetched null and no indicator - programming error! throw soci_error( "Null value fetched and no indicator defined."); } } } } else // gotData == false { // nothing to do here, vectors are truncated anyway } } void oracle_vector_into_type_backend::resize(std::size_t sz) { switch (type_) { // simple cases case x_char: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_short: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_integer: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_long_long: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_unsigned_long_long: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_double: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_stdstring: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_stdtm: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } } std::size_t oracle_vector_into_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type_) { // simple cases case x_char: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_short: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_integer: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_long_long: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_unsigned_long_long: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_double: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_stdstring: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_stdtm: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } return sz; } void oracle_vector_into_type_backend::clean_up() { if (defnp_ != NULL) { OCIHandleFree(defnp_, OCI_HTYPE_DEFINE); defnp_ = NULL; } if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } } soci-3.2.3/backends/oracle/CMakeLists.txt0000644000000000000000000000116312511362240016726 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend(Oracle DEPENDS Oracle HEADERS soci-oracle.h error.h DESCRIPTION "SOCI backend for Oracle 10+" AUTHORS "Maciej Sobczak, Stephen Hutton" MAINTAINERS "Maciej Sobczak") add_subdirectory(test) soci-3.2.3/backends/odbc/0000755000000000000000000000000012511401144013624 5ustar rootrootsoci-3.2.3/backends/odbc/soci-odbc.h0000644000000000000000000003133312511401144015642 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_ODBC_H_INCLUDED #define SOCI_ODBC_H_INCLUDED #ifdef _WIN32 # ifdef SOCI_DLL # ifdef SOCI_ODBC_SOURCE # define SOCI_ODBC_DECL __declspec(dllexport) # else # define SOCI_ODBC_DECL __declspec(dllimport) # endif // SOCI_ODBC_SOURCE # endif // SOCI_DLL #endif // _WIN32 // // If SOCI_ODBC_DECL isn't defined yet define it now #ifndef SOCI_ODBC_DECL # define SOCI_ODBC_DECL #endif #include #include #include #if defined(_MSC_VER) || defined(__MINGW32__) #include #include #endif #include // ODBC #include // strcpy() namespace soci { // TODO: Do we want to make it a part of public interface? --mloskot namespace details { std::size_t const odbc_max_buffer_length = 100 * 1024 * 1024; } // Option allowing to specify the "driver completion" parameter of // SQLDriverConnect(). Its possible values are the same as the allowed values // for this parameter in the official ODBC, i.e. one of SQL_DRIVER_XXX (in // string form as all options are strings currently). extern SOCI_ODBC_DECL char const * odbc_option_driver_complete; struct odbc_statement_backend; // Helper of into and use backends. class odbc_standard_type_backend_base { protected: odbc_standard_type_backend_base(odbc_statement_backend &st) : statement_(st) {} // Check if we need to pass 64 bit integers as strings to the database as // some drivers don't support them directly. inline bool use_string_for_bigint() const; // If we do need to use strings for 64 bit integers, this constant defines // the maximal string length needed. enum { // This is the length of decimal representation of UINT64_MAX + 1. max_bigint_length = 21 }; odbc_statement_backend &statement_; }; struct odbc_standard_into_type_backend : details::standard_into_type_backend, private odbc_standard_type_backend_base { odbc_standard_into_type_backend(odbc_statement_backend &st) : odbc_standard_type_backend_base(st), buf_(0) {} virtual void define_by_pos(int &position, void *data, details::exchange_type type); virtual void pre_fetch(); virtual void post_fetch(bool gotData, bool calledFromFetch, indicator *ind); virtual void clean_up(); char *buf_; // generic buffer void *data_; details::exchange_type type_; int position_; SQLSMALLINT odbcType_; SQLLEN valueLen_; }; struct odbc_vector_into_type_backend : details::vector_into_type_backend, private odbc_standard_type_backend_base { odbc_vector_into_type_backend(odbc_statement_backend &st) : odbc_standard_type_backend_base(st), indHolders_(NULL), data_(NULL), buf_(NULL) {} virtual void define_by_pos(int &position, void *data, details::exchange_type type); virtual void pre_fetch(); virtual void post_fetch(bool gotData, indicator *ind); virtual void resize(std::size_t sz); virtual std::size_t size(); virtual void clean_up(); // helper function for preparing indicators // (as part of the define_by_pos) void prepare_indicators(std::size_t size); SQLLEN *indHolders_; std::vector indHolderVec_; void *data_; char *buf_; // generic buffer details::exchange_type type_; std::size_t colSize_; // size of the string column (used for strings) SQLSMALLINT odbcType_; }; struct odbc_standard_use_type_backend : details::standard_use_type_backend, private odbc_standard_type_backend_base { odbc_standard_use_type_backend(odbc_statement_backend &st) : odbc_standard_type_backend_base(st), position_(-1), data_(0), buf_(0), indHolder_(0) {} virtual void bind_by_pos(int &position, void *data, details::exchange_type type, bool readOnly); virtual void bind_by_name(std::string const &name, void *data, details::exchange_type type, bool readOnly); virtual void pre_use(indicator const *ind); virtual void post_use(bool gotData, indicator *ind); virtual void clean_up(); // Return the pointer to the buffer containing data to be used by ODBC. // This can be either data_ itself or buf_, that is allocated by this // function if necessary. // // Also fill in the size of the data and SQL and C types of it. void* prepare_for_bind(SQLLEN &size, SQLSMALLINT &sqlType, SQLSMALLINT &cType); int position_; void *data_; details::exchange_type type_; char *buf_; SQLLEN indHolder_; }; struct odbc_vector_use_type_backend : details::vector_use_type_backend, private odbc_standard_type_backend_base { odbc_vector_use_type_backend(odbc_statement_backend &st) : odbc_standard_type_backend_base(st), indHolders_(NULL), data_(NULL), buf_(NULL) {} // helper function for preparing indicators // (as part of the define_by_pos) void prepare_indicators(std::size_t size); // common part for bind_by_pos and bind_by_name void prepare_for_bind(void *&data, SQLUINTEGER &size, SQLSMALLINT &sqlType, SQLSMALLINT &cType); void bind_helper(int &position, void *data, details::exchange_type type); virtual void bind_by_pos(int &position, void *data, details::exchange_type type); virtual void bind_by_name(std::string const &name, void *data, details::exchange_type type); virtual void pre_use(indicator const *ind); virtual std::size_t size(); virtual void clean_up(); SQLLEN *indHolders_; std::vector indHolderVec_; void *data_; details::exchange_type type_; char *buf_; // generic buffer std::size_t colSize_; // size of the string column (used for strings) // used for strings only std::size_t maxSize_; }; struct odbc_session_backend; struct odbc_statement_backend : details::statement_backend { odbc_statement_backend(odbc_session_backend &session); virtual void alloc(); virtual void clean_up(); virtual void prepare(std::string const &query, details::statement_type eType); virtual exec_fetch_result execute(int number); virtual exec_fetch_result fetch(int number); virtual long long get_affected_rows(); virtual int get_number_of_rows(); virtual std::string rewrite_for_procedure_call(std::string const &query); virtual int prepare_for_describe(); virtual void describe_column(int colNum, data_type &dtype, std::string &columnName); // helper for defining into vector std::size_t column_size(int position); virtual odbc_standard_into_type_backend * make_into_type_backend(); virtual odbc_standard_use_type_backend * make_use_type_backend(); virtual odbc_vector_into_type_backend * make_vector_into_type_backend(); virtual odbc_vector_use_type_backend * make_vector_use_type_backend(); odbc_session_backend &session_; SQLHSTMT hstmt_; SQLULEN numRowsFetched_; bool hasVectorUseElements_; bool boundByName_; bool boundByPos_; long long rowsAffected_; // number of rows affected by the last operation std::string query_; std::vector names_; // list of names for named binds }; struct odbc_rowid_backend : details::rowid_backend { odbc_rowid_backend(odbc_session_backend &session); ~odbc_rowid_backend(); }; struct odbc_blob_backend : details::blob_backend { odbc_blob_backend(odbc_session_backend &session); ~odbc_blob_backend(); virtual std::size_t get_len(); virtual std::size_t read(std::size_t offset, char *buf, std::size_t toRead); virtual std::size_t write(std::size_t offset, char const *buf, std::size_t toWrite); virtual std::size_t append(char const *buf, std::size_t toWrite); virtual void trim(std::size_t newLen); odbc_session_backend &session_; }; struct odbc_session_backend : details::session_backend { odbc_session_backend(connection_parameters const & parameters); ~odbc_session_backend(); virtual void begin(); virtual void commit(); virtual void rollback(); virtual bool get_next_sequence_value(session & s, std::string const & sequence, long & value); virtual bool get_last_insert_id(session & s, std::string const & table, long & value); virtual std::string get_backend_name() const { return "odbc"; } void reset_transaction(); void clean_up(); virtual odbc_statement_backend * make_statement_backend(); virtual odbc_rowid_backend * make_rowid_backend(); virtual odbc_blob_backend * make_blob_backend(); enum database_product { prod_uninitialized, // Never returned by get_database_product(). prod_firebird, prod_mssql, prod_mysql, prod_oracle, prod_postgresql, prod_sqlite, prod_unknown = -1 }; // Determine the type of the database we're connected to. database_product get_database_product(); // Return full ODBC connection string. std::string get_connection_string() const { return connection_string_; } SQLHENV henv_; SQLHDBC hdbc_; std::string connection_string_; database_product product_; }; class SOCI_ODBC_DECL odbc_soci_error : public soci_error { SQLCHAR message_[SQL_MAX_MESSAGE_LENGTH + 1]; SQLCHAR sqlstate_[SQL_SQLSTATE_SIZE + 1]; SQLINTEGER sqlcode_; public: odbc_soci_error(SQLSMALLINT htype, SQLHANDLE hndl, std::string const & msg) : soci_error(interpret_odbc_error(htype, hndl, msg)) { } SQLCHAR const * odbc_error_code() const { return sqlstate_; } SQLINTEGER native_error_code() const { return sqlcode_; } SQLCHAR const * odbc_error_message() const { return message_; } private: std::string interpret_odbc_error(SQLSMALLINT htype, SQLHANDLE hndl, std::string const& msg) { std::ostringstream ss(msg, std::ostringstream::app); const char* socierror = NULL; SQLSMALLINT length, i = 1; switch ( SQLGetDiagRecA(htype, hndl, i, sqlstate_, &sqlcode_, message_, SQL_MAX_MESSAGE_LENGTH + 1, &length) ) { case SQL_SUCCESS: // The error message was successfully retrieved. break; case SQL_INVALID_HANDLE: socierror = "[SOCI]: Invalid handle."; break; case SQL_ERROR: socierror = "[SOCI]: SQLGetDiagRec() error."; break; case SQL_SUCCESS_WITH_INFO: socierror = "[SOCI]: Error message too long."; break; case SQL_NO_DATA: socierror = "[SOCI]: No error."; break; default: socierror = "[SOCI]: Unexpected SQLGetDiagRec() return value."; break; } if (socierror) { // Use our own error message if we failed to retrieve the ODBC one. strcpy(reinterpret_cast(message_), socierror); // Use "General warning" SQLSTATE code. strcpy(reinterpret_cast(sqlstate_), "01000"); sqlcode_ = 0; } ss << ": " << message_ << " (" << sqlstate_ << ")"; return ss.str(); } }; inline bool is_odbc_error(SQLRETURN rc) { if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO && rc != SQL_NO_DATA) { return true; } else { return false; } } inline bool odbc_standard_type_backend_base::use_string_for_bigint() const { // Oracle ODBC driver doesn't support SQL_C_[SU]BIGINT data types // (see appendix G.1 of Oracle Database Administrator's reference at // http://docs.oracle.com/cd/B19306_01/server.102/b15658/app_odbc.htm), // so we need a special workaround for this case and we represent 64 // bit integers as strings and rely on ODBC driver for transforming // them to SQL_NUMERIC. return statement_.session_.get_database_product() == odbc_session_backend::prod_oracle; } struct odbc_backend_factory : backend_factory { odbc_backend_factory() {} virtual odbc_session_backend * make_session( connection_parameters const & parameters) const; }; extern SOCI_ODBC_DECL odbc_backend_factory const odbc; extern "C" { // for dynamic backend loading SOCI_ODBC_DECL backend_factory const * factory_odbc(); SOCI_ODBC_DECL void register_factory_odbc(); } // extern "C" } // namespace soci #endif // SOCI_EMPTY_H_INCLUDED soci-3.2.3/backends/odbc/makefile.msvc0000644000000000000000000000255712505151606016314 0ustar rootroot# The following variable is specific to this backend and its correct # values might depend on your environment - feel free to set it accordingly. ODBCINCLUDEDIR="C:\Program Files\Microsoft Platform SDK\Include" # The rest of the Makefile is indepentent of the target environment. COMPILER = cl CXXFLAGS = /nologo /EHsc /D_CRT_SECURE_NO_DEPRECATE INCLUDEDIRS = /I..\..\core /I$(ODBCINCLUDEDIR) OBJECTS = blob.obj factory.obj row-id.obj session.obj standard-into-type.obj \ standard-use-type.obj statement.obj vector-into-type.obj \ vector-use-type.obj soci-odbc.lib : $(OBJECTS) lib /NOLOGO /OUT:$@ $? del *.obj blob.obj : blob.cpp $(COMPILER) /c $? $(CXXFLAGS) $(INCLUDEDIRS) factory.obj : factory.cpp $(COMPILER) /c $? $(CXXFLAGS) $(INCLUDEDIRS) row-id.obj : row-id.cpp $(COMPILER) /c $? $(CXXFLAGS) $(INCLUDEDIRS) session.obj : session.cpp $(COMPILER) /c $? $(CXXFLAGS) $(INCLUDEDIRS) standard-into-type.obj : standard-into-type.cpp $(COMPILER) /c $? $(CXXFLAGS) $(INCLUDEDIRS) standard-use-type.obj : standard-use-type.cpp $(COMPILER) /c $? $(CXXFLAGS) $(INCLUDEDIRS) statement.obj : statement.cpp $(COMPILER) /c $? $(CXXFLAGS) $(INCLUDEDIRS) vector-into-type.obj : vector-into-type.cpp $(COMPILER) /c $? $(CXXFLAGS) $(INCLUDEDIRS) vector-use-type.obj : vector-use-type.cpp $(COMPILER) /c $? $(CXXFLAGS) $(INCLUDEDIRS) clean : del soci-odbc.lib soci-odbc.dll soci-3.2.3/backends/odbc/blob.cpp0000644000000000000000000000205012511361676015262 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ODBC_SOURCE #include "soci-odbc.h" using namespace soci; using namespace soci::details; odbc_blob_backend::odbc_blob_backend(odbc_session_backend &session) : session_(session) { // ... } odbc_blob_backend::~odbc_blob_backend() { // ... } std::size_t odbc_blob_backend::get_len() { // ... return 0; } std::size_t odbc_blob_backend::read( std::size_t /* offset */, char * /* buf */, std::size_t /* toRead */) { // ... return 0; } std::size_t odbc_blob_backend::write( std::size_t /* offset */, char const * /* buf */, std::size_t /* toWrite */) { // ... return 0; } std::size_t odbc_blob_backend::append( char const * /* buf */, std::size_t /* toWrite */) { // ... return 0; } void odbc_blob_backend::trim(std::size_t /* newLen */) { // ... } soci-3.2.3/backends/odbc/statement.cpp0000644000000000000000000002326612511361676016364 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ODBC_SOURCE #include "soci-odbc.h" #include #include #include #ifdef _MSC_VER // disables the warning about converting int to void*. This is a 64 bit compatibility // warning, but odbc requires the value to be converted on this line // SQLSetStmtAttr(hstmt_, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)number, 0); #pragma warning(disable:4312) #endif using namespace soci; using namespace soci::details; odbc_statement_backend::odbc_statement_backend(odbc_session_backend &session) : session_(session), hstmt_(0), numRowsFetched_(0), hasVectorUseElements_(false), boundByName_(false), boundByPos_(false), rowsAffected_(-1LL) { } void odbc_statement_backend::alloc() { SQLRETURN rc; // Allocate environment handle rc = SQLAllocHandle(SQL_HANDLE_STMT, session_.hdbc_, &hstmt_); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_DBC, session_.hdbc_, "Allocating statement"); } } void odbc_statement_backend::clean_up() { rowsAffected_ = -1LL; SQLFreeHandle(SQL_HANDLE_STMT, hstmt_); } void odbc_statement_backend::prepare(std::string const & query, statement_type /* eType */) { // rewrite the query by transforming all named parameters into // the ODBC numbers ones (:abc -> $1, etc.) enum { eNormal, eInQuotes, eInName, eInAccessDate } state = eNormal; std::string name; query_.reserve(query.length()); for (std::string::const_iterator it = query.begin(), end = query.end(); it != end; ++it) { switch (state) { case eNormal: if (*it == '\'') { query_ += *it; state = eInQuotes; } else if (*it == '#') { query_ += *it; state = eInAccessDate; } else if (*it == ':') { state = eInName; } else // regular character, stay in the same state { query_ += *it; } break; case eInQuotes: if (*it == '\'') { query_ += *it; state = eNormal; } else // regular quoted character { query_ += *it; } break; case eInName: if (std::isalnum(*it) || *it == '_') { name += *it; } else // end of name { names_.push_back(name); name.clear(); query_ += "?"; query_ += *it; state = eNormal; } break; case eInAccessDate: if (*it == '#') { query_ += *it; state = eNormal; } else // regular quoted character { query_ += *it; } break; } } if (state == eInName) { names_.push_back(name); query_ += "?"; } SQLRETURN rc = SQLPrepare(hstmt_, (SQLCHAR*)query_.c_str(), (SQLINTEGER)query_.size()); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_STMT, hstmt_, query_.c_str()); } } statement_backend::exec_fetch_result odbc_statement_backend::execute(int number) { // Store the number of rows processed by this call. SQLULEN rows_processed = 0; if (hasVectorUseElements_) { SQLSetStmtAttr(hstmt_, SQL_ATTR_PARAMS_PROCESSED_PTR, &rows_processed, 0); } // if we are called twice for the same statement we need to close the open // cursor or an "invalid cursor state" error will occur on execute SQLCloseCursor(hstmt_); SQLRETURN rc = SQLExecute(hstmt_); if (is_odbc_error(rc)) { // If executing bulk operation a partial // number of rows affected may be available. if (hasVectorUseElements_) { rowsAffected_ = 0; do { SQLLEN res = 0; // SQLRowCount will return error after a partially executed statement. // SQL_DIAG_ROW_COUNT returns the same info but must be collected immediatelly after the execution. rc = SQLGetDiagField(SQL_HANDLE_STMT, hstmt_, 0, SQL_DIAG_ROW_COUNT, &res, 0, NULL); if (!is_odbc_error(rc) && res > 0) // 'res' will be -1 for the where the statement failed. { rowsAffected_ += res; } --rows_processed; // Avoid unnecessary calls to SQLGetDiagField } // Move forward to the next result while there are rows processed. while (rows_processed > 0 && SQLMoreResults(hstmt_) == SQL_SUCCESS); } throw odbc_soci_error(SQL_HANDLE_STMT, hstmt_, "Statement Execute"); } // We should preserve the number of rows affected here // where we know for sure that a bulk operation was executed. else { rowsAffected_ = 0; do { SQLLEN res = 0; SQLRETURN rc = SQLRowCount(hstmt_, &res); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_STMT, hstmt_, "Getting number of affected rows"); } rowsAffected_ += res; } // Move forward to the next result if executing a bulk operation. while (hasVectorUseElements_ && SQLMoreResults(hstmt_) == SQL_SUCCESS); } SQLSMALLINT colCount; SQLNumResultCols(hstmt_, &colCount); if (number > 0 && colCount > 0) { return fetch(number); } return ef_success; } statement_backend::exec_fetch_result odbc_statement_backend::fetch(int number) { numRowsFetched_ = 0; SQLULEN const row_array_size = static_cast(number); SQLSetStmtAttr(hstmt_, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0); SQLSetStmtAttr(hstmt_, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)row_array_size, 0); SQLSetStmtAttr(hstmt_, SQL_ATTR_ROWS_FETCHED_PTR, &numRowsFetched_, 0); SQLRETURN rc = SQLFetch(hstmt_); if (SQL_NO_DATA == rc) { return ef_no_data; } if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_STMT, hstmt_, "Statement Fetch"); } return ef_success; } long long odbc_statement_backend::get_affected_rows() { return rowsAffected_; } int odbc_statement_backend::get_number_of_rows() { return numRowsFetched_; } std::string odbc_statement_backend::rewrite_for_procedure_call( std::string const &query) { return query; } int odbc_statement_backend::prepare_for_describe() { SQLSMALLINT numCols; SQLNumResultCols(hstmt_, &numCols); return numCols; } void odbc_statement_backend::describe_column(int colNum, data_type & type, std::string & columnName) { SQLCHAR colNameBuffer[2048]; SQLSMALLINT colNameBufferOverflow; SQLSMALLINT dataType; SQLULEN colSize; SQLSMALLINT decDigits; SQLSMALLINT isNullable; SQLRETURN rc = SQLDescribeCol(hstmt_, static_cast(colNum), colNameBuffer, 2048, &colNameBufferOverflow, &dataType, &colSize, &decDigits, &isNullable); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_STMT, hstmt_, "describe Column"); } char const *name = reinterpret_cast(colNameBuffer); columnName.assign(name, std::strlen(name)); switch (dataType) { case SQL_TYPE_DATE: case SQL_TYPE_TIME: case SQL_TYPE_TIMESTAMP: type = dt_date; break; case SQL_DOUBLE: case SQL_DECIMAL: case SQL_REAL: case SQL_FLOAT: case SQL_NUMERIC: type = dt_double; break; case SQL_TINYINT: case SQL_SMALLINT: case SQL_INTEGER: type = dt_integer; break; case SQL_BIGINT: type = dt_long_long; break; case SQL_CHAR: case SQL_VARCHAR: case SQL_LONGVARCHAR: default: type = dt_string; break; } } std::size_t odbc_statement_backend::column_size(int colNum) { SQLCHAR colNameBuffer[2048]; SQLSMALLINT colNameBufferOverflow; SQLSMALLINT dataType; SQLULEN colSize; SQLSMALLINT decDigits; SQLSMALLINT isNullable; SQLRETURN rc = SQLDescribeCol(hstmt_, static_cast(colNum), colNameBuffer, 2048, &colNameBufferOverflow, &dataType, &colSize, &decDigits, &isNullable); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_STMT, hstmt_, "column size"); } return colSize; } odbc_standard_into_type_backend * odbc_statement_backend::make_into_type_backend() { return new odbc_standard_into_type_backend(*this); } odbc_standard_use_type_backend * odbc_statement_backend::make_use_type_backend() { return new odbc_standard_use_type_backend(*this); } odbc_vector_into_type_backend * odbc_statement_backend::make_vector_into_type_backend() { return new odbc_vector_into_type_backend(*this); } odbc_vector_use_type_backend * odbc_statement_backend::make_vector_use_type_backend() { hasVectorUseElements_ = true; return new odbc_vector_use_type_backend(*this); } soci-3.2.3/backends/odbc/vector-use-type.cpp0000644000000000000000000003146612511361676017434 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ODBC_SOURCE #include "soci-odbc.h" #include #include #include #include #include #include #include #ifdef _MSC_VER // disables the warning about converting int to void*. This is a 64 bit compatibility // warning, but odbc requires the value to be converted on this line // SQLSetStmtAttr(statement_.hstmt_, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)arraySize, 0); #pragma warning(disable:4312) #endif using namespace soci; using namespace soci::details; void odbc_vector_use_type_backend::prepare_indicators(std::size_t size) { if (size == 0) { throw soci_error("Vectors of size 0 are not allowed."); } indHolderVec_.resize(size); indHolders_ = &indHolderVec_[0]; } void odbc_vector_use_type_backend::prepare_for_bind(void *&data, SQLUINTEGER &size, SQLSMALLINT &sqlType, SQLSMALLINT &cType) { switch (type_) { // simple cases case x_short: { sqlType = SQL_SMALLINT; cType = SQL_C_SSHORT; size = sizeof(short); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_integer: { sqlType = SQL_INTEGER; cType = SQL_C_SLONG; size = sizeof(SQLINTEGER); assert(sizeof(SQLINTEGER) == sizeof(int)); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_long_long: { std::vector *vp = static_cast *>(data); std::vector &v(*vp); std::size_t const vsize = v.size(); prepare_indicators(vsize); if (use_string_for_bigint()) { sqlType = SQL_NUMERIC; cType = SQL_C_CHAR; size = max_bigint_length; buf_ = new char[size * vsize]; data = buf_; } else // Normal case, use ODBC support. { sqlType = SQL_BIGINT; cType = SQL_C_SBIGINT; size = sizeof(long long); data = &v[0]; } } break; case x_unsigned_long_long: { std::vector *vp = static_cast *>(data); std::vector &v(*vp); std::size_t const vsize = v.size(); prepare_indicators(vsize); if (use_string_for_bigint()) { sqlType = SQL_NUMERIC; cType = SQL_C_CHAR; size = max_bigint_length; buf_ = new char[size * vsize]; data = buf_; } else // Normal case, use ODBC support. { sqlType = SQL_BIGINT; cType = SQL_C_SBIGINT; size = sizeof(unsigned long long); data = &v[0]; } } break; case x_double: { sqlType = SQL_DOUBLE; cType = SQL_C_DOUBLE; size = sizeof(double); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; // cases that require adjustments and buffer management case x_char: { std::vector *vp = static_cast *>(data); std::size_t const vsize = vp->size(); prepare_indicators(vsize); size = sizeof(char) * 2; buf_ = new char[size * vsize]; char *pos = buf_; for (std::size_t i = 0; i != vsize; ++i) { *pos++ = (*vp)[i]; *pos++ = 0; } sqlType = SQL_CHAR; cType = SQL_C_CHAR; data = buf_; } break; case x_stdstring: { sqlType = SQL_CHAR; cType = SQL_C_CHAR; std::vector *vp = static_cast *>(data); std::vector &v(*vp); std::size_t maxSize = 0; std::size_t const vecSize = v.size(); prepare_indicators(vecSize); for (std::size_t i = 0; i != vecSize; ++i) { std::size_t sz = v[i].length() + 1; // add one for null indHolderVec_[i] = static_cast(sz); maxSize = sz > maxSize ? sz : maxSize; } buf_ = new char[maxSize * vecSize]; memset(buf_, 0, maxSize * vecSize); char *pos = buf_; for (std::size_t i = 0; i != vecSize; ++i) { strncpy(pos, v[i].c_str(), v[i].length()); pos += maxSize; } data = buf_; size = static_cast(maxSize); } break; case x_stdtm: { std::vector *vp = static_cast *>(data); prepare_indicators(vp->size()); buf_ = new char[sizeof(TIMESTAMP_STRUCT) * vp->size()]; sqlType = SQL_TYPE_TIMESTAMP; cType = SQL_C_TYPE_TIMESTAMP; data = buf_; size = 19; // This number is not the size in bytes, but the number // of characters in the date if it was written out // yyyy-mm-dd hh:mm:ss } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } colSize_ = size; } void odbc_vector_use_type_backend::bind_helper(int &position, void *data, exchange_type type) { data_ = data; // for future reference type_ = type; // for future reference SQLSMALLINT sqlType; SQLSMALLINT cType; SQLUINTEGER size; prepare_for_bind(data, size, sqlType, cType); SQLULEN const arraySize = static_cast(indHolderVec_.size()); SQLSetStmtAttr(statement_.hstmt_, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)arraySize, 0); SQLRETURN rc = SQLBindParameter(statement_.hstmt_, static_cast(position++), SQL_PARAM_INPUT, cType, sqlType, size, 0, static_cast(data), size, indHolders_); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_STMT, statement_.hstmt_, "Error while binding value to column"); } } void odbc_vector_use_type_backend::bind_by_pos(int &position, void *data, exchange_type type) { if (statement_.boundByName_) { throw soci_error( "Binding for use elements must be either by position or by name."); } bind_helper(position, data, type); statement_.boundByPos_ = true; } void odbc_vector_use_type_backend::bind_by_name( std::string const &name, void *data, exchange_type type) { if (statement_.boundByPos_) { throw soci_error( "Binding for use elements must be either by position or by name."); } int position = -1; int count = 1; for (std::vector::iterator it = statement_.names_.begin(); it != statement_.names_.end(); ++it) { if (*it == name) { position = count; break; } count++; } if (position != -1) { bind_helper(position, data, type); } else { std::ostringstream ss; ss << "Unable to find name '" << name << "' to bind to"; throw soci_error(ss.str().c_str()); } statement_.boundByName_ = true; } void odbc_vector_use_type_backend::pre_use(indicator const *ind) { // first deal with data if (type_ == x_stdtm) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { std::tm t = v[i]; TIMESTAMP_STRUCT * ts = reinterpret_cast(pos); ts->year = static_cast(t.tm_year + 1900); ts->month = static_cast(t.tm_mon + 1); ts->day = static_cast(t.tm_mday); ts->hour = static_cast(t.tm_hour); ts->minute = static_cast(t.tm_min); ts->second = static_cast(t.tm_sec); ts->fraction = 0; pos += sizeof(TIMESTAMP_STRUCT); } } else if (type_ == x_long_long && use_string_for_bigint()) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { snprintf(pos, max_bigint_length, "%" LL_FMT_FLAGS "d", v[i]); pos += max_bigint_length; } } else if (type_ == x_unsigned_long_long && use_string_for_bigint()) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { snprintf(pos, max_bigint_length, "%" LL_FMT_FLAGS "u", v[i]); pos += max_bigint_length; } } // then handle indicators if (ind != NULL) { std::size_t const vsize = size(); for (std::size_t i = 0; i != vsize; ++i, ++ind) { if (*ind == i_null) { indHolderVec_[i] = SQL_NULL_DATA; // null } else { // for strings we have already set the values if (type_ != x_stdstring) { indHolderVec_[i] = SQL_NTS; // value is OK } } } } else { // no indicators - treat all fields as OK std::size_t const vsize = size(); for (std::size_t i = 0; i != vsize; ++i, ++ind) { // for strings we have already set the values if (type_ != x_stdstring) { indHolderVec_[i] = SQL_NTS; // value is OK } } } } std::size_t odbc_vector_use_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type_) { // simple cases case x_char: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_short: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_integer: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_long_long: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_unsigned_long_long: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_double: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_stdstring: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_stdtm: { std::vector *vp = static_cast *>(data_); sz = vp->size(); } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } return sz; } void odbc_vector_use_type_backend::clean_up() { if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } } soci-3.2.3/backends/odbc/standard-use-type.cpp0000644000000000000000000001517712511361676017733 0ustar rootroot// Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #define SOCI_ODBC_SOURCE #include #include "soci-odbc.h" #include #include #include #include #include using namespace soci; using namespace soci::details; #ifdef _MSC_VER #pragma warning(disable:4996) #define snprintf _snprintf #endif void* odbc_standard_use_type_backend::prepare_for_bind( SQLLEN &size, SQLSMALLINT &sqlType, SQLSMALLINT &cType) { switch (type_) { // simple cases case x_short: sqlType = SQL_SMALLINT; cType = SQL_C_SSHORT; size = sizeof(short); break; case x_integer: sqlType = SQL_INTEGER; cType = SQL_C_SLONG; size = sizeof(int); break; case x_long_long: if (use_string_for_bigint()) { sqlType = SQL_NUMERIC; cType = SQL_C_CHAR; size = max_bigint_length; buf_ = new char[size]; snprintf(buf_, size, "%" LL_FMT_FLAGS "d", *static_cast(data_)); indHolder_ = SQL_NTS; } else // Normal case, use ODBC support. { sqlType = SQL_BIGINT; cType = SQL_C_SBIGINT; size = sizeof(long long); } break; case x_unsigned_long_long: if (use_string_for_bigint()) { sqlType = SQL_NUMERIC; cType = SQL_C_CHAR; size = max_bigint_length; buf_ = new char[size]; snprintf(buf_, size, "%" LL_FMT_FLAGS "u", *static_cast(data_)); indHolder_ = SQL_NTS; } else // Normal case, use ODBC support. { sqlType = SQL_BIGINT; cType = SQL_C_UBIGINT; size = sizeof(unsigned long long); } break; case x_double: sqlType = SQL_DOUBLE; cType = SQL_C_DOUBLE; size = sizeof(double); break; case x_char: sqlType = SQL_CHAR; cType = SQL_C_CHAR; size = 2; buf_ = new char[size]; buf_[0] = *static_cast(data_); buf_[1] = '\0'; indHolder_ = SQL_NTS; break; case x_stdstring: { std::string* s = static_cast(data_); sqlType = SQL_VARCHAR; cType = SQL_C_CHAR; size = s->size(); buf_ = new char[size+1]; memcpy(buf_, s->c_str(), size); buf_[size++] = '\0'; indHolder_ = SQL_NTS; } break; case x_stdtm: { std::tm *t = static_cast(data_); sqlType = SQL_TIMESTAMP; cType = SQL_C_TIMESTAMP; buf_ = new char[sizeof(TIMESTAMP_STRUCT)]; size = 19; // This number is not the size in bytes, but the number // of characters in the date if it was written out // yyyy-mm-dd hh:mm:ss TIMESTAMP_STRUCT * ts = reinterpret_cast(buf_); ts->year = static_cast(t->tm_year + 1900); ts->month = static_cast(t->tm_mon + 1); ts->day = static_cast(t->tm_mday); ts->hour = static_cast(t->tm_hour); ts->minute = static_cast(t->tm_min); ts->second = static_cast(t->tm_sec); ts->fraction = 0; } break; case x_blob: { // sqlType = SQL_VARBINARY; // cType = SQL_C_BINARY; // BLOB *b = static_cast(data); // odbc_blob_backend *bbe // = static_cast(b->getBackEnd()); // size = 0; // indHolder_ = size; //TODO data = &bbe->lobp_; } break; case x_statement: case x_rowid: // Unsupported data types. return NULL; } // Return either the pointer to C++ data itself or the buffer that we // allocated, if any. return buf_ ? buf_ : data_; } void odbc_standard_use_type_backend::bind_by_pos( int &position, void *data, exchange_type type, bool /* readOnly */) { if (statement_.boundByName_) { throw soci_error( "Binding for use elements must be either by position or by name."); } position_ = position++; data_ = data; type_ = type; statement_.boundByPos_ = true; } void odbc_standard_use_type_backend::bind_by_name( std::string const &name, void *data, exchange_type type, bool /* readOnly */) { if (statement_.boundByPos_) { throw soci_error( "Binding for use elements must be either by position or by name."); } int position = -1; int count = 1; for (std::vector::iterator it = statement_.names_.begin(); it != statement_.names_.end(); ++it) { if (*it == name) { position = count; break; } count++; } if (position == -1) { std::ostringstream ss; ss << "Unable to find name '" << name << "' to bind to"; throw soci_error(ss.str().c_str()); } position_ = position; data_ = data; type_ = type; statement_.boundByName_ = true; } void odbc_standard_use_type_backend::pre_use(indicator const *ind) { // first deal with data SQLSMALLINT sqlType; SQLSMALLINT cType; SQLLEN size; void* const sqlData = prepare_for_bind(size, sqlType, cType); SQLRETURN rc = SQLBindParameter(statement_.hstmt_, static_cast(position_), SQL_PARAM_INPUT, cType, sqlType, size, 0, sqlData, 0, &indHolder_); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_STMT, statement_.hstmt_, "Binding"); } // then handle indicators if (ind != NULL && *ind == i_null) { indHolder_ = SQL_NULL_DATA; // null } } void odbc_standard_use_type_backend::post_use(bool gotData, indicator *ind) { if (ind != NULL) { if (gotData) { if (indHolder_ == 0) { *ind = i_ok; } else if (indHolder_ == SQL_NULL_DATA) { *ind = i_null; } else { *ind = i_truncated; } } } } void odbc_standard_use_type_backend::clean_up() { if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } } soci-3.2.3/backends/odbc/session.cpp0000644000000000000000000002031712511361676016035 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ODBC_SOURCE #include "soci-odbc.h" #include "session.h" #include using namespace soci; using namespace soci::details; char const * soci::odbc_option_driver_complete = "odbc.driver_complete"; odbc_session_backend::odbc_session_backend( connection_parameters const & parameters) : henv_(0), hdbc_(0), product_(prod_uninitialized) { SQLRETURN rc; // Allocate environment handle rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv_); if (is_odbc_error(rc)) { throw soci_error("Unable to get environment handle"); } // Set the ODBC version environment attribute rc = SQLSetEnvAttr(henv_, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_ENV, henv_, "Setting ODBC version"); } // Allocate connection handle rc = SQLAllocHandle(SQL_HANDLE_DBC, henv_, &hdbc_); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_DBC, hdbc_, "Allocating connection handle"); } SQLCHAR outConnString[1024]; SQLSMALLINT strLength; // Prompt the user for any missing information (typically UID/PWD) in the // connection string by default but allow overriding this using "prompt" // option. SQLHWND hwnd_for_prompt = NULL; unsigned completion = SQL_DRIVER_COMPLETE; std::string completionString; if (parameters.get_option(odbc_option_driver_complete, completionString)) { // The value of the option is supposed to be just the integer value of // one of SQL_DRIVER_XXX constants but don't check for the exact value in // case more of them are added in the future, the ODBC driver will return // an error if we pass it an invalid value anyhow. if (std::sscanf(completionString.c_str(), "%u", &completion) != 1) { throw soci_error("Invalid non-numeric driver completion option value \"" + completionString + "\"."); } } #ifdef _WIN32 if (completion != SQL_DRIVER_NOPROMPT) hwnd_for_prompt = ::GetDesktopWindow(); #endif // _WIN32 std::string const & connectString = parameters.get_connect_string(); rc = SQLDriverConnect(hdbc_, hwnd_for_prompt, (SQLCHAR *)connectString.c_str(), (SQLSMALLINT)connectString.size(), outConnString, 1024, &strLength, static_cast(completion)); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_DBC, hdbc_, "Error Connecting to database"); } connection_string_.assign((const char*)outConnString, strLength); reset_transaction(); } odbc_session_backend::~odbc_session_backend() { clean_up(); } void odbc_session_backend::begin() { SQLRETURN rc = SQLSetConnectAttr( hdbc_, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, 0 ); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_DBC, hdbc_, "Begin Transaction"); } } void odbc_session_backend::commit() { SQLRETURN rc = SQLEndTran(SQL_HANDLE_DBC, hdbc_, SQL_COMMIT); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_DBC, hdbc_, "Committing"); } reset_transaction(); } void odbc_session_backend::rollback() { SQLRETURN rc = SQLEndTran(SQL_HANDLE_DBC, hdbc_, SQL_ROLLBACK); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_DBC, hdbc_, "Rolling back"); } reset_transaction(); } bool odbc_session_backend::get_next_sequence_value( session & s, std::string const & sequence, long & value) { std::string query; switch ( get_database_product() ) { case prod_firebird: query = "select next value for " + sequence + " from rdb$database"; break; case prod_oracle: query = "select " + sequence + ".nextval from dual"; break; case prod_postgresql: query = "select nextval('" + sequence + "')"; break; case prod_mssql: case prod_mysql: case prod_sqlite: // These RDBMS implement get_last_insert_id() instead. return false; case prod_unknown: // For this one we can't do anything at all. return false; case prod_uninitialized: // This is not supposed to happen at all but still cover this case // here to avoid gcc warnings about unhandled enum values in a // switch. return false; } s << query, into(value); return true; } bool odbc_session_backend::get_last_insert_id( session & s, std::string const & table, long & value) { std::string query; switch ( get_database_product() ) { case prod_mssql: query = "select ident_current('" + table + "')"; break; case prod_mysql: query = "select last_insert_id()"; break; case prod_sqlite: query = "select last_insert_rowid()"; break; case prod_firebird: case prod_oracle: case prod_postgresql: // For these RDBMS get_next_sequence_value() should have been used. return false; case prod_unknown: // For this one we can't do anything at all. return false; case prod_uninitialized: // As above, this is not supposed to happen but put it here to // mollify gcc. return false; } s << query, into(value); return true; } void odbc_session_backend::reset_transaction() { SQLRETURN rc = SQLSetConnectAttr( hdbc_, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0 ); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_DBC, hdbc_, "Set Auto Commit"); } } void odbc_session_backend::clean_up() { SQLRETURN rc = SQLDisconnect(hdbc_); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_DBC, hdbc_, "SQLDisconnect"); } rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc_); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_DBC, hdbc_, "SQLFreeHandle DBC"); } rc = SQLFreeHandle(SQL_HANDLE_ENV, henv_); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_ENV, henv_, "SQLFreeHandle ENV"); } } odbc_statement_backend * odbc_session_backend::make_statement_backend() { return new odbc_statement_backend(*this); } odbc_rowid_backend * odbc_session_backend::make_rowid_backend() { return new odbc_rowid_backend(*this); } odbc_blob_backend * odbc_session_backend::make_blob_backend() { return new odbc_blob_backend(*this); } odbc_session_backend::database_product odbc_session_backend::get_database_product() { // Cache the product type, it's not going to change during our life time. if (product_ != prod_uninitialized) return product_; char product_name[1024]; SQLSMALLINT len = sizeof(product_name); SQLRETURN rc = SQLGetInfo(hdbc_, SQL_DBMS_NAME, product_name, len, &len); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_DBC, henv_, "SQLGetInfo(SQL_DBMS_NAME)"); } if (strcmp(product_name, "Firebird") == 0) product_ = prod_firebird; else if (strcmp(product_name, "Microsoft SQL Server") == 0) product_ = prod_mssql; else if (strcmp(product_name, "MySQL") == 0) product_ = prod_mysql; else if (strcmp(product_name, "Oracle") == 0) product_ = prod_oracle; else if (strcmp(product_name, "PostgreSQL") == 0) product_ = prod_postgresql; else if (strcmp(product_name, "SQLite") == 0) product_ = prod_sqlite; else product_ = prod_unknown; return product_; } soci-3.2.3/backends/odbc/Makefile.basic0000644000000000000000000000453312505151606016361 0ustar rootroot# The following variable is specific to this backend and its correct # values might depend on your environment - feel free to set it accordingly. ODBCINCLUDEDIR = -I/usr/include # The rest of the Makefile is indepentent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long CXXFLAGSSO = ${CXXFLAGS} -fPIC INCLUDEDIRS = -I../../core ${ODBCINCLUDEDIR} OBJECTS = blob.o factory.o row-id.o session.o standard-into-type.o \ standard-use-type.o statement.o vector-into-type.o vector-use-type.o OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \ standard-into-type-s.o standard-use-type-s.o statement-s.o \ vector-into-type-s.o vector-use-type-s.o libsoci_odbc.a : ${OBJECTS} ar rv $@ $? ranlib $@ rm *.o blob.o : blob.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} factory.o : factory.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} row-id.o : row-id.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} session.o : session.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-into-type.o : standard-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-use-type.o : standard-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} statement.o : statement.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-into-type.o : vector-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-use-type.o : vector-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} shared : ${OBJECTSSO} ${COMPILER} -shared -o libsoci_odbc.so ${OBJECTSSO} rm *.o blob-s.o : blob.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} factory-s.o : factory.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} row-id-s.o : row-id.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} session-s.o : session.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} standard-into-type-s.o : standard-into-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} standard-use-type-s.o : standard-use-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} statement-s.o : statement.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} vector-into-type-s.o : vector-into-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} vector-use-type-s.o : vector-use-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} clean : rm -f libsoci_odbc.a libsoci_odbc.so soci-3.2.3/backends/odbc/factory.cpp0000644000000000000000000000156412511361676016024 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ODBC_SOURCE #include "soci-odbc.h" #include using namespace soci; using namespace soci::details; // concrete factory for ODBC concrete strategies odbc_session_backend * odbc_backend_factory::make_session( connection_parameters const & parameters) const { return new odbc_session_backend(parameters); } odbc_backend_factory const soci::odbc; extern "C" { // for dynamic backend loading SOCI_ODBC_DECL backend_factory const * factory_odbc() { return &soci::odbc; } SOCI_ODBC_DECL void register_factory_odbc() { soci::dynamic_backends::register_backend("odbc", soci::odbc); } } // extern "C" soci-3.2.3/backends/odbc/row-id.cpp0000644000000000000000000000075312511361676015555 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ODBC_SOURCE #include "soci-odbc.h" using namespace soci; using namespace soci::details; odbc_rowid_backend::odbc_rowid_backend(odbc_session_backend & /* session */) { // ... } odbc_rowid_backend::~odbc_rowid_backend() { // ... } soci-3.2.3/backends/odbc/standard-into-type.cpp0000644000000000000000000001271012511361676020076 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ODBC_SOURCE #include #include "soci-odbc.h" #include #include // sscanf() using namespace soci; using namespace soci::details; void odbc_standard_into_type_backend::define_by_pos( int & position, void * data, exchange_type type) { data_ = data; type_ = type; position_ = position++; SQLUINTEGER size = 0; switch (type_) { case x_char: odbcType_ = SQL_C_CHAR; size = sizeof(char) + 1; buf_ = new char[size]; data = buf_; break; case x_stdstring: odbcType_ = SQL_C_CHAR; // Patch: set to min between column size and 100MB (used ot be 32769) // Column size for text data type can be too large for buffer allocation size = statement_.column_size(position_); size = size > odbc_max_buffer_length ? odbc_max_buffer_length : size; size++; buf_ = new char[size]; data = buf_; break; case x_short: odbcType_ = SQL_C_SSHORT; size = sizeof(short); break; case x_integer: odbcType_ = SQL_C_SLONG; size = sizeof(int); break; case x_long_long: if (use_string_for_bigint()) { odbcType_ = SQL_C_CHAR; size = max_bigint_length; buf_ = new char[size]; data = buf_; } else // Normal case, use ODBC support. { odbcType_ = SQL_C_SBIGINT; size = sizeof(long long); } break; case x_unsigned_long_long: if (use_string_for_bigint()) { odbcType_ = SQL_C_CHAR; size = max_bigint_length; buf_ = new char[size]; data = buf_; } else // Normal case, use ODBC support. { odbcType_ = SQL_C_UBIGINT; size = sizeof(unsigned long long); } break; case x_double: odbcType_ = SQL_C_DOUBLE; size = sizeof(double); break; case x_stdtm: odbcType_ = SQL_C_TYPE_TIMESTAMP; size = sizeof(TIMESTAMP_STRUCT); buf_ = new char[size]; data = buf_; break; case x_rowid: odbcType_ = SQL_C_ULONG; size = sizeof(unsigned long); break; default: throw soci_error("Into element used with non-supported type."); } valueLen_ = 0; SQLRETURN rc = SQLBindCol(statement_.hstmt_, static_cast(position_), static_cast(odbcType_), data, size, &valueLen_); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_STMT, statement_.hstmt_, "into type pre_fetch"); } } void odbc_standard_into_type_backend::pre_fetch() { //... } void odbc_standard_into_type_backend::post_fetch( bool gotData, bool calledFromFetch, indicator * ind) { if (calledFromFetch == true && gotData == false) { // this is a normal end-of-rowset condition, // no need to do anything (fetch() will return false) return; } if (gotData) { // first, deal with indicators if (SQL_NULL_DATA == valueLen_) { if (ind == NULL) { throw soci_error( "Null value fetched and no indicator defined."); } *ind = i_null; return; } else { if (ind != NULL) { *ind = i_ok; } } // only std::string and std::tm need special handling if (type_ == x_char) { char *c = static_cast(data_); *c = buf_[0]; } if (type_ == x_stdstring) { std::string *s = static_cast(data_); *s = buf_; if (s->size() >= (odbc_max_buffer_length - 1)) { throw soci_error("Buffer size overflow; maybe got too large string"); } } else if (type_ == x_stdtm) { std::tm *t = static_cast(data_); TIMESTAMP_STRUCT * ts = reinterpret_cast(buf_); t->tm_isdst = -1; t->tm_year = ts->year - 1900; t->tm_mon = ts->month - 1; t->tm_mday = ts->day; t->tm_hour = ts->hour; t->tm_min = ts->minute; t->tm_sec = ts->second; // normalize and compute the remaining fields std::mktime(t); } else if (type_ == x_long_long && use_string_for_bigint()) { long long *ll = static_cast(data_); if (sscanf(buf_, "%" LL_FMT_FLAGS "d", ll) != 1) { throw soci_error("Failed to parse the returned 64-bit integer value"); } } else if (type_ == x_unsigned_long_long && use_string_for_bigint()) { unsigned long long *ll = static_cast(data_); if (sscanf(buf_, "%" LL_FMT_FLAGS "u", ll) != 1) { throw soci_error("Failed to parse the returned 64-bit integer value"); } } } } void odbc_standard_into_type_backend::clean_up() { if (buf_) { delete [] buf_; buf_ = 0; } } soci-3.2.3/backends/odbc/test/0000755000000000000000000000000012511362240014606 5ustar rootrootsoci-3.2.3/backends/odbc/test/test-odbc-postgresql.cpp0000644000000000000000000000761412511362240021407 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci.h" #include "soci-odbc.h" #include "common-tests.h" #include #include #include #include #include using namespace soci; using namespace soci::tests; std::string connectString; backend_factory const &backEnd = *soci::factory_odbc(); // DDL Creation objects for common tests struct table_creator_one : public table_creator_base { table_creator_one(session & sql) : table_creator_base(sql) { sql << "create table soci_test(id integer, val integer, c char, " "str varchar(20), sh int2, ul numeric(20), d float8, " "tm timestamp, i1 integer, i2 integer, i3 integer, " "name varchar(20))"; } }; struct table_creator_two : public table_creator_base { table_creator_two(session & sql) : table_creator_base(sql) { sql << "create table soci_test(num_float float8, num_int integer," " name varchar(20), sometime timestamp, chr char)"; } }; struct table_creator_three : public table_creator_base { table_creator_three(session & sql) : table_creator_base(sql) { sql << "create table soci_test(name varchar(100) not null, " "phone varchar(15))"; } }; struct table_creator_for_get_affected_rows : table_creator_base { table_creator_for_get_affected_rows(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val integer)"; } }; // // Support for SOCI Common Tests // class test_context : public test_context_base { public: test_context(backend_factory const &backEnd, std::string const &connectString) : test_context_base(backEnd, connectString) {} table_creator_base * table_creator_1(session& s) const { return new table_creator_one(s); } table_creator_base * table_creator_2(session& s) const { return new table_creator_two(s); } table_creator_base * table_creator_3(session& s) const { return new table_creator_three(s); } table_creator_base * table_creator_4(session& s) const { return new table_creator_for_get_affected_rows(s); } std::string to_date_time(std::string const &datdt_string) const { return "timestamptz(\'" + datdt_string + "\')"; } }; int main(int argc, char** argv) { #ifdef _MSC_VER // Redirect errors, unrecoverable problems, and assert() failures to STDERR, // instead of debug message window. // This hack is required to run asser()-driven tests by Buildbot. // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); #endif //_MSC_VER if (argc == 2) { connectString = argv[1]; } else { connectString = "FILEDSN=./test-postgresql.dsn"; } try { std::cout << "\nSOCI ODBC with PostgreSQL Tests:\n\n"; test_context tc(backEnd, connectString); common_tests tests(tc); tests.run(); std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; } catch (soci::odbc_soci_error const & e) { std::cout << "ODBC Error Code: " << e.odbc_error_code() << std::endl << "Native Error Code: " << e.native_error_code() << std::endl << "SOCI Message: " << e.what() << std::endl << "ODBC Message: " << e.odbc_error_message() << std::endl; } catch (std::exception const & e) { std::cout << "STD::EXECEPTION " << e.what() << '\n'; } return EXIT_FAILURE; } soci-3.2.3/backends/odbc/test/makefile.msvc0000644000000000000000000000107012511361676017267 0ustar rootrootODBCINCLUDEDIR="C:\Program Files\Microsoft Platform SDK\Include" ODBCLIBDIR="C:\Program Files\Microsoft Platform SDK\Lib" COMPILER = cl CXXFLAGS = /nologo /EHsc CXXFLAGSSO = $(CXXFLAGS) INCLUDEDIRS = /I.. /I..\..\..\core /I..\..\..\core\test /I$(ODBCINCLUDEDIR) LIBS = ..\..\..\core\soci-core.lib ..\soci-odbc.lib $(ODBCLIBDIR)\uuid.lib $(ODBCLIBDIR)\odbc32.lib mssql: test-odbc-mssql.cpp $(COMPILER) $? $(CXXFLAGS) $(INCLUDEDIRS) $(LIBS) access: test-odbc-access.cpp $(COMPILER) $? $(CXXFLAGS) $(INCLUDEDIRS) $(LIBS) clean: del *.exe del *.obj soci-3.2.3/backends/odbc/test/test-odbc-mysql.cpp0000644000000000000000000000755112511362240020351 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci.h" #include "soci-odbc.h" #include "common-tests.h" #include #include #include #include #include using namespace soci; using namespace soci::tests; std::string connectString; backend_factory const &backEnd = *soci::factory_odbc(); // DDL Creation objects for common tests struct table_creator_one : public table_creator_base { table_creator_one(session & sql) : table_creator_base(sql) { sql << "create table soci_test(id integer, val integer, c char, " "str varchar(20), sh int2, ul numeric(20), d float8, " "tm datetime, i1 integer, i2 integer, i3 integer, " "name varchar(20))"; } }; struct table_creator_two : public table_creator_base { table_creator_two(session & sql) : table_creator_base(sql) { sql << "create table soci_test(num_float float8, num_int integer," " name varchar(20), sometime datetime, chr char)"; } }; struct table_creator_three : public table_creator_base { table_creator_three(session & sql) : table_creator_base(sql) { sql << "create table soci_test(name varchar(100) not null, " "phone varchar(15))"; } }; struct table_creator_for_get_affected_rows : table_creator_base { table_creator_for_get_affected_rows(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val integer)"; } }; // // Support for SOCI Common Tests // class test_context : public test_context_base { public: test_context(backend_factory const &backEnd, std::string const &connectString) : test_context_base(backEnd, connectString) {} table_creator_base * table_creator_1(session& s) const { return new table_creator_one(s); } table_creator_base * table_creator_2(session& s) const { return new table_creator_two(s); } table_creator_base * table_creator_3(session& s) const { return new table_creator_three(s); } table_creator_base * table_creator_4(session& s) const { return new table_creator_for_get_affected_rows(s); } std::string to_date_time(std::string const &datdt_string) const { return "\'" + datdt_string + "\'"; } }; int main(int argc, char** argv) { #ifdef _MSC_VER // Redirect errors, unrecoverable problems, and assert() failures to STDERR, // instead of debug message window. // This hack is required to run asser()-driven tests by Buildbot. // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); #endif //_MSC_VER if (argc == 2) { connectString = argv[1]; } else { connectString = "FILEDSN=./test-mysql.dsn"; } try { std::cout << "\nSOCI ODBC with MySQL Tests:\n\n"; test_context tc(backEnd, connectString); common_tests tests(tc); tests.run(); std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; } catch (soci::odbc_soci_error const & e) { std::cout << "ODBC Error Code: " << e.odbc_error_code() << std::endl << "Native Error Code: " << e.native_error_code() << std::endl << "SOCI Message: " << e.what() << std::endl << "ODBC Message: " << e.odbc_error_message() << std::endl; } catch (std::exception const & e) { std::cout << "STD::EXECEPTION " << e.what() << '\n'; } return EXIT_FAILURE; } soci-3.2.3/backends/odbc/test/test-odbc-mssql.cpp0000644000000000000000000000776212511362240020347 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci.h" #include "soci-odbc.h" #include "common-tests.h" #include #include #include #include #include using namespace soci; using namespace soci::tests; std::string connectString; backend_factory const &backEnd = *soci::factory_odbc(); // DDL Creation objects for common tests struct table_creator_one : public table_creator_base { table_creator_one(session & sql) : table_creator_base(sql) { sql << "create table soci_test(id integer, val integer, c char, " "str varchar(20), sh smallint, ul numeric(20), d float, " "tm datetime, i1 integer, i2 integer, i3 integer, " "name varchar(20))"; } }; struct table_creator_two : public table_creator_base { table_creator_two(session & sql) : table_creator_base(sql) { sql << "create table soci_test(num_float float, num_int integer," " name varchar(20), sometime datetime, chr char)"; } }; struct table_creator_three : public table_creator_base { table_creator_three(session & sql) : table_creator_base(sql) { sql << "create table soci_test(name varchar(100) not null, " "phone varchar(15))"; } }; struct table_creator_for_get_affected_rows : table_creator_base { table_creator_for_get_affected_rows(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val integer)"; } }; // // Support for SOCI Common Tests // class test_context : public test_context_base { public: test_context(backend_factory const &backEnd, std::string const &connectString) : test_context_base(backEnd, connectString) {} table_creator_base* table_creator_1(session& s) const { return new table_creator_one(s); } table_creator_base* table_creator_2(session& s) const { return new table_creator_two(s); } table_creator_base* table_creator_3(session& s) const { return new table_creator_three(s); } table_creator_base * table_creator_4(session& s) const { return new table_creator_for_get_affected_rows(s); } std::string to_date_time(std::string const &datdt_string) const { return "convert(datetime, \'" + datdt_string + "\', 120)"; } }; int main(int argc, char** argv) { #ifdef _MSC_VER // Redirect errors, unrecoverable problems, and assert() failures to STDERR, // instead of debug message window. // This hack is required to run asser()-driven tests by Buildbot. // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); #endif //_MSC_VER if (argc == 2) { connectString = argv[1]; } else { connectString = "FILEDSN=./test-mssql.dsn"; } try { std::cout << "\nSOCI ODBC with MS SQL Server Tests:\n\n"; test_context tc(backEnd, connectString); common_tests tests(tc); tests.run(); std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; } catch (soci::odbc_soci_error const & e) { std::cout << "ODBC Error Code: " << e.odbc_error_code() << std::endl << "Native Error Code: " << e.native_error_code() << std::endl << "SOCI Message: " << e.what() << std::endl << "ODBC Message: " << e.odbc_error_message() << std::endl; } catch (soci::soci_error const & e) { std::cout << "SOCIERROR: " << e.what() << '\n'; } catch (std::exception const & e) { std::cout << "STD::EXECEPTION " << e.what() << '\n'; } return EXIT_FAILURE; }soci-3.2.3/backends/odbc/test/test-mysql.dsn0000644000000000000000000000006012511361676017446 0ustar rootroot[ODBC] DRIVER=MySQL DATABASE=soci_test OPTION=0 soci-3.2.3/backends/odbc/test/test-odbc-db2.cpp0000644000000000000000000002000612511361676017655 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci.h" #include "soci-odbc.h" #include "common-tests.h" #include #include #include #include #include using namespace soci; using namespace soci::tests; std::string connectString; backend_factory const &backEnd = *soci::factory_odbc(); // DDL Creation objects for common tests struct table_creator_one : public table_creator_base { table_creator_one(session & sql) : table_creator_base(sql) { sql << "CREATE TABLE SOCI_TEST(ID INTEGER, VAL SMALLINT, C CHAR, STR VARCHAR(20), SH SMALLINT, UL NUMERIC(20), D DOUBLE, " "TM TIMESTAMP(9), I1 INTEGER, I2 INTEGER, I3 INTEGER, NAME VARCHAR(20))"; } }; struct table_creator_two : public table_creator_base { table_creator_two(session & sql) : table_creator_base(sql) { sql << "CREATE TABLE SOCI_TEST(NUM_FLOAT DOUBLE, NUM_INT INTEGER, NAME VARCHAR(20), SOMETIME TIMESTAMP, CHR CHAR)"; } }; struct table_creator_three : public table_creator_base { table_creator_three(session & sql) : table_creator_base(sql) { sql << "CREATE TABLE SOCI_TEST(NAME VARCHAR(100) NOT NULL, PHONE VARCHAR(15))"; } }; struct table_creator_for_get_affected_rows : table_creator_base { table_creator_for_get_affected_rows(session & sql) : table_creator_base(sql) { sql << "CREATE TABLE SOCI_TEST(VAL INTEGER)"; } }; // // Support for SOCI Common Tests // class test_context : public test_context_base { public: test_context(backend_factory const &backEnd, std::string const &connectString) : test_context_base(backEnd, connectString) {} table_creator_base * table_creator_1(session& s) const { return new table_creator_one(s); } table_creator_base * table_creator_2(session& s) const { return new table_creator_two(s); } table_creator_base * table_creator_3(session& s) const { return new table_creator_three(s); } table_creator_base * table_creator_4(session& s) const { return new table_creator_for_get_affected_rows(s); } std::string to_date_time(std::string const &datdt_string) const { return "\'" + datdt_string + "\'"; } }; struct table_creator_bigint : table_creator_base { table_creator_bigint(session & sql) : table_creator_base(sql) { sql << "CREATE TABLE SOCI_TEST (VAL BIGINT)"; } }; void test_odbc_db2_long_long() { const int num_recs = 100; session sql(backEnd, connectString); table_creator_bigint table(sql); { long long n; statement st = (sql.prepare << "INSERT INTO SOCI_TEST (VAL) VALUES (:val)", use(n)); for (int i = 0; i < num_recs; i++) { n = 1000000000LL + i; st.execute(); } } { long long n2; statement st = (sql.prepare << "SELECT VAL FROM SOCI_TEST ORDER BY VAL", into(n2)); st.execute(); for (int i = 0; i < num_recs; i++) { st.fetch(); assert(n2 == 1000000000LL + i); } } std::cout << "test odbc_db2_long_long passed" << std::endl; } void test_odbc_db2_unsigned_long_long() { const int num_recs = 100; session sql(backEnd, connectString); table_creator_bigint table(sql); { unsigned long long n; statement st = (sql.prepare << "INSERT INTO SOCI_TEST (VAL) VALUES (:val)", use(n)); for (int i = 0; i < num_recs; i++) { n = 1000000000LL + i; st.execute(); } } { unsigned long long n2; statement st = (sql.prepare << "SELECT VAL FROM SOCI_TEST ORDER BY VAL", into(n2)); st.execute(); for (int i = 0; i < num_recs; i++) { st.fetch(); assert(n2 == 1000000000LL + i); } } std::cout << "test odbc_db2_unsigned_long_long passed" << std::endl; } void test_odbc_db2_long_long_vector() { const std::size_t num_recs = 100; session sql(backEnd, connectString); table_creator_bigint table(sql); { std::vector v(num_recs); for (std::size_t i = 0; i < num_recs; i++) { v[i] = 1000000000LL + i; } sql << "INSERT INTO SOCI_TEST (VAL) VALUES (:bi)", use(v); } { std::size_t recs = 0; std::vector v(num_recs / 2 + 1); statement st = (sql.prepare << "SELECT VAL FROM SOCI_TEST ORDER BY VAL", into(v)); st.execute(); while (true) { if (!st.fetch()) { break; } const std::size_t vsize = v.size(); for (std::size_t i = 0; i < vsize; i++) { assert(v[i] == 1000000000LL + static_cast(recs)); recs++; } } assert(recs == num_recs); } std::cout << "test odbc_db2_long_long_vector passed" << std::endl; } void test_odbc_db2_unsigned_long_long_vector() { const std::size_t num_recs = 100; session sql(backEnd, connectString); table_creator_bigint table(sql); { std::vector v(num_recs); for (std::size_t i = 0; i < num_recs; i++) { v[i] = 1000000000LL + i; } sql << "INSERT INTO SOCI_TEST (VAL) VALUES (:bi)", use(v); } { std::size_t recs = 0; std::vector v(num_recs / 2 + 1); statement st = (sql.prepare << "SELECT VAL FROM SOCI_TEST ORDER BY VAL", into(v)); st.execute(); while (true) { if (!st.fetch()) { break; } const std::size_t vsize = v.size(); for (std::size_t i = 0; i < vsize; i++) { assert(v[i] == 1000000000LL + static_cast(recs)); recs++; } } assert(recs == num_recs); } std::cout << "test odbc_db2_unsigned_long_long_vector passed" << std::endl; } int main(int argc, char** argv) { #ifdef _MSC_VER // Redirect errors, unrecoverable problems, and assert() failures to STDERR, // instead of debug message window. // This hack is required to run asser()-driven tests by Buildbot. // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); #endif //_MSC_VER if (argc == 2) { connectString = argv[1]; } else { std::cerr << std::endl << "usage: test-odbc-db2 \"DSN=;Uid=;Pwd=\"" << std::endl << std::endl; return EXIT_FAILURE; } try { std::cout << "\nSOCI ODBC with DB2 Tests:\n\n"; test_context tc(backEnd, connectString); common_tests tests(tc); tests.run(); std::cout << "\nSOCI DB2 Specific Tests:\n\n"; test_odbc_db2_long_long(); test_odbc_db2_unsigned_long_long(); test_odbc_db2_long_long_vector(); test_odbc_db2_unsigned_long_long_vector(); std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; } catch (soci::odbc_soci_error const & e) { std::cout << "ODBC Error Code: " << e.odbc_error_code() << std::endl << "Native Error Code: " << e.native_error_code() << std::endl << "SOCI Message: " << e.what() << std::endl << "ODBC Message: " << e.odbc_error_message() << std::endl; } catch (std::exception const & e) { std::cout << "STD::EXECEPTION " << e.what() << '\n'; } return EXIT_FAILURE; } soci-3.2.3/backends/odbc/test/test-postgresql.dsn0000644000000000000000000000022512511361676020507 0ustar rootroot[ODBC] Description=DSN for SOCI ODBC connection to PostgreSQL Driver=PostgreSQL ANSI Server=localhost Port=5432 Database=soci_test UID=postgres PWD= soci-3.2.3/backends/odbc/test/Makefile.basic0000644000000000000000000000141412511361676017342 0ustar rootroot# The following variable is specific to this backend and its correct # values might depend on your environment - feel free to set it accordingly. ODBCINCLUDEDIR = -I/usr/include ODBCLIBDIR = -L/usr/lib ODBCLIBS = -lodbc -lodbcinst # The rest of the Makefile is independent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long INCLUDEDIRS = -I.. -I../../../core ${ODBCINCLUDEDIR} LIBDIRS = -L.. -L../../../core ${ODBCLIBDIR} LIBS = -lsoci_core -lsoci_odbc -ldl ${ODBCLIBS} test-odbc-mssql: test-odbc-mssql.cpp ${COMPILER} -o $@ $? ${CXXFLAGS} ${INCLUDEDIRS} ${LIBDIRS} ${LIBS} test-odbc-access: test-odbc-access.cpp ${COMPILER} -o $@ $? ${CXXFLAGS} ${INCLUDEDIRS} ${LIBDIRS} ${LIBS} clean : rm -f test-odbc-access.exe test-odbc-mssql.exe soci-3.2.3/backends/odbc/test/test-mssql.dsn0000644000000000000000000000023712511361676017446 0ustar rootroot[ODBC] DRIVER=SQL Native Client UID=David DATABASE=soci_test WSID=NANO APP=Microsoft Data Access Components Trusted_Connection=Yes SERVER=localhost\SQLEXPRESS soci-3.2.3/backends/odbc/test/test-odbc-access.cpp0000644000000000000000000001005212511362240020433 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci.h" #include "soci-odbc.h" #include "common-tests.h" #include #include #include #include #include using namespace soci; using namespace soci::tests; std::string connectString; backend_factory const &backEnd = *soci::factory_odbc(); // DDL Creation objects for common tests struct table_creator_one : public table_creator_base { table_creator_one(session & sql) : table_creator_base(sql) { sql << "create table soci_test(id integer, val integer, c char, " "str varchar(20), sh integer, ul number, d float, " "tm timestamp, i1 integer, i2 integer, i3 integer, " "name varchar(20))"; } }; struct table_creator_two : public table_creator_base { table_creator_two(session & sql) : table_creator_base(sql) { sql << "create table soci_test(num_float float, num_int integer," " name varchar(20), sometime datetime, chr char)"; } }; struct table_creator_three : public table_creator_base { table_creator_three(session & sql) : table_creator_base(sql) { sql << "create table soci_test(name varchar(100) not null, " "phone varchar(15))"; } }; struct table_creator_for_get_affected_rows : table_creator_base { table_creator_for_get_affected_rows(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val integer)"; } }; // // Support for SOCI Common Tests // class test_context : public test_context_base { public: test_context(backend_factory const &backEnd, std::string const &connectString) : test_context_base(backEnd, connectString) {} table_creator_base * table_creator_1(session& s) const { return new table_creator_one(s); } table_creator_base * table_creator_2(session& s) const { return new table_creator_two(s); } table_creator_base * table_creator_3(session& s) const { return new table_creator_three(s); } table_creator_base * table_creator_4(session& s) const { return new table_creator_for_get_affected_rows(s); } std::string fromDual(std::string const &sql) const { return sql; } std::string toDate(std::string const &datdt_string) const { return "#" + datdt_string + "#"; } std::string to_date_time(std::string const &datdt_string) const { return "#" + datdt_string + "#"; } }; int main(int argc, char** argv) { #ifdef _MSC_VER // Redirect errors, unrecoverable problems, and assert() failures to STDERR, // instead of debug message window. // This hack is required to run asser()-driven tests by Buildbot. // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); #endif //_MSC_VER if (argc == 2) { connectString = argv[1]; } else { connectString = "FILEDSN=./test-access.dsn"; } try { std::cout << "\nSOCI ODBC with MS Access Tests:\n\n"; test_context tc(backEnd, connectString); common_tests tests(tc); tests.run(); std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; } catch (soci::odbc_soci_error const & e) { std::cout << "ODBC Error Code: " << e.odbc_error_code() << std::endl << "Native Error Code: " << e.native_error_code() << std::endl << "SOCI Message: " << e.what() << std::endl << "ODBC Message: " << e.odbc_error_message() << std::endl; } catch (std::exception const & e) { std::cout << "STD::EXECEPTION " << e.what() << '\n'; } return EXIT_FAILURE; } soci-3.2.3/backends/odbc/test/test-access.dsn0000644000000000000000000000032312511361676017544 0ustar rootroot[ODBC] DRIVER=Microsoft Access Driver (*.mdb) UID=admin UserCommitSync=Yes Threads=3 SafeTransactions=0 PageTimeout=5 MaxScanRows=8 MaxBufferSize=2048 FIL=MS Access DriverId=25 DefaultDir=.\ DBQ=.\soci_test.mdb soci-3.2.3/backends/odbc/test/CMakeLists.txt0000644000000000000000000000241712511361676017366 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### if (WIN32) # MDBTools driver seems unreliable soci_backend_test( NAME access BACKEND ODBC SOURCE test-odbc-access.cpp CONNSTR "test-access.dsn") # We have no means to test SQL Server at travis-ci.org soci_backend_test( NAME mssql BACKEND ODBC SOURCE test-odbc-mssql.cpp CONNSTR "test-mssql.dsn") endif() soci_backend_test( NAME mysql BACKEND ODBC SOURCE test-odbc-mysql.cpp CONNSTR "test-mysql.dsn") soci_backend_test( NAME postgresql BACKEND ODBC SOURCE test-odbc-postgresql.cpp CONNSTR "test-postgresql.dsn") # TODO: DB2 backend is tested by Travis CI on dedicated VM, separate from ODBC, # in order to test DB2 with ODBC, it would be best to install DB2 driver only. if (NOT $ENV{TRAVIS}) soci_backend_test( NAME db2 BACKEND ODBC SOURCE test-odbc-db2.cpp CONNSTR "test-db2.dsn") endif() soci-3.2.3/backends/odbc/utility.h0000644000000000000000000000271712505151606015517 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_UTILITY_H_INCLUDED #define SOCI_UTILITY_H_INCLUDED #include "soci-backend.h" #include namespace soci { inline void throw_odbc_error(SQLSMALLINT htype, SQLHANDLE hndl, char const * msg) { SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; SQLINTEGER sqlcode; SQLSMALLINT length, i; std::stringstream ss; i = 1; /* get multiple field settings of diagnostic record */ while (SQLGetDiagRecA(htype, hndl, i, sqlstate, &sqlcode, message, SQL_MAX_MESSAGE_LENGTH + 1, &length) == SQL_SUCCESS) { ss << std::endl << "SOCI ODBC Error: " << msg << std::endl << "SQLSTATE = " << sqlstate << std::endl << "Native Error Code = " << sqlcode << std::endl << message << std::endl; ++i; } throw soci_error(ss.str()); } inline bool is_odbc_error(SQLRETURN rc) { if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { return true; } else { return false; } } } #endif // SOCI_UTILITY_H_INCLUDED soci-3.2.3/backends/odbc/vector-into-type.cpp0000644000000000000000000003227612511361676017611 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_ODBC_SOURCE #include "soci-odbc.h" #include #include #include #include #include #include #include #include // sscanf() using namespace soci; using namespace soci::details; void odbc_vector_into_type_backend::prepare_indicators(std::size_t size) { if (size == 0) { throw soci_error("Vectors of size 0 are not allowed."); } indHolderVec_.resize(size); indHolders_ = &indHolderVec_[0]; } void odbc_vector_into_type_backend::define_by_pos( int &position, void *data, exchange_type type) { data_ = data; // for future reference type_ = type; // for future reference SQLLEN size = 0; // also dummy switch (type) { // simple cases case x_short: { odbcType_ = SQL_C_SSHORT; size = sizeof(short); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_integer: { odbcType_ = SQL_C_SLONG; size = sizeof(SQLINTEGER); assert(sizeof(SQLINTEGER) == sizeof(int)); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_long_long: { std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); if (use_string_for_bigint()) { odbcType_ = SQL_C_CHAR; size = max_bigint_length; std::size_t bufSize = size * v.size(); colSize_ = size; buf_ = new char[bufSize]; data = buf_; } else // Normal case, use ODBC support. { odbcType_ = SQL_C_SBIGINT; size = sizeof(long long); data = &v[0]; } } break; case x_unsigned_long_long: { std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); if (use_string_for_bigint()) { odbcType_ = SQL_C_CHAR; size = max_bigint_length; std::size_t bufSize = size * v.size(); colSize_ = size; buf_ = new char[bufSize]; data = buf_; } else // Normal case, use ODBC support. { odbcType_ = SQL_C_UBIGINT; size = sizeof(unsigned long long); data = &v[0]; } } break; case x_double: { odbcType_ = SQL_C_DOUBLE; size = sizeof(double); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; // cases that require adjustments and buffer management case x_char: { odbcType_ = SQL_C_CHAR; std::vector *v = static_cast *>(data); prepare_indicators(v->size()); size = sizeof(char) * 2; std::size_t bufSize = size * v->size(); colSize_ = size; buf_ = new char[bufSize]; data = buf_; } break; case x_stdstring: { odbcType_ = SQL_C_CHAR; std::vector *v = static_cast *>(data); colSize_ = statement_.column_size(position) + 1; std::size_t bufSize = colSize_ * v->size(); buf_ = new char[bufSize]; prepare_indicators(v->size()); size = static_cast(colSize_); data = buf_; } break; case x_stdtm: { odbcType_ = SQL_C_TYPE_TIMESTAMP; std::vector *v = static_cast *>(data); prepare_indicators(v->size()); size = sizeof(TIMESTAMP_STRUCT); colSize_ = size; std::size_t bufSize = size * v->size(); buf_ = new char[bufSize]; data = buf_; } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } SQLRETURN rc = SQLBindCol(statement_.hstmt_, static_cast(position++), odbcType_, static_cast(data), size, indHolders_); if (is_odbc_error(rc)) { throw odbc_soci_error(SQL_HANDLE_STMT, statement_.hstmt_, "vector into type define by pos"); } } void odbc_vector_into_type_backend::pre_fetch() { // nothing to do for the supported types } void odbc_vector_into_type_backend::post_fetch(bool gotData, indicator *ind) { if (gotData) { // first, deal with data // only std::string, std::tm and Statement need special handling if (type_ == x_char) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { v[i] = *pos; pos += colSize_; } } if (type_ == x_stdstring) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { v[i].assign(pos, strlen(pos)); pos += colSize_; } } else if (type_ == x_stdtm) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { std::tm t; TIMESTAMP_STRUCT * ts = reinterpret_cast(pos); t.tm_isdst = -1; t.tm_year = ts->year - 1900; t.tm_mon = ts->month - 1; t.tm_mday = ts->day; t.tm_hour = ts->hour; t.tm_min = ts->minute; t.tm_sec = ts->second; // normalize and compute the remaining fields std::mktime(&t); v[i] = t; pos += colSize_; } } else if (type_ == x_long_long && use_string_for_bigint()) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { if (sscanf(pos, "%" LL_FMT_FLAGS "d", &v[i]) != 1) { throw soci_error("Failed to parse the returned 64-bit integer value"); } pos += colSize_; } } else if (type_ == x_unsigned_long_long && use_string_for_bigint()) { std::vector *vp = static_cast *>(data_); std::vector &v(*vp); char *pos = buf_; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { if (sscanf(pos, "%" LL_FMT_FLAGS "u", &v[i]) != 1) { throw soci_error("Failed to parse the returned 64-bit integer value"); } pos += colSize_; } } // then - deal with indicators if (ind != NULL) { std::size_t const indSize = statement_.get_number_of_rows(); for (std::size_t i = 0; i != indSize; ++i) { if (indHolderVec_[i] > 0) { ind[i] = i_ok; } else if (indHolderVec_[i] == SQL_NULL_DATA) { ind[i] = i_null; } else { ind[i] = i_truncated; } } } else { std::size_t const indSize = statement_.get_number_of_rows(); for (std::size_t i = 0; i != indSize; ++i) { if (indHolderVec_[i] == SQL_NULL_DATA) { // fetched null and no indicator - programming error! throw soci_error( "Null value fetched and no indicator defined."); } } } } else // gotData == false { // nothing to do here, vectors are truncated anyway } } void odbc_vector_into_type_backend::resize(std::size_t sz) { indHolderVec_.resize(sz); switch (type_) { // simple cases case x_char: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_short: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_integer: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_long_long: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_unsigned_long_long: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_double: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_stdstring: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_stdtm: { std::vector *v = static_cast *>(data_); v->resize(sz); } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } } std::size_t odbc_vector_into_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type_) { // simple cases case x_char: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_short: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_integer: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_long_long: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_unsigned_long_long: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_double: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_stdstring: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_stdtm: { std::vector *v = static_cast *>(data_); sz = v->size(); } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } return sz; } void odbc_vector_into_type_backend::clean_up() { if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } } soci-3.2.3/backends/odbc/CMakeLists.txt0000644000000000000000000000123012511362240016363 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend(ODBC DEPENDS ODBC HEADERS soci-odbc.h utility.h DESCRIPTION "SOCI backend for ODBC" AUTHORS "Maciej Sobczak, Stephen Hutton, David Courtney" MAINTAINERS "Vadim Zeitlin, Mateusz Loskot, Maciej Sobczak") add_subdirectory(test) soci-3.2.3/backends/mysql/0000755000000000000000000000000012511401144014062 5ustar rootrootsoci-3.2.3/backends/mysql/common.h0000644000000000000000000000336612511361676015552 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_MYSQL_COMMON_H_INCLUDED #define SOCI_MYSQL_COMMON_H_INCLUDED #include "soci-mysql.h" // std #include #include #include #include namespace soci { namespace details { namespace mysql { // helper function for parsing datetime values void parse_std_tm(char const *buf, std::tm &t); // The idea is that infinity - infinity gives NaN, and NaN != NaN is true. // // This should work on any IEEE-754-compliant implementation, which is // another way of saying that it does not always work (in particular, // according to stackoverflow, it won't work with gcc with the --fast-math // option), but I know of no better way of testing this portably in C++ prior // to C++11. When soci moves to C++11 this should be replaced // with std::isfinite(). template bool is_infinity_or_nan(T x) { T y = x - x; return (y != y); } template void parse_num(char const *buf, T &x) { std::istringstream iss(buf); iss >> x; if (iss.fail() || (iss.eof() == false)) { throw soci_error("Cannot convert data."); } if (is_infinity_or_nan(x)) { throw soci_error("Cannot convert data."); } } // helper for escaping strings char * quote(MYSQL * conn, const char *s, int len); // helper for vector operations template std::size_t get_vector_size(void *p) { std::vector *v = static_cast *>(p); return v->size(); } } // namespace mysql } // namespace details } // namespace soci #endif // SOCI_MYSQL_COMMON_H_INCLUDED soci-3.2.3/backends/mysql/blob.cpp0000644000000000000000000000263312511361676015527 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_MYSQL_SOURCE #include "soci-mysql.h" #include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4355 4702) #endif using namespace soci; using namespace soci::details; mysql_blob_backend::mysql_blob_backend(mysql_session_backend &session) : session_(session) { throw soci_error("BLOBs are not supported."); } mysql_blob_backend::~mysql_blob_backend() { } std::size_t mysql_blob_backend::get_len() { throw soci_error("BLOBs are not supported."); } std::size_t mysql_blob_backend::read( std::size_t /* offset */, char * /* buf */, std::size_t /* toRead */) { throw soci_error("BLOBs are not supported."); } std::size_t mysql_blob_backend::write( std::size_t /* offset */, char const * /* buf */, std::size_t /* toWrite */) { throw soci_error("BLOBs are not supported."); } std::size_t mysql_blob_backend::append( char const * /* buf */, std::size_t /* toWrite */) { throw soci_error("BLOBs are not supported."); } void mysql_blob_backend::trim(std::size_t /* newLen */) { throw soci_error("BLOBs are not supported."); } #ifdef _MSC_VER #pragma warning(pop) #endif soci-3.2.3/backends/mysql/statement.cpp0000644000000000000000000003510012511361676016610 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_MYSQL_SOURCE #include "soci-mysql.h" #include #include //#include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using std::string; mysql_statement_backend::mysql_statement_backend( mysql_session_backend &session) : session_(session), result_(NULL), rowsAffectedBulk_(-1LL), justDescribed_(false), hasIntoElements_(false), hasVectorIntoElements_(false), hasUseElements_(false), hasVectorUseElements_(false) { } void mysql_statement_backend::alloc() { // nothing to do here. } void mysql_statement_backend::clean_up() { // 'reset' the value for a // potential new execution. rowsAffectedBulk_ = -1; if (result_ != NULL) { mysql_free_result(result_); result_ = NULL; } } void mysql_statement_backend::prepare(std::string const & query, statement_type /* eType */) { queryChunks_.clear(); enum { eNormal, eInQuotes, eInName } state = eNormal; std::string name; queryChunks_.push_back(""); bool escaped = false; for (std::string::const_iterator it = query.begin(), end = query.end(); it != end; ++it) { switch (state) { case eNormal: if (*it == '\'') { queryChunks_.back() += *it; state = eInQuotes; } else if (*it == ':') { const std::string::const_iterator next_it = it + 1; // Check whether this is an assignment (e.g. @x:=y) // and treat it as a special case, not as a named binding. if (next_it != end && *next_it == '=') { queryChunks_.back() += ":="; ++it; } else { state = eInName; } } else // regular character, stay in the same state { queryChunks_.back() += *it; } break; case eInQuotes: if (*it == '\'' && !escaped) { queryChunks_.back() += *it; state = eNormal; } else // regular quoted character { queryChunks_.back() += *it; } escaped = *it == '\\' && !escaped; break; case eInName: if (std::isalnum(*it) || *it == '_') { name += *it; } else // end of name { names_.push_back(name); name.clear(); queryChunks_.push_back(""); queryChunks_.back() += *it; state = eNormal; } break; } } if (state == eInName) { names_.push_back(name); } /* cerr << "Chunks: "; for (std::vector::iterator i = queryChunks_.begin(); i != queryChunks_.end(); ++i) { cerr << "\"" << *i << "\" "; } cerr << "\nNames: "; for (std::vector::iterator i = names_.begin(); i != names_.end(); ++i) { cerr << "\"" << *i << "\" "; } cerr << endl; */ } statement_backend::exec_fetch_result mysql_statement_backend::execute(int number) { if (justDescribed_ == false) { clean_up(); if (number > 1 && hasIntoElements_) { throw soci_error( "Bulk use with single into elements is not supported."); } // number - size of vectors (into/use) // numberOfExecutions - number of loops to perform int numberOfExecutions = 1; if (number > 0) { numberOfExecutions = hasUseElements_ ? 1 : number; } std::string query; if (not useByPosBuffers_.empty() or not useByNameBuffers_.empty()) { if (not useByPosBuffers_.empty() and not useByNameBuffers_.empty()) { throw soci_error( "Binding for use elements must be either by position " "or by name."); } long long rowsAffectedBulkTemp = 0; for (int i = 0; i != numberOfExecutions; ++i) { std::vector paramValues; if (not useByPosBuffers_.empty()) { // use elements bind by position // the map of use buffers can be traversed // in its natural order for (UseByPosBuffersMap::iterator it = useByPosBuffers_.begin(), end = useByPosBuffers_.end(); it != end; ++it) { char **buffers = it->second; //cerr<<"i: "<::iterator it = names_.begin(), end = names_.end(); it != end; ++it) { UseByNameBuffersMap::iterator b = useByNameBuffers_.find(*it); if (b == useByNameBuffers_.end()) { std::string msg( "Missing use element for bind by name ("); msg += *it; msg += ")."; throw soci_error(msg); } char **buffers = b->second; paramValues.push_back(buffers[i]); } } //cerr << "queryChunks_.size(): "<::const_iterator ci = queryChunks_.begin(); for (std::vector::const_iterator pi = paramValues.begin(), end = paramValues.end(); pi != end; ++ci, ++pi) { query += *ci; query += *pi; } if (ci != queryChunks_.end()) { query += *ci; } if (numberOfExecutions > 1) { // bulk operation //std::cerr << "bulk operation:\n" << query << std::endl; if (0 != mysql_real_query(session_.conn_, query.c_str(), query.size())) { // preserve the number of rows affected so far. rowsAffectedBulk_ = rowsAffectedBulkTemp; throw mysql_soci_error(mysql_error(session_.conn_), mysql_errno(session_.conn_)); } else { rowsAffectedBulkTemp += static_cast(mysql_affected_rows(session_.conn_)); } if (mysql_field_count(session_.conn_) != 0) { throw soci_error("The query shouldn't have returned" " any data but it did."); } query.clear(); } } rowsAffectedBulk_ = rowsAffectedBulkTemp; if (numberOfExecutions > 1) { // bulk return ef_no_data; } } else { query = queryChunks_.front(); } //std::cerr << query << std::endl; if (0 != mysql_real_query(session_.conn_, query.c_str(), query.size())) { throw mysql_soci_error(mysql_error(session_.conn_), mysql_errno(session_.conn_)); } result_ = mysql_store_result(session_.conn_); if (result_ == NULL and mysql_field_count(session_.conn_) != 0) { throw mysql_soci_error(mysql_error(session_.conn_), mysql_errno(session_.conn_)); } if (result_ != NULL) { // Cache the rows offsets to have random access to the rows later. // [mysql_data_seek() is O(n) so we don't want to use it]. int numrows = static_cast(mysql_num_rows(result_)); resultRowOffsets_.resize(numrows); for (int i = 0; i < numrows; i++) { resultRowOffsets_[i] = mysql_row_tell(result_); mysql_fetch_row(result_); } } } else { justDescribed_ = false; } if (result_ != NULL) { currentRow_ = 0; rowsToConsume_ = 0; numberOfRows_ = static_cast(mysql_num_rows(result_)); if (numberOfRows_ == 0) { return ef_no_data; } else { if (number > 0) { // prepare for the subsequent data consumption return fetch(number); } else { // execute(0) was meant to only perform the query return ef_success; } } } else { // it was not a SELECT return ef_no_data; } } statement_backend::exec_fetch_result mysql_statement_backend::fetch(int number) { // Note: This function does not actually fetch anything from anywhere // - the data was already retrieved from the server in the execute() // function, and the actual consumption of this data will take place // in the postFetch functions, called for each into element. // Here, we only prepare for this to happen (to emulate "the Oracle way"). // forward the "cursor" from the last fetch currentRow_ += rowsToConsume_; if (currentRow_ >= numberOfRows_) { // all rows were already consumed return ef_no_data; } else { if (currentRow_ + number > numberOfRows_) { rowsToConsume_ = numberOfRows_ - currentRow_; // this simulates the behaviour of Oracle // - when EOF is hit, we return ef_no_data even when there are // actually some rows fetched return ef_no_data; } else { rowsToConsume_ = number; return ef_success; } } } long long mysql_statement_backend::get_affected_rows() { if (rowsAffectedBulk_ >= 0) { return rowsAffectedBulk_; } return static_cast(mysql_affected_rows(session_.conn_)); } int mysql_statement_backend::get_number_of_rows() { return numberOfRows_ - currentRow_; } std::string mysql_statement_backend::rewrite_for_procedure_call( std::string const &query) { std::string newQuery("select "); newQuery += query; return newQuery; } int mysql_statement_backend::prepare_for_describe() { execute(1); justDescribed_ = true; int columns = mysql_field_count(session_.conn_); return columns; } void mysql_statement_backend::describe_column(int colNum, data_type & type, std::string & columnName) { int pos = colNum - 1; MYSQL_FIELD *field = mysql_fetch_field_direct(result_, pos); switch (field->type) { case FIELD_TYPE_CHAR: //MYSQL_TYPE_TINY: case FIELD_TYPE_SHORT: //MYSQL_TYPE_SHORT: case FIELD_TYPE_INT24: //MYSQL_TYPE_INT24: type = dt_integer; break; case FIELD_TYPE_LONG: //MYSQL_TYPE_LONG: type = field->flags & UNSIGNED_FLAG ? dt_long_long : dt_integer; break; case FIELD_TYPE_LONGLONG: //MYSQL_TYPE_LONGLONG: type = field->flags & UNSIGNED_FLAG ? dt_unsigned_long_long : dt_long_long; break; case FIELD_TYPE_FLOAT: //MYSQL_TYPE_FLOAT: case FIELD_TYPE_DOUBLE: //MYSQL_TYPE_DOUBLE: case FIELD_TYPE_DECIMAL: //MYSQL_TYPE_DECIMAL: // Prior to MySQL v. 5.x there was no column type corresponding // to MYSQL_TYPE_NEWDECIMAL. However, MySQL server 5.x happily // sends field type number 246, no matter which version of libraries // the client is using. case 246: //MYSQL_TYPE_NEWDECIMAL: type = dt_double; break; case FIELD_TYPE_TIMESTAMP: //MYSQL_TYPE_TIMESTAMP: case FIELD_TYPE_DATE: //MYSQL_TYPE_DATE: case FIELD_TYPE_TIME: //MYSQL_TYPE_TIME: case FIELD_TYPE_DATETIME: //MYSQL_TYPE_DATETIME: case FIELD_TYPE_YEAR: //MYSQL_TYPE_YEAR: case FIELD_TYPE_NEWDATE: //MYSQL_TYPE_NEWDATE: type = dt_date; break; // case MYSQL_TYPE_VARCHAR: case FIELD_TYPE_VAR_STRING: //MYSQL_TYPE_VAR_STRING: case FIELD_TYPE_STRING: //MYSQL_TYPE_STRING: case FIELD_TYPE_BLOB: // TEXT OR BLOB case FIELD_TYPE_TINY_BLOB: case FIELD_TYPE_MEDIUM_BLOB: case FIELD_TYPE_LONG_BLOB: type = dt_string; break; default: //std::cerr << "field->type: " << field->type << std::endl; throw soci_error("Unknown data type."); } columnName = field->name; } mysql_standard_into_type_backend * mysql_statement_backend::make_into_type_backend() { hasIntoElements_ = true; return new mysql_standard_into_type_backend(*this); } mysql_standard_use_type_backend * mysql_statement_backend::make_use_type_backend() { hasUseElements_ = true; return new mysql_standard_use_type_backend(*this); } mysql_vector_into_type_backend * mysql_statement_backend::make_vector_into_type_backend() { hasVectorIntoElements_ = true; return new mysql_vector_into_type_backend(*this); } mysql_vector_use_type_backend * mysql_statement_backend::make_vector_use_type_backend() { hasVectorUseElements_ = true; return new mysql_vector_use_type_backend(*this); } soci-3.2.3/backends/mysql/vector-use-type.cpp0000644000000000000000000001560112511361676017663 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_MYSQL_SOURCE #include "soci-mysql.h" #include "common.h" #include // std #include #include #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace soci::details::mysql; void mysql_vector_use_type_backend::bind_by_pos(int &position, void *data, exchange_type type) { data_ = data; type_ = type; position_ = position++; } void mysql_vector_use_type_backend::bind_by_name( std::string const &name, void *data, exchange_type type) { data_ = data; type_ = type; name_ = name; } void mysql_vector_use_type_backend::pre_use(indicator const *ind) { std::size_t const vsize = size(); for (size_t i = 0; i != vsize; ++i) { char *buf; // the data in vector can be either i_ok or i_null if (ind != NULL && ind[i] == i_null) { buf = new char[5]; std::strcpy(buf, "NULL"); } else { // allocate and fill the buffer with text-formatted client data switch (type_) { case x_char: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; char tmp[] = { v[i], '\0' }; buf = quote(statement_.session_.conn_, tmp, 1); } break; case x_stdstring: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; buf = quote(statement_.session_.conn_, v[i].c_str(), v[i].size()); } break; case x_short: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf = new char[bufSize]; snprintf(buf, bufSize, "%d", static_cast(v[i])); } break; case x_integer: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf = new char[bufSize]; snprintf(buf, bufSize, "%d", v[i]); } break; case x_long_long: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf = new char[bufSize]; snprintf(buf, bufSize, "%" LL_FMT_FLAGS "d", v[i]); } break; case x_unsigned_long_long: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf = new char[bufSize]; snprintf(buf, bufSize, "%" LL_FMT_FLAGS "u", v[i]); } break; case x_double: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; if (is_infinity_or_nan(v[i])) { throw soci_error( "Use element used with infinity or NaN, which are " "not supported by the MySQL server."); } std::size_t const bufSize = 100; buf = new char[bufSize]; snprintf(buf, bufSize, "%.20g", v[i]); } break; case x_stdtm: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; std::size_t const bufSize = 22; buf = new char[bufSize]; snprintf(buf, bufSize, "\'%d-%02d-%02d %02d:%02d:%02d\'", v[i].tm_year + 1900, v[i].tm_mon + 1, v[i].tm_mday, v[i].tm_hour, v[i].tm_min, v[i].tm_sec); } break; default: throw soci_error( "Use vector element used with non-supported type."); } } buffers_.push_back(buf); } if (position_ > 0) { // binding by position statement_.useByPosBuffers_[position_] = &buffers_[0]; } else { // binding by name statement_.useByNameBuffers_[name_] = &buffers_[0]; } } std::size_t mysql_vector_use_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type_) { // simple cases case x_char: sz = get_vector_size (data_); break; case x_short: sz = get_vector_size (data_); break; case x_integer: sz = get_vector_size (data_); break; case x_long_long: sz = get_vector_size (data_); break; case x_unsigned_long_long: sz = get_vector_size(data_); break; case x_double: sz = get_vector_size (data_); break; case x_stdstring: sz = get_vector_size (data_); break; case x_stdtm: sz = get_vector_size (data_); break; default: throw soci_error("Use vector element used with non-supported type."); } return sz; } void mysql_vector_use_type_backend::clean_up() { std::size_t const bsize = buffers_.size(); for (std::size_t i = 0; i != bsize; ++i) { delete [] buffers_[i]; } } soci-3.2.3/backends/mysql/standard-use-type.cpp0000644000000000000000000001225512511361676020163 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_MYSQL_SOURCE #include "soci-mysql.h" #include "common.h" #include // std #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace soci::details::mysql; void mysql_standard_use_type_backend::bind_by_pos( int &position, void *data, exchange_type type, bool /* readOnly */) { data_ = data; type_ = type; position_ = position++; } void mysql_standard_use_type_backend::bind_by_name( std::string const &name, void *data, exchange_type type, bool /* readOnly */) { data_ = data; type_ = type; name_ = name; } void mysql_standard_use_type_backend::pre_use(indicator const *ind) { if (ind != NULL && *ind == i_null) { buf_ = new char[5]; std::strcpy(buf_, "NULL"); } else { // allocate and fill the buffer with text-formatted client data switch (type_) { case x_char: { char buf[] = { *static_cast(data_), '\0' }; buf_ = quote(statement_.session_.conn_, buf, 1); } break; case x_stdstring: { std::string *s = static_cast(data_); buf_ = quote(statement_.session_.conn_, s->c_str(), s->size()); } break; case x_short: { std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%d", static_cast(*static_cast(data_))); } break; case x_integer: { std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%d", *static_cast(data_)); } break; case x_long_long: { std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%" LL_FMT_FLAGS "d", *static_cast(data_)); } break; case x_unsigned_long_long: { std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%" LL_FMT_FLAGS "u", *static_cast(data_)); } break; case x_double: { if (is_infinity_or_nan(*static_cast(data_))) { throw soci_error( "Use element used with infinity or NaN, which are " "not supported by the MySQL server."); } std::size_t const bufSize = 100; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%.20g", *static_cast(data_)); } break; case x_stdtm: { std::size_t const bufSize = 22; buf_ = new char[bufSize]; std::tm *t = static_cast(data_); snprintf(buf_, bufSize, "\'%d-%02d-%02d %02d:%02d:%02d\'", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); } break; default: throw soci_error("Use element used with non-supported type."); } } if (position_ > 0) { // binding by position statement_.useByPosBuffers_[position_] = &buf_; } else { // binding by name statement_.useByNameBuffers_[name_] = &buf_; } } void mysql_standard_use_type_backend::post_use(bool /*gotData*/, indicator* /*ind*/) { // TODO: Is it possible to have the bound element being overwritten // by the database? // If not, then nothing to do here, please remove this comment. // If yes, then use the value of the readOnly parameter: // - true: the given object should not be modified and the backend // should detect if the modification was performed on the // isolated buffer and throw an exception if the buffer was modified // (this indicates logic error, because the user used const object // and executed a query that attempted to modified it) // - false: the modification should be propagated to the given object. // ... clean_up(); } void mysql_standard_use_type_backend::clean_up() { if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } } soci-3.2.3/backends/mysql/session.cpp0000644000000000000000000002217412511401144016257 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_MYSQL_SOURCE #include "soci-mysql.h" #include // std #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using std::string; namespace { // anonymous void skip_white(std::string::const_iterator *i, std::string::const_iterator const & end, bool endok) { for (;;) { if (*i == end) { if (endok) { return; } else { throw soci_error("Unexpected end of connection string."); } } if (std::isspace(**i)) { ++*i; } else { return; } } } std::string param_name(std::string::const_iterator *i, std::string::const_iterator const & end) { std::string val(""); for (;;) { if (*i == end or (not std::isalpha(**i) and **i != '_')) { break; } val += **i; ++*i; } return val; } string param_value(string::const_iterator *i, string::const_iterator const & end) { string err = "Malformed connection string."; bool quot; if (**i == '\'') { quot = true; ++*i; } else { quot = false; } string val(""); for (;;) { if (*i == end) { if (quot) { throw soci_error(err); } else { break; } } if (**i == '\'') { if (quot) { ++*i; break; } else { throw soci_error(err); } } if (not quot and std::isspace(**i)) { break; } if (**i == '\\') { ++*i; if (*i == end) { throw soci_error(err); } } val += **i; ++*i; } return val; } bool valid_int(const string & s) { char *tail; const char *cstr = s.c_str(); errno = 0; long n = std::strtol(cstr, &tail, 10); if (errno != 0 or n > INT_MAX or n < INT_MIN) { return false; } if (*tail != '\0') { return false; } return true; } void parse_connect_string(const string & connectString, string *host, bool *host_p, string *user, bool *user_p, string *password, bool *password_p, string *db, bool *db_p, string *unix_socket, bool *unix_socket_p, int *port, bool *port_p, string *ssl_ca, bool *ssl_ca_p, string *ssl_cert, bool *ssl_cert_p, string *ssl_key, bool *ssl_key_p, int *local_infile, bool *local_infile_p, string *charset, bool *charset_p) { *host_p = false; *user_p = false; *password_p = false; *db_p = false; *unix_socket_p = false; *port_p = false; *ssl_ca_p = false; *ssl_cert_p = false; *ssl_key_p = false; *local_infile_p = false; *charset_p = false; string err = "Malformed connection string."; string::const_iterator i = connectString.begin(), end = connectString.end(); while (i != end) { skip_white(&i, end, true); if (i == end) { return; } string par = param_name(&i, end); skip_white(&i, end, false); if (*i == '=') { ++i; } else { throw soci_error(err); } skip_white(&i, end, false); string val = param_value(&i, end); if (par == "port" and not *port_p) { if (not valid_int(val)) { throw soci_error(err); } *port = std::atoi(val.c_str()); if (port < 0) { throw soci_error(err); } *port_p = true; } else if (par == "host" and not *host_p) { *host = val; *host_p = true; } else if (par == "user" and not *user_p) { *user = val; *user_p = true; } else if ((par == "pass" or par == "password") and not *password_p) { *password = val; *password_p = true; } else if ((par == "db" or par == "dbname" or par == "service") and not *db_p) { *db = val; *db_p = true; } else if (par == "unix_socket" and not *unix_socket_p) { *unix_socket = val; *unix_socket_p = true; } else if (par == "sslca" and not *ssl_ca_p) { *ssl_ca = val; *ssl_ca_p = true; } else if (par == "sslcert" and not *ssl_cert_p) { *ssl_cert = val; *ssl_cert_p = true; } else if (par == "sslkey" and not *ssl_key_p) { *ssl_key = val; *ssl_key_p = true; } else if (par == "local_infile" and not *local_infile_p) { if (not valid_int(val)) { throw soci_error(err); } *local_infile = std::atoi(val.c_str()); if (*local_infile != 0 and *local_infile != 1) { throw soci_error(err); } *local_infile_p = true; } else if (par == "charset" and not *charset_p) { *charset = val; *charset_p = true; } else { throw soci_error(err); } } } } // namespace anonymous mysql_session_backend::mysql_session_backend( connection_parameters const & parameters) { string host, user, password, db, unix_socket, ssl_ca, ssl_cert, ssl_key, charset; int port, local_infile; bool host_p, user_p, password_p, db_p, unix_socket_p, port_p, ssl_ca_p, ssl_cert_p, ssl_key_p, local_infile_p, charset_p; parse_connect_string(parameters.get_connect_string(), &host, &host_p, &user, &user_p, &password, &password_p, &db, &db_p, &unix_socket, &unix_socket_p, &port, &port_p, &ssl_ca, &ssl_ca_p, &ssl_cert, &ssl_cert_p, &ssl_key, &ssl_key_p, &local_infile, &local_infile_p, &charset, &charset_p); conn_ = mysql_init(NULL); if (conn_ == NULL) { throw soci_error("mysql_init() failed."); } if (charset_p) { if (0 != mysql_options(conn_, MYSQL_SET_CHARSET_NAME, charset.c_str())) { clean_up(); throw soci_error("mysql_options(MYSQL_SET_CHARSET_NAME) failed."); } } if (ssl_ca_p) { mysql_ssl_set(conn_, ssl_key_p ? ssl_key.c_str() : NULL, ssl_cert_p ? ssl_cert.c_str() : NULL, ssl_ca_p ? ssl_ca.c_str() : NULL, 0, 0); } if (local_infile_p and local_infile == 1) { if (0 != mysql_options(conn_, MYSQL_OPT_LOCAL_INFILE, NULL)) { clean_up(); throw soci_error( "mysql_options() failed when trying to set local-infile."); } } if (mysql_real_connect(conn_, host_p ? host.c_str() : NULL, user_p ? user.c_str() : NULL, password_p ? password.c_str() : NULL, db_p ? db.c_str() : NULL, port_p ? port : 0, unix_socket_p ? unix_socket.c_str() : NULL, #ifdef CLIENT_MULTI_RESULTS CLIENT_FOUND_ROWS | CLIENT_MULTI_RESULTS) == NULL) #else CLIENT_FOUND_ROWS) == NULL) #endif { string errMsg = mysql_error(conn_); unsigned int errNum = mysql_errno(conn_); clean_up(); throw mysql_soci_error(errMsg, errNum); } } mysql_session_backend::~mysql_session_backend() { clean_up(); } namespace // unnamed { // helper function for hardcoded queries void hard_exec(MYSQL *conn, const string & query) { if (0 != mysql_real_query(conn, query.c_str(), static_cast(query.size()))) { throw soci_error(mysql_error(conn)); } } } // namespace unnamed void mysql_session_backend::begin() { hard_exec(conn_, "BEGIN"); } void mysql_session_backend::commit() { hard_exec(conn_, "COMMIT"); } void mysql_session_backend::rollback() { hard_exec(conn_, "ROLLBACK"); } void mysql_session_backend::clean_up() { if (conn_ != NULL) { mysql_close(conn_); conn_ = NULL; } } mysql_statement_backend * mysql_session_backend::make_statement_backend() { return new mysql_statement_backend(*this); } mysql_rowid_backend * mysql_session_backend::make_rowid_backend() { return new mysql_rowid_backend(*this); } mysql_blob_backend * mysql_session_backend::make_blob_backend() { return new mysql_blob_backend(*this); } soci-3.2.3/backends/mysql/Makefile.basic0000644000000000000000000000511012505151606016607 0ustar rootroot# The following variables are specific to this backend and their correct # values might depend on your environment - feel free to set it accordingly. MYSQLLIBDIR = -L/usr/lib/mysql MYSQLLIBS = -lmysqlclient -lz MYSQLINCLUDEDIR = -I/usr/include/mysql # The rest of the Makefile is independent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long CXXFLAGSSO = ${CXXFLAGS} -fPIC INCLUDEDIRS = -I../../core ${MYSQLINCLUDEDIR} OBJECTS = blob.o factory.o row-id.o session.o standard-into-type.o \ standard-use-type.o statement.o vector-into-type.o vector-use-type.o \ common.o OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \ standard-into-type-s.o standard-use-type-s.o statement-s.o \ vector-into-type-s.o vector-use-type-s.o common-s.o libsoci_mysql.a : ${OBJECTS} ar rv $@ $? rm *.o blob.o : blob.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} common.o : common.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} factory.o : factory.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} row-id.o : row-id.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} session.o : session.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-into-type.o : standard-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-use-type.o : standard-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} statement.o : statement.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-into-type.o : vector-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-use-type.o : vector-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} shared : ${OBJECTSSO} ${COMPILER} -shared -o libsoci_mysql.so ${OBJECTSSO} rm *.o blob-s.o : blob.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} common-s.o : common.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} factory-s.o : factory.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} row-id-s.o : row-id.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} session-s.o : session.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} standard-into-type-s.o : standard-into-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} standard-use-type-s.o : standard-use-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} statement-s.o : statement.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} vector-into-type-s.o : vector-into-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} vector-use-type-s.o : vector-use-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} clean : rm -f libsoci_mysql.a libsoci_mysql.so soci-3.2.3/backends/mysql/factory.cpp0000644000000000000000000000177412511361676016265 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_MYSQL_SOURCE #include "soci-mysql.h" #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; // concrete factory for MySQL concrete strategies mysql_session_backend * mysql_backend_factory::make_session( connection_parameters const & parameters) const { return new mysql_session_backend(parameters); } mysql_backend_factory const soci::mysql; extern "C" { // for dynamic backend loading SOCI_MYSQL_DECL backend_factory const * factory_mysql() { return &soci::mysql; } SOCI_MYSQL_DECL void register_factory_mysql() { soci::dynamic_backends::register_backend("mysql", soci::mysql); } } // extern "C" soci-3.2.3/backends/mysql/row-id.cpp0000644000000000000000000000130112511361676016001 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_MYSQL_SOURCE #include "soci-mysql.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4355 4702) #endif using namespace soci; using namespace soci::details; mysql_rowid_backend::mysql_rowid_backend( mysql_session_backend & /* session */) { throw soci_error("RowIDs are not supported."); } mysql_rowid_backend::~mysql_rowid_backend() { } #ifdef _MSC_VER #pragma warning(pop) #endif soci-3.2.3/backends/mysql/standard-into-type.cpp0000644000000000000000000000727212511361676020343 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_MYSQL_SOURCE #include "soci-mysql.h" #include #include "common.h" // std #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace soci::details::mysql; void mysql_standard_into_type_backend::define_by_pos( int &position, void *data, exchange_type type) { data_ = data; type_ = type; position_ = position++; } void mysql_standard_into_type_backend::pre_fetch() { // nothing to do here } void mysql_standard_into_type_backend::post_fetch( bool gotData, bool calledFromFetch, indicator *ind) { if (calledFromFetch == true && gotData == false) { // this is a normal end-of-rowset condition, // no need to do anything (fetch() will return false) return; } if (gotData) { int pos = position_ - 1; //mysql_data_seek(statement_.result_, statement_.currentRow_); mysql_row_seek(statement_.result_, statement_.resultRowOffsets_[statement_.currentRow_]); MYSQL_ROW row = mysql_fetch_row(statement_.result_); if (row[pos] == NULL) { if (ind == NULL) { throw soci_error( "Null value fetched and no indicator defined."); } *ind = i_null; return; } else { if (ind != NULL) { *ind = i_ok; } } const char *buf = row[pos] != NULL ? row[pos] : ""; switch (type_) { case x_char: { char *dest = static_cast(data_); *dest = *buf; } break; case x_stdstring: { std::string *dest = static_cast(data_); unsigned long * lengths = mysql_fetch_lengths(statement_.result_); dest->assign(buf, lengths[pos]); } break; case x_short: { short *dest = static_cast(data_); parse_num(buf, *dest); } break; case x_integer: { int *dest = static_cast(data_); parse_num(buf, *dest); } break; case x_long_long: { long long *dest = static_cast(data_); parse_num(buf, *dest); } break; case x_unsigned_long_long: { unsigned long long *dest = static_cast(data_); parse_num(buf, *dest); } break; case x_double: { double *dest = static_cast(data_); parse_num(buf, *dest); } break; case x_stdtm: { // attempt to parse the string and convert to std::tm std::tm *dest = static_cast(data_); parse_std_tm(buf, *dest); } break; default: throw soci_error("Into element used with non-supported type."); } } } void mysql_standard_into_type_backend::clean_up() { // nothing to do here } soci-3.2.3/backends/mysql/test/0000755000000000000000000000000012511362240015044 5ustar rootrootsoci-3.2.3/backends/mysql/test/test-mysql.cpp0000644000000000000000000007122412511362240017700 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci.h" #include "soci-mysql.h" #include "test/common-tests.h" #include #include #include #include #include #include #include #include #include #include #include using namespace soci; using namespace soci::tests; std::string connectString; backend_factory const &backEnd = *soci::factory_mysql(); // procedure call test void test1() { { session sql(backEnd, connectString); mysql_session_backend *sessionBackEnd = static_cast(sql.get_backend()); std::string version = mysql_get_server_info(sessionBackEnd->conn_); int v; std::istringstream iss(version); if ((iss >> v) and v < 5) { std::cout << "skipping test 1 (MySQL server version "; std::cout << version << " does not support stored procedures)\n"; return; } try { sql << "drop function myecho"; } catch (soci_error const &) {} sql << "create function myecho(msg text) " "returns text deterministic " " return msg; "; std::string in("my message"); std::string out; statement st = (sql.prepare << "select myecho(:input)", into(out), use(in, "input")); st.execute(1); assert(out == in); // explicit procedure syntax { std::string in("my message2"); std::string out; procedure proc = (sql.prepare << "myecho(:input)", into(out), use(in, "input")); proc.execute(1); assert(out == in); } sql << "drop function myecho"; } std::cout << "test 1 passed" << std::endl; } // MySQL error reporting test. void test2() { { try { session sql(backEnd, "host=test.soci.invalid"); } catch (mysql_soci_error const &e) { assert(e.err_num_ == CR_UNKNOWN_HOST || e.err_num_ == CR_CONN_HOST_ERROR); } } { session sql(backEnd, connectString); sql << "create table soci_test (id integer)"; try { int n; sql << "select id from soci_test_nosuchtable", into(n); } catch (mysql_soci_error const &e) { assert(e.err_num_ == ER_NO_SUCH_TABLE); } try { sql << "insert into soci_test (invalid) values (256)"; } catch (mysql_soci_error const &e) { assert(e.err_num_ == ER_BAD_FIELD_ERROR); } // A bulk operation. try { std::vector v(3, 5); sql << "insert into soci_test_nosuchtable values (:n)", use(v); } catch (mysql_soci_error const &e) { assert(e.err_num_ == ER_NO_SUCH_TABLE); } sql << "drop table soci_test"; } std::cout << "test 2 passed" << std::endl; } struct bigint_table_creator : table_creator_base { bigint_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val bigint)"; } }; struct bigint_unsigned_table_creator : table_creator_base { bigint_unsigned_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val bigint unsigned)"; } }; // long long test void test3() { { session sql(backEnd, connectString); bigint_table_creator tableCreator(sql); long long v1 = 1000000000000LL; assert(v1 / 1000000 == 1000000); sql << "insert into soci_test(val) values(:val)", use(v1); long long v2 = 0LL; sql << "select val from soci_test", into(v2); assert(v2 == v1); } // vector { session sql(backEnd, connectString); bigint_table_creator tableCreator(sql); std::vector v1; v1.push_back(1000000000000LL); v1.push_back(1000000000001LL); v1.push_back(1000000000002LL); v1.push_back(1000000000003LL); v1.push_back(1000000000004LL); sql << "insert into soci_test(val) values(:val)", use(v1); std::vector v2(10); sql << "select val from soci_test order by val desc", into(v2); assert(v2.size() == 5); assert(v2[0] == 1000000000004LL); assert(v2[1] == 1000000000003LL); assert(v2[2] == 1000000000002LL); assert(v2[3] == 1000000000001LL); assert(v2[4] == 1000000000000LL); } { session sql(backEnd, connectString); bigint_unsigned_table_creator tableCreator(sql); sql << "insert into soci_test set val = 18446744073709551615"; row v; sql << "select * from soci_test", into(v); } { session sql(backEnd, connectString); bigint_unsigned_table_creator tableCreator(sql); const char* source = "18446744073709551615"; sql << "insert into soci_test set val = " << source; unsigned long long vv = 0; sql << "select val from soci_test", into(vv); std::stringstream buf; buf << vv; assert(buf.str() == source); } { session sql(backEnd, connectString); bigint_unsigned_table_creator tableCreator(sql); const char* source = "18446744073709551615"; sql << "insert into soci_test set val = " << source; std::vector v(1); sql << "select val from soci_test", into(v); std::stringstream buf; buf << v.at(0); assert(buf.str() == source); } { session sql(backEnd, connectString); bigint_unsigned_table_creator tableCreator(sql); unsigned long long n = 18446744073709551615ULL; sql << "insert into soci_test(val) values (:n)", use(n); unsigned long long m = 0; sql << "select val from soci_test", into(m); assert(n == m); } { session sql(backEnd, connectString); bigint_unsigned_table_creator tableCreator(sql); std::vector v1; v1.push_back(18446744073709551615ULL); v1.push_back(18446744073709551614ULL); v1.push_back(18446744073709551613ULL); sql << "insert into soci_test(val) values(:val)", use(v1); std::vector v2(10); sql << "select val from soci_test order by val", into(v2); assert(v2.size() == 3); assert(v2[0] == 18446744073709551613ULL); assert(v2[1] == 18446744073709551614ULL); assert(v2[2] == 18446744073709551615ULL); } std::cout << "test 3 passed" << std::endl; } template void test_num(const char* s, bool valid, T value) { try { session sql(backEnd, connectString); T val; sql << "select \'" << s << "\'", into(val); if (valid) { double v1 = static_cast(value); double v2 = static_cast(val); double d = std::fabs(v1 - v2); double epsilon = 0.001; assert(d < epsilon || d < epsilon * (std::fabs(v1) + std::fabs(v2))); } else { std::cout << "string \"" << s << "\" parsed as " << val << " but should have failed.\n"; assert(false); } } catch (soci_error const& e) { if (valid) { std::cout << "couldn't parse number: \"" << s << "\"\n"; assert(false); } else { assert(std::string(e.what()) == "Cannot convert data."); } } } // Number conversion test. void test4() { test_num("", false, 0); test_num("foo", false, 0); test_num("1", true, 1); test_num("12", true, 12); test_num("123", true, 123); test_num("12345", true, 12345); test_num("12341234123412341234123412341234123412341234123412341", true, 1.23412e+52); test_num("99999999999999999999999912222222222222222222222222223" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333" "9999999999999999999999991222222222222222222222222222333333333333", false, 0); test_num("1e3", true, 1000); test_num("1.2", true, 1.2); test_num("1.2345e2", true, 123.45); test_num("1 ", false, 0); test_num(" 123", true, 123); test_num("1,2", false, 0); test_num("123abc", false, 0); test_num("-0", true, 0); test_num("123", true, 123); test_num("100000", false, 0); test_num("123", true, 123); test_num("2147483647", true, 2147483647); test_num("2147483647a", false, 0); test_num("2147483648", false, 0); // -2147483648 causes a warning because it is interpreted as // 2147483648 (which doesn't fit in an integer) to which a negation // is applied. test_num("-2147483648", true, -2147483647 - 1); test_num("-2147483649", false, 0); test_num("-0", true, 0); test_num("1.1", false, 0); test_num("123", true, 123); test_num("9223372036854775807", true, 9223372036854775807LL); test_num("9223372036854775808", false, 0); std::cout << "test 4 passed" << std::endl; } void test5() { session sql(backEnd, connectString); std::tm t; sql << "select maketime(19, 54, 52)", into(t); assert(t.tm_year == 100); assert(t.tm_mon == 0); assert(t.tm_mday == 1); assert(t.tm_hour == 19); assert(t.tm_min == 54); assert(t.tm_sec == 52); std::cout << "test 5 passed" << std::endl; } // TEXT and BLOB types support test. void test6() { session sql(backEnd, connectString); std::string a("asdfg\0hjkl", 10); std::string b("lkjhg\0fd\0\0sa\0", 13); std::string c("\\0aa\\0bb\\0cc\\0", 10); // The maximum length for TEXT and BLOB is 65536. std::string x(60000, 'X'); std::string y(60000, 'Y'); // The default max_allowed_packet value for a MySQL server is 1M, // so let's limit ourselves to 800k, even though the maximum length // for LONGBLOB is 4G. std::string z(800000, 'Z'); sql << "create table soci_test (id int, text_value text, " "blob_value blob, longblob_value longblob)"; sql << "insert into soci_test values (1, \'foo\', \'bar\', \'baz\')"; sql << "insert into soci_test " << "values (2, \'qwerty\\0uiop\', \'zxcv\\0bnm\', " << "\'qwerty\\0uiop\\0zxcvbnm\\0\')"; sql << "insert into soci_test values (3, :a, :b, :c)", use(a), use(b), use(c); sql << "insert into soci_test values (4, :x, :y, :z)", use(x), use(y), use(z); std::vector text_vec(100); std::vector blob_vec(100); std::vector longblob_vec(100); sql << "select text_value, blob_value, longblob_value " << "from soci_test order by id", into(text_vec), into(blob_vec), into(longblob_vec); assert(text_vec.size() == 4); assert(blob_vec.size() == 4); assert(longblob_vec.size() == 4); assert(text_vec[0] == "foo"); assert(blob_vec[0] == "bar"); assert(longblob_vec[0] == "baz"); assert(text_vec[1] == std::string("qwerty\0uiop", 11)); assert(blob_vec[1] == std::string("zxcv\0bnm", 8)); assert(longblob_vec[1] == std::string("qwerty\0uiop\0zxcvbnm\0", 20)); assert(text_vec[2] == a); assert(blob_vec[2] == b); assert(longblob_vec[2] == c); assert(text_vec[3] == x); assert(blob_vec[3] == y); assert(longblob_vec[3] == z); std::string text, blob, longblob; sql << "select text_value, blob_value, longblob_value " << "from soci_test where id = 1", into(text), into(blob), into(longblob); assert(text == "foo"); assert(blob == "bar"); assert(longblob == "baz"); sql << "select text_value, blob_value, longblob_value " << "from soci_test where id = 2", into(text), into(blob), into(longblob); assert(text == std::string("qwerty\0uiop", 11)); assert(blob == std::string("zxcv\0bnm", 8)); assert(longblob == std::string("qwerty\0uiop\0zxcvbnm\0", 20)); sql << "select text_value, blob_value, longblob_value " << "from soci_test where id = 3", into(text), into(blob), into(longblob); assert(text == a); assert(blob == b); assert(longblob == c); sql << "select text_value, blob_value, longblob_value " << "from soci_test where id = 4", into(text), into(blob), into(longblob); assert(text == x); assert(blob == y); assert(longblob == z); rowset rs = (sql.prepare << "select text_value, blob_value, longblob_value " "from soci_test order by id"); rowset::const_iterator r = rs.begin(); assert(r->get_properties(0).get_data_type() == dt_string); assert(r->get(0) == "foo"); assert(r->get_properties(1).get_data_type() == dt_string); assert(r->get(1) == "bar"); assert(r->get_properties(2).get_data_type() == dt_string); assert(r->get(2) == "baz"); ++r; assert(r->get_properties(0).get_data_type() == dt_string); assert(r->get(0) == std::string("qwerty\0uiop", 11)); assert(r->get_properties(1).get_data_type() == dt_string); assert(r->get(1) == std::string("zxcv\0bnm", 8)); assert(r->get_properties(2).get_data_type() == dt_string); assert(r->get(2) == std::string("qwerty\0uiop\0zxcvbnm\0", 20)); ++r; assert(r->get_properties(0).get_data_type() == dt_string); assert(r->get(0) == a); assert(r->get_properties(1).get_data_type() == dt_string); assert(r->get(1) == b); assert(r->get_properties(2).get_data_type() == dt_string); assert(r->get(2) == c); ++r; assert(r->get_properties(0).get_data_type() == dt_string); assert(r->get(0) == x); assert(r->get_properties(1).get_data_type() == dt_string); assert(r->get(1) == y); assert(r->get_properties(2).get_data_type() == dt_string); assert(r->get(2) == z); ++r; assert(r == rs.end()); sql << "drop table soci_test"; std::cout << "test 6 passed" << std::endl; } // test for number of affected rows struct integer_value_table_creator : table_creator_base { integer_value_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val integer)"; } }; void test7() { { session sql(backEnd, connectString); integer_value_table_creator tableCreator(sql); for (int i = 0; i != 10; i++) { sql << "insert into soci_test(val) values(:val)", use(i); } statement st1 = (sql.prepare << "update soci_test set val = val + 1"); st1.execute(false); assert(st1.get_affected_rows() == 10); statement st2 = (sql.prepare << "delete from soci_test where val <= 5"); st2.execute(false); assert(st2.get_affected_rows() == 5); } std::cout << "test 7 passed" << std::endl; } // The prepared statements should survive session::reconnect(). void test8() { { session sql(backEnd, connectString); integer_value_table_creator tableCreator(sql); int i; statement st = (sql.prepare << "insert into soci_test(val) values(:val)", use(i)); i = 5; st.execute(true); sql.reconnect(); i = 6; st.execute(true); sql.close(); sql.reconnect(); i = 7; st.execute(true); std::vector v(5); sql << "select val from soci_test order by val", into(v); assert(v.size() == 3); assert(v[0] == 5); assert(v[1] == 6); assert(v[2] == 7); } std::cout << "test 8 passed" << std::endl; } struct unsigned_value_table_creator : table_creator_base { unsigned_value_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val int unsigned)"; } }; // rowset<> should be able to take INT UNSIGNED. void test9() { { session sql(backEnd, connectString); unsigned_value_table_creator tableCreator(sql); unsigned int mask = 0xffffff00; sql << "insert into soci_test set val = " << mask; soci::rowset<> rows(sql.prepare << "select val from soci_test"); int cnt = 0; for (soci::rowset<>::iterator it = rows.begin(), end = rows.end(); it != end; ++it) { cnt++; } assert(cnt == 1); } std::cout << "test 9 passed" << std::endl; } void test10() { session sql(backEnd, connectString); row r; sql << "set @day = '5'"; sql << "set @mm = 'december'"; sql << "set @year = '2012'"; sql << "select concat(@day,' ',@mm,' ',@year)", into(r); std::cout << "test 10 passed" << std::endl; } struct double_value_table_creator : table_creator_base { double_value_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val double)"; } }; void test11() { const std::string expectedError = "Use element used with infinity or NaN, which are " "not supported by the MySQL server."; { session sql(backEnd, connectString); double x = std::numeric_limits::quiet_NaN(); statement st = (sql.prepare << "SELECT :x", use(x, "x")); try { st.execute(true); } catch (soci_error const &e) { if (e.what() != expectedError) { throw; } } } { session sql(backEnd, connectString); double x = std::numeric_limits::infinity(); statement st = (sql.prepare << "SELECT :x", use(x, "x")); try { st.execute(true); } catch (soci_error const &e) { if (e.what() != expectedError) { throw; } } } { session sql(backEnd, connectString); double_value_table_creator tableCreator(sql); std::vector v(1, std::numeric_limits::quiet_NaN()); try { sql << "insert into soci_test (val) values (:val)", use(v); } catch (soci_error const &e) { if (e.what() != expectedError) { throw; } } } { session sql(backEnd, connectString); double_value_table_creator tableCreator(sql); std::vector v(1, std::numeric_limits::infinity()); try { sql << "insert into soci_test (val) values (:val)", use(v); } catch (soci_error const &e) { if (e.what() != expectedError) { throw; } } } std::cout << "test 11 passed" << std::endl; } struct tinyint_value_table_creator : table_creator_base { tinyint_value_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val tinyint)"; } }; struct tinyint_unsigned_value_table_creator : table_creator_base { tinyint_unsigned_value_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val tinyint unsigned)"; } }; void test12() { { session sql(backEnd, connectString); unsigned_value_table_creator tableCreator(sql); unsigned int mask = 0xffffff00; sql << "insert into soci_test set val = " << mask; row r; sql << "select val from soci_test", into(r); assert(r.size() == 1); assert(r.get_properties("val").get_data_type() == dt_long_long); assert(r.get("val") == 0xffffff00); assert(r.get("val") == 0xffffff00); } { session sql(backEnd, connectString); tinyint_value_table_creator tableCreator(sql); sql << "insert into soci_test set val = -123"; row r; sql << "select val from soci_test", into(r); assert(r.size() == 1); assert(r.get_properties("val").get_data_type() == dt_integer); assert(r.get("val") == -123); } { session sql(backEnd, connectString); tinyint_unsigned_value_table_creator tableCreator(sql); sql << "insert into soci_test set val = 123"; row r; sql << "select val from soci_test", into(r); assert(r.size() == 1); assert(r.get_properties("val").get_data_type() == dt_integer); assert(r.get("val") == 123); } { session sql(backEnd, connectString); bigint_unsigned_table_creator tableCreator(sql); sql << "insert into soci_test set val = 123456789012345"; row r; sql << "select val from soci_test", into(r); assert(r.size() == 1); assert(r.get_properties("val").get_data_type() == dt_unsigned_long_long); assert(r.get("val") == 123456789012345ULL); } { session sql(backEnd, connectString); bigint_table_creator tableCreator(sql); sql << "insert into soci_test set val = -123456789012345"; row r; sql << "select val from soci_test", into(r); assert(r.size() == 1); assert(r.get_properties("val").get_data_type() == dt_long_long); assert(r.get("val") == -123456789012345LL); } std::cout << "test 12 passed" << std::endl; } struct strings_table_creator : table_creator_base { strings_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(s1 char(20), s2 varchar(20), " "s3 tinytext, s4 mediumtext, s5 text, s6 longtext, " "b1 binary(20), b2 varbinary(20), b3 tinyblob, b4 mediumblob, " "b5 blob, b6 longblob, e1 enum ('foo', 'bar', 'baz'))"; } }; void test13() { { session sql(backEnd, connectString); strings_table_creator tableCreator(sql); std::string text = "Ala ma kota."; std::string binary("Ala\0ma\0kota.........", 20); sql << "insert into soci_test " "(s1, s2, s3, s4, s5, s6, b1, b2, b3, b4, b5, b6, e1) values " "(:s1, :s2, :s3, :s4, :d5, :s6, :b1, :b2, :b3, :b4, :b5, :b6, " "\'foo\')", use(text), use(text), use(text), use(text), use(text), use(text), use(binary), use(binary), use(binary), use(binary), use(binary), use(binary); row r; sql << "select s1, s2, s3, s4, s5, s6, b1, b2, b3, b4, b5, b6, e1 " "from soci_test", into(r); assert(r.size() == 13); for (int i = 0; i < 13; i++) { assert(r.get_properties(i).get_data_type() == dt_string); if (i < 6) { assert(r.get(i) == text); } else if (i < 12) { assert(r.get(i) == binary); } else { assert(r.get(i) == "foo"); } } } std::cout << "test 13 passed" << std::endl; } std::string escape_string(soci::session& sql, const std::string& s) { mysql_session_backend* backend = static_cast( sql.get_backend()); char* escaped = new char[2 * s.size() + 1]; mysql_real_escape_string(backend->conn_, escaped, s.data(), s.size()); std::string retv = escaped; delete [] escaped; return retv; } void test14() { { session sql(backEnd, connectString); strings_table_creator tableCreator(sql); std::string s = "word1'word2:word3"; std::string escaped = escape_string(sql, s); std::string query = "insert into soci_test (s5) values ('"; query.append(escaped); query.append("')"); sql << query; std::string s2; sql << "select s5 from soci_test", into(s2); assert(s == s2); } std::cout << "test 14 passed" << std::endl; } void test15() { { session sql(backEnd, connectString); int n; sql << "select @a := 123", into(n); assert(n == 123); } std::cout << "test 15 passed" << std::endl; } // DDL Creation objects for common tests struct table_creator_one : public table_creator_base { table_creator_one(session & sql) : table_creator_base(sql) { sql << "create table soci_test(id integer, val integer, c char, " "str varchar(20), sh int2, ul numeric(20), d float8, " "tm datetime, i1 integer, i2 integer, i3 integer, " "name varchar(20)) engine=InnoDB"; } }; struct table_creator_two : public table_creator_base { table_creator_two(session & sql) : table_creator_base(sql) { sql << "create table soci_test(num_float float8, num_int integer," " name varchar(20), sometime datetime, chr char)"; } }; struct table_creator_three : public table_creator_base { table_creator_three(session & sql) : table_creator_base(sql) { sql << "create table soci_test(name varchar(100) not null, " "phone varchar(15))"; } }; struct table_creator_for_get_affected_rows : table_creator_base { table_creator_for_get_affected_rows(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val integer)"; } }; // // Support for SOCI Common Tests // class test_context : public test_context_base { public: test_context(backend_factory const &backEnd, std::string const &connectString) : test_context_base(backEnd, connectString) {} table_creator_base* table_creator_1(session& s) const { return new table_creator_one(s); } table_creator_base* table_creator_2(session& s) const { return new table_creator_two(s); } table_creator_base* table_creator_3(session& s) const { return new table_creator_three(s); } table_creator_base* table_creator_4(session& s) const { return new table_creator_for_get_affected_rows(s); } std::string to_date_time(std::string const &datdt_string) const { return "\'" + datdt_string + "\'"; } }; bool are_transactions_supported() { session sql(backEnd, connectString); sql << "drop table if exists soci_test"; sql << "create table soci_test (id int) engine=InnoDB"; row r; sql << "show table status like \'soci_test\'", into(r); bool retv = (r.get(1) == "InnoDB"); sql << "drop table soci_test"; return retv; } int main(int argc, char** argv) { if (argc == 2) { connectString = argv[1]; } else { std::cout << "usage: " << argv[0] << " connectstring\n" << "example: " << argv[0] << " \"dbname=test user=root password=\'Ala ma kota\'\"\n"; std::exit(1); } try { test_context tc(backEnd, connectString); common_tests tests(tc); bool checkTransactions = are_transactions_supported(); tests.run(checkTransactions); std::cout << "\nSOCI MySQL Tests:\n\n"; test1(); test2(); test3(); test4(); test5(); test6(); test7(); // Test 8 commented out because a bug in soci can make it crash // https://github.com/SOCI/soci/issues/136 //test8(); test9(); test10(); if (std::numeric_limits::is_iec559) { test11(); } else { std::cout << "Skipping test11 " << "(C++ implementation's double type is not IEC-559)\n"; } test12(); test13(); test14(); test15(); std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; } catch (std::exception const & e) { std::cout << e.what() << '\n'; } return EXIT_FAILURE; } soci-3.2.3/backends/mysql/test/.gitignore0000644000000000000000000000001312511361676017042 0ustar rootroottest_mysql soci-3.2.3/backends/mysql/test/Makefile.basic0000644000000000000000000000121712511361676017601 0ustar rootroot# The following variables are specific to this backend and their correct # values might depend on your environment - feel free to set it accordingly. MYSQLLIBDIR = -L/usr/lib/mysql MYSQLLIBS = -lmysqlclient -lz MYSQLINCLUDEDIR = -I/usr/include/mysql # The rest of the Makefile is independent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long INCLUDEDIRS = -I.. -I../../../core ${MYSQLINCLUDEDIR} LIBDIRS = -L.. -L../../../core ${MYSQLLIBDIR} LIBS = -lsoci_core -lsoci_mysql -ldl ${MYSQLLIBS} test-mysql : test-mysql.cpp ${COMPILER} -o $@ $? ${CXXFLAGS} ${INCLUDEDIRS} ${LIBDIRS} ${LIBS} clean : rm -f test-mysql soci-3.2.3/backends/mysql/test/CMakeLists.txt0000644000000000000000000000075412511361676017626 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend_test( BACKEND MySQL SOURCE test-mysql.cpp CONNSTR "dummy")soci-3.2.3/backends/mysql/common.cpp0000644000000000000000000000351112511361676016075 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "common.h" #include "soci-backend.h" #include #include #include #include namespace // anonymous { // helper function for parsing decimal data (for std::tm) long parse10(char const *&p1, char *&p2, const char *msg) { long v = std::strtol(p1, &p2, 10); if (p2 != p1) { p1 = p2 + 1; return v; } else { throw soci::soci_error(msg); } } } // namespace anonymous void soci::details::mysql::parse_std_tm(char const *buf, std::tm &t) { char const *p1 = buf; char *p2; long year, month, day; long hour = 0, minute = 0, second = 0; const char *errMsg = "Cannot convert data to std::tm."; if (strchr(buf, '-') != NULL) { year = parse10(p1, p2, errMsg); month = parse10(p1, p2, errMsg); day = parse10(p1, p2, errMsg); } else { year = 2000; month = 1; day = 1; } if (strchr(buf, ':') != NULL) { // there is also the time of day available hour = parse10(p1, p2, errMsg); minute = parse10(p1, p2, errMsg); second = parse10(p1, p2, errMsg); } t.tm_isdst = -1; t.tm_year = year - 1900; t.tm_mon = month - 1; t.tm_mday = day; t.tm_hour = hour; t.tm_min = minute; t.tm_sec = second; std::mktime(&t); } char * soci::details::mysql::quote(MYSQL * conn, const char *s, int len) { char *retv = new char[2 * len + 3]; retv[0] = '\''; int len_esc = mysql_real_escape_string(conn, retv + 1, s, len); retv[len_esc + 1] = '\''; retv[len_esc + 2] = '\0'; return retv; } soci-3.2.3/backends/mysql/soci-mysql.h0000644000000000000000000001714712511362240016350 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_MYSQL_H_INCLUDED #define SOCI_MYSQL_H_INCLUDED #ifdef _WIN32 # ifdef SOCI_DLL # ifdef SOCI_MYSQL_SOURCE # define SOCI_MYSQL_DECL __declspec(dllexport) # else # define SOCI_MYSQL_DECL __declspec(dllimport) # endif // SOCI_DLL # endif // SOCI_MYSQL_SOURCE #endif // _WIN32 // // If SOCI_MYSQL_DECL isn't defined yet define it now #ifndef SOCI_MYSQL_DECL # define SOCI_MYSQL_DECL #endif #include "soci-backend.h" #ifdef _WIN32 #include // SOCKET #endif // _WIN32 #include // MySQL Client #include namespace soci { class mysql_soci_error : public soci_error { public: mysql_soci_error(std::string const & msg, int errNum) : soci_error(msg), err_num_(errNum) {} unsigned int err_num_; }; struct mysql_statement_backend; struct mysql_standard_into_type_backend : details::standard_into_type_backend { mysql_standard_into_type_backend(mysql_statement_backend &st) : statement_(st) {} virtual void define_by_pos(int &position, void *data, details::exchange_type type); virtual void pre_fetch(); virtual void post_fetch(bool gotData, bool calledFromFetch, indicator *ind); virtual void clean_up(); mysql_statement_backend &statement_; void *data_; details::exchange_type type_; int position_; }; struct mysql_vector_into_type_backend : details::vector_into_type_backend { mysql_vector_into_type_backend(mysql_statement_backend &st) : statement_(st) {} virtual void define_by_pos(int &position, void *data, details::exchange_type type); virtual void pre_fetch(); virtual void post_fetch(bool gotData, indicator *ind); virtual void resize(std::size_t sz); virtual std::size_t size(); virtual void clean_up(); mysql_statement_backend &statement_; void *data_; details::exchange_type type_; int position_; }; struct mysql_standard_use_type_backend : details::standard_use_type_backend { mysql_standard_use_type_backend(mysql_statement_backend &st) : statement_(st), position_(0), buf_(NULL) {} virtual void bind_by_pos(int &position, void *data, details::exchange_type type, bool readOnly); virtual void bind_by_name(std::string const &name, void *data, details::exchange_type type, bool readOnly); virtual void pre_use(indicator const *ind); virtual void post_use(bool gotData, indicator *ind); virtual void clean_up(); mysql_statement_backend &statement_; void *data_; details::exchange_type type_; int position_; std::string name_; char *buf_; }; struct mysql_vector_use_type_backend : details::vector_use_type_backend { mysql_vector_use_type_backend(mysql_statement_backend &st) : statement_(st), position_(0) {} virtual void bind_by_pos(int &position, void *data, details::exchange_type type); virtual void bind_by_name(std::string const &name, void *data, details::exchange_type type); virtual void pre_use(indicator const *ind); virtual std::size_t size(); virtual void clean_up(); mysql_statement_backend &statement_; void *data_; details::exchange_type type_; int position_; std::string name_; std::vector buffers_; }; struct mysql_session_backend; struct mysql_statement_backend : details::statement_backend { mysql_statement_backend(mysql_session_backend &session); virtual void alloc(); virtual void clean_up(); virtual void prepare(std::string const &query, details::statement_type eType); virtual exec_fetch_result execute(int number); virtual exec_fetch_result fetch(int number); virtual long long get_affected_rows(); virtual int get_number_of_rows(); virtual std::string rewrite_for_procedure_call(std::string const &query); virtual int prepare_for_describe(); virtual void describe_column(int colNum, data_type &dtype, std::string &columnName); virtual mysql_standard_into_type_backend * make_into_type_backend(); virtual mysql_standard_use_type_backend * make_use_type_backend(); virtual mysql_vector_into_type_backend * make_vector_into_type_backend(); virtual mysql_vector_use_type_backend * make_vector_use_type_backend(); mysql_session_backend &session_; MYSQL_RES *result_; // The query is split into chunks, separated by the named parameters; // e.g. for "SELECT id FROM ttt WHERE name = :foo AND gender = :bar" // we will have query chunks "SELECT id FROM ttt WHERE name = ", // "AND gender = " and names "foo", "bar". std::vector queryChunks_; std::vector names_; // list of names for named binds long long rowsAffectedBulk_; // number of rows affected by the last bulk operation int numberOfRows_; // number of rows retrieved from the server int currentRow_; // "current" row number to consume in postFetch int rowsToConsume_; // number of rows to be consumed in postFetch bool justDescribed_; // to optimize row description with immediately // following actual statement execution // Prefetch the row offsets in order to use mysql_row_seek() for // random access to rows, since mysql_data_seek() is expensive. std::vector resultRowOffsets_; bool hasIntoElements_; bool hasVectorIntoElements_; bool hasUseElements_; bool hasVectorUseElements_; // the following maps are used for finding data buffers according to // use elements specified by the user typedef std::map UseByPosBuffersMap; UseByPosBuffersMap useByPosBuffers_; typedef std::map UseByNameBuffersMap; UseByNameBuffersMap useByNameBuffers_; }; struct mysql_rowid_backend : details::rowid_backend { mysql_rowid_backend(mysql_session_backend &session); ~mysql_rowid_backend(); }; struct mysql_blob_backend : details::blob_backend { mysql_blob_backend(mysql_session_backend &session); ~mysql_blob_backend(); virtual std::size_t get_len(); virtual std::size_t read(std::size_t offset, char *buf, std::size_t toRead); virtual std::size_t write(std::size_t offset, char const *buf, std::size_t toWrite); virtual std::size_t append(char const *buf, std::size_t toWrite); virtual void trim(std::size_t newLen); mysql_session_backend &session_; }; struct mysql_session_backend : details::session_backend { mysql_session_backend(connection_parameters const & parameters); ~mysql_session_backend(); virtual void begin(); virtual void commit(); virtual void rollback(); virtual std::string get_backend_name() const { return "mysql"; } void clean_up(); virtual mysql_statement_backend * make_statement_backend(); virtual mysql_rowid_backend * make_rowid_backend(); virtual mysql_blob_backend * make_blob_backend(); MYSQL *conn_; }; struct mysql_backend_factory : backend_factory { mysql_backend_factory() {} virtual mysql_session_backend * make_session( connection_parameters const & parameters) const; }; extern SOCI_MYSQL_DECL mysql_backend_factory const mysql; extern "C" { // for dynamic backend loading SOCI_MYSQL_DECL backend_factory const * factory_mysql(); SOCI_MYSQL_DECL void register_factory_mysql(); } // extern "C" } // namespace soci #endif // SOCI_MYSQL_H_INCLUDED soci-3.2.3/backends/mysql/vector-into-type.cpp0000644000000000000000000001546212511361676020045 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_MYSQL_SOURCE #include "soci-mysql.h" #include "common.h" #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace soci::details::mysql; void mysql_vector_into_type_backend::define_by_pos( int &position, void *data, exchange_type type) { data_ = data; type_ = type; position_ = position++; } void mysql_vector_into_type_backend::pre_fetch() { // nothing to do here } namespace // anonymous { template void set_invector_(void *p, int indx, T const &val) { std::vector *dest = static_cast *>(p); std::vector &v = *dest; v[indx] = val; } } // namespace anonymous void mysql_vector_into_type_backend::post_fetch(bool gotData, indicator *ind) { if (gotData) { // Here, rowsToConsume_ in the Statement object designates // the number of rows that need to be put in the user's buffers. // MySQL column positions start at 0 int pos = position_ - 1; int const endRow = statement_.currentRow_ + statement_.rowsToConsume_; //mysql_data_seek(statement_.result_, statement_.currentRow_); mysql_row_seek(statement_.result_, statement_.resultRowOffsets_[statement_.currentRow_]); for (int curRow = statement_.currentRow_, i = 0; curRow != endRow; ++curRow, ++i) { MYSQL_ROW row = mysql_fetch_row(statement_.result_); // first, deal with indicators if (row[pos] == NULL) { if (ind == NULL) { throw soci_error( "Null value fetched and no indicator defined."); } ind[i] = i_null; // no need to convert data if it is null, go to next row continue; } else { if (ind != NULL) { ind[i] = i_ok; } } // buffer with data retrieved from server, in text format const char *buf = row[pos] != NULL ? row[pos] : ""; switch (type_) { case x_char: set_invector_(data_, i, *buf); break; case x_stdstring: { unsigned long * lengths = mysql_fetch_lengths(statement_.result_); // Not sure if it's necessary, but the code below is used // instead of // set_invector_(data_, i, std::string(buf, lengths[pos]); // to avoid copying the (possibly large) temporary string. std::vector *dest = static_cast *>(data_); (*dest)[i].assign(buf, lengths[pos]); } break; case x_short: { short val; parse_num(buf, val); set_invector_(data_, i, val); } break; case x_integer: { int val; parse_num(buf, val); set_invector_(data_, i, val); } break; case x_long_long: { long long val; parse_num(buf, val); set_invector_(data_, i, val); } break; case x_unsigned_long_long: { unsigned long long val; parse_num(buf, val); set_invector_(data_, i, val); } break; case x_double: { double val; parse_num(buf, val); set_invector_(data_, i, val); } break; case x_stdtm: { // attempt to parse the string and convert to std::tm std::tm t; parse_std_tm(buf, t); set_invector_(data_, i, t); } break; default: throw soci_error("Into element used with non-supported type."); } } } else // no data retrieved { // nothing to do, into vectors are already truncated } } namespace // anonymous { template void resizevector_(void *p, std::size_t sz) { std::vector *v = static_cast *>(p); v->resize(sz); } } // namespace anonymous void mysql_vector_into_type_backend::resize(std::size_t sz) { switch (type_) { // simple cases case x_char: resizevector_ (data_, sz); break; case x_short: resizevector_ (data_, sz); break; case x_integer: resizevector_ (data_, sz); break; case x_long_long: resizevector_ (data_, sz); break; case x_unsigned_long_long: resizevector_(data_, sz); break; case x_double: resizevector_ (data_, sz); break; case x_stdstring: resizevector_ (data_, sz); break; case x_stdtm: resizevector_ (data_, sz); break; default: throw soci_error("Into vector element used with non-supported type."); } } std::size_t mysql_vector_into_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type_) { // simple cases case x_char: sz = get_vector_size (data_); break; case x_short: sz = get_vector_size (data_); break; case x_integer: sz = get_vector_size (data_); break; case x_long_long: sz = get_vector_size (data_); break; case x_unsigned_long_long: sz = get_vector_size(data_); break; case x_double: sz = get_vector_size (data_); break; case x_stdstring: sz = get_vector_size (data_); break; case x_stdtm: sz = get_vector_size (data_); break; default: throw soci_error("Into vector element used with non-supported type."); } return sz; } void mysql_vector_into_type_backend::clean_up() { // nothing to do here } soci-3.2.3/backends/mysql/CMakeLists.txt0000644000000000000000000000120612511362240016624 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend(MySQL DEPENDS MySQL HEADERS soci-mysql.h common.h DESCRIPTION "SOCI backend for MySQL database engine" AUTHORS "Pawel Aleksander Fedorynski" MAINTAINERS "Pawel Aleksander Fedorynski") add_subdirectory(test) soci-3.2.3/backends/db2/0000755000000000000000000000000012511362240013367 5ustar rootrootsoci-3.2.3/backends/db2/common.h0000644000000000000000000000121212505151606015031 0ustar rootroot// // Copyright (C) 2013 Mateusz Loskot // Copyright (C) 2011-2013 Denis Chapligin // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_DB2_COMMON_H_INCLUDED #define SOCI_DB2_COMMON_H_INCLUDED #include namespace soci { namespace details { namespace db2 { const std::size_t cli_max_buffer = 1024 * 1024 * 1024; //CLI limit is about 3 GB, but 1GB should be enough }}} // namespace soci::details::db2 #endif // SOCI_DB2_COMMON_H_INCLUDED soci-3.2.3/backends/db2/blob.cpp0000644000000000000000000000215512511361676015030 0ustar rootroot// // Copyright (C) 2011-2013 Denis Chapligin // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_DB2_SOURCE #include "soci-db2.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; db2_blob_backend::db2_blob_backend(db2_session_backend &session) : session_(session) { // ... } db2_blob_backend::~db2_blob_backend() { // ... } std::size_t db2_blob_backend::get_len() { // ... return 0; } std::size_t db2_blob_backend::read( std::size_t /* offset */, char * /* buf */, std::size_t /* toRead */) { // ... return 0; } std::size_t db2_blob_backend::write( std::size_t /* offset */, char const * /* buf */, std::size_t /* toWrite */) { // ... return 0; } std::size_t db2_blob_backend::append( char const * /* buf */, std::size_t /* toWrite */) { // ... return 0; } void db2_blob_backend::trim(std::size_t /* newLen */) { // ... } soci-3.2.3/backends/db2/statement.cpp0000644000000000000000000002101312511361676016110 0ustar rootroot// // Copyright (C) 2011-2013 Denis Chapligin // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_DB2_SOURCE #include "soci-db2.h" #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; db2_statement_backend::db2_statement_backend(db2_session_backend &session) : session_(session),hasVectorUseElements(false),use_binding_method_(details::db2::BOUND_BY_NONE) { } void db2_statement_backend::alloc() { SQLRETURN cliRC = SQL_SUCCESS; cliRC = SQLAllocHandle(SQL_HANDLE_STMT,session_.hDbc,&hStmt); if (cliRC != SQL_SUCCESS) { throw db2_soci_error("Error while allocation statement handle",cliRC); } } void db2_statement_backend::clean_up() { SQLRETURN cliRC = SQL_SUCCESS; cliRC=SQLFreeHandle(SQL_HANDLE_STMT,hStmt); if (cliRC != SQL_SUCCESS) { throw db2_soci_error(db2_soci_error::sqlState("Statement handle clean-up error",SQL_HANDLE_STMT,hStmt),cliRC); } } void db2_statement_backend::prepare(std::string const & query , statement_type /* eType */) { // rewrite the query by transforming all named parameters into // the markers (:abc -> ?, etc.) enum { normal, in_quotes, in_name } state = normal; std::string name; for (std::string::const_iterator it = query.begin(), end = query.end(); it != end; ++it) { switch (state) { case normal: if (*it == '\'') { query_ += *it; state = in_quotes; } else if (*it == ':') { // Check whether this is a cast operator (e.g. 23::float) // and treat it as a special case, not as a named binding const std::string::const_iterator next_it = it + 1; if ((next_it != end) && (*next_it == ':')) { query_ += "::"; ++it; } else { state = in_name; } } else // regular character, stay in the same state { query_ += *it; } break; case in_quotes: if (*it == '\'') { query_ += *it; state = normal; } else // regular quoted character { query_ += *it; } break; case in_name: if (std::isalnum(*it) || *it == '_') { name += *it; } else // end of name { names.push_back(name); name.clear(); std::ostringstream ss; ss << '?'; query_ += ss.str(); query_ += *it; state = normal; } break; } } if (state == in_name) { names.push_back(name); std::ostringstream ss; ss << '?'; query_ += ss.str(); } SQLRETURN cliRC = SQLPrepare(hStmt, const_cast((const SQLCHAR *) query_.c_str()), SQL_NTS); if (cliRC!=SQL_SUCCESS) { throw db2_soci_error("Error while preparing query",cliRC); } } statement_backend::exec_fetch_result db2_statement_backend::execute(int number ) { SQLUINTEGER rows_processed = 0; SQLRETURN cliRC; if (hasVectorUseElements) { SQLSetStmtAttr(hStmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &rows_processed, 0); } // if we are called twice for the same statement we need to close the open // cursor or an "invalid cursor state" error will occur on execute cliRC = SQLFreeStmt(hStmt,SQL_CLOSE); if (cliRC != SQL_SUCCESS) { throw db2_soci_error(db2_soci_error::sqlState("Statement execution error",SQL_HANDLE_STMT,hStmt),cliRC); } cliRC = SQLExecute(hStmt); if (cliRC != SQL_SUCCESS && cliRC != SQL_SUCCESS_WITH_INFO) { throw db2_soci_error(db2_soci_error::sqlState("Statement execution error",SQL_HANDLE_STMT,hStmt),cliRC); } SQLSMALLINT colCount; SQLNumResultCols(hStmt, &colCount); if (number > 0 && colCount > 0) { return fetch(number); } return ef_success; } statement_backend::exec_fetch_result db2_statement_backend::fetch(int number ) { numRowsFetched = 0; SQLSetStmtAttr(hStmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0); SQLSetStmtAttr(hStmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)number, 0); SQLSetStmtAttr(hStmt, SQL_ATTR_ROWS_FETCHED_PTR, &numRowsFetched, 0); SQLRETURN cliRC = SQLFetch(hStmt); if (SQL_NO_DATA == cliRC) { return ef_no_data; } if (cliRC != SQL_SUCCESS && cliRC != SQL_SUCCESS_WITH_INFO) { throw db2_soci_error(db2_soci_error::sqlState("Error while fetching data", SQL_HANDLE_STMT, hStmt), cliRC); } return ef_success; } long long db2_statement_backend::get_affected_rows() { SQLLEN rows; SQLRETURN cliRC = SQLRowCount(hStmt, &rows); if (cliRC != SQL_SUCCESS && cliRC != SQL_SUCCESS_WITH_INFO) { throw db2_soci_error(db2_soci_error::sqlState("Error while getting affected row count", SQL_HANDLE_STMT, hStmt), cliRC); } else if (rows == -1) { throw soci_error("Error getting affected row count: statement did not perform an update, insert, delete, or merge"); } return rows; } int db2_statement_backend::get_number_of_rows() { return numRowsFetched; } std::string db2_statement_backend::rewrite_for_procedure_call( std::string const &query) { return query; } int db2_statement_backend::prepare_for_describe() { SQLSMALLINT numCols; SQLNumResultCols(hStmt, &numCols); return numCols; } void db2_statement_backend::describe_column(int colNum, data_type & type, std::string & columnName ) { SQLCHAR colNameBuffer[2048]; SQLSMALLINT colNameBufferOverflow; SQLSMALLINT dataType; SQLULEN colSize; SQLSMALLINT decDigits; SQLSMALLINT isNullable; SQLRETURN cliRC = SQLDescribeCol(hStmt, static_cast(colNum), colNameBuffer, 2048, &colNameBufferOverflow, &dataType, &colSize, &decDigits, &isNullable); if (cliRC != SQL_SUCCESS) { throw db2_soci_error(db2_soci_error::sqlState("Error while describing column",SQL_HANDLE_STMT,hStmt),cliRC); } char const *name = reinterpret_cast(colNameBuffer); columnName.assign(name, std::strlen(name)); switch (dataType) { case SQL_TYPE_DATE: case SQL_TYPE_TIME: case SQL_TYPE_TIMESTAMP: type = dt_date; break; case SQL_DOUBLE: case SQL_DECIMAL: case SQL_REAL: case SQL_FLOAT: case SQL_NUMERIC: type = dt_double; break; case SQL_TINYINT: case SQL_SMALLINT: case SQL_INTEGER: type = dt_integer; break; case SQL_BIGINT: type = dt_long_long; break; case SQL_CHAR: case SQL_VARCHAR: case SQL_LONGVARCHAR: default: type = dt_string; break; } } std::size_t db2_statement_backend::column_size(int col) { SQLCHAR colNameBuffer[2048]; SQLSMALLINT colNameBufferOverflow; SQLSMALLINT dataType; SQLULEN colSize; SQLSMALLINT decDigits; SQLSMALLINT isNullable; SQLRETURN cliRC = SQLDescribeCol(hStmt, static_cast(col), colNameBuffer, 2048, &colNameBufferOverflow, &dataType, &colSize, &decDigits, &isNullable); if (cliRC != SQL_SUCCESS) { throw db2_soci_error(db2_soci_error::sqlState("Error while detecting column size",SQL_HANDLE_STMT,hStmt),cliRC); } return colSize; } db2_standard_into_type_backend * db2_statement_backend::make_into_type_backend() { return new db2_standard_into_type_backend(*this); } db2_standard_use_type_backend * db2_statement_backend::make_use_type_backend() { return new db2_standard_use_type_backend(*this); } db2_vector_into_type_backend * db2_statement_backend::make_vector_into_type_backend() { return new db2_vector_into_type_backend(*this); } db2_vector_use_type_backend * db2_statement_backend::make_vector_use_type_backend() { hasVectorUseElements = true; return new db2_vector_use_type_backend(*this); } soci-3.2.3/backends/db2/vector-use-type.cpp0000644000000000000000000002601512511361676017166 0ustar rootroot// // Copyright (C) 2011-2013 Denis Chapligin // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_DB2_SOURCE #include "soci-db2.h" #include #include #include #include #include #ifdef _MSC_VER // disables the warning about converting int to void*. This is a 64 bit compatibility // warning, but odbc requires the value to be converted on this line // SQLSetStmtAttr(statement_.hstmt_, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)arraySize, 0); #pragma warning(disable:4312) #endif using namespace soci; using namespace soci::details; void db2_vector_use_type_backend::prepare_indicators(std::size_t size) { if (size == 0) { throw soci_error("Vectors of size 0 are not allowed."); } indVec.resize(size); indptr = &indVec[0]; } void db2_vector_use_type_backend::prepare_for_bind(void *&data, SQLUINTEGER &size, SQLSMALLINT &sqlType, SQLSMALLINT &cType) { switch (type) { // simple cases case x_short: { sqlType = SQL_SMALLINT; cType = SQL_C_SSHORT; size = sizeof(short); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_integer: { sqlType = SQL_INTEGER; cType = SQL_C_SLONG; size = sizeof(int); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_long_long: { sqlType = SQL_BIGINT; cType = SQL_C_SBIGINT; size = sizeof(long long); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_unsigned_long_long: { sqlType = SQL_BIGINT; cType = SQL_C_UBIGINT; size = sizeof(unsigned long long); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_double: { sqlType = SQL_DOUBLE; cType = SQL_C_DOUBLE; size = sizeof(double); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; // cases that require adjustments and buffer management case x_char: { std::vector *vp = static_cast *>(data); std::size_t const vsize = vp->size(); prepare_indicators(vsize); size = sizeof(char) * 2; buf = new char[size * vsize]; char *pos = buf; for (std::size_t i = 0; i != vsize; ++i) { *pos++ = (*vp)[i]; *pos++ = 0; } sqlType = SQL_CHAR; cType = SQL_C_CHAR; data = buf; } break; case x_stdstring: { sqlType = SQL_CHAR; cType = SQL_C_CHAR; std::vector *vp = static_cast *>(data); std::vector &v(*vp); std::size_t maxSize = 0; std::size_t const vecSize = v.size(); prepare_indicators(vecSize); for (std::size_t i = 0; i != vecSize; ++i) { std::size_t sz = v[i].length() + 1; // add one for null indVec[i] = static_cast(sz); maxSize = sz > maxSize ? sz : maxSize; } buf = new char[maxSize * vecSize]; memset(buf, 0, maxSize * vecSize); char *pos = buf; for (std::size_t i = 0; i != vecSize; ++i) { strncpy(pos, v[i].c_str(), v[i].length()); pos += maxSize; } data = buf; size = static_cast(maxSize); } break; case x_stdtm: { std::vector *vp = static_cast *>(data); prepare_indicators(vp->size()); buf = new char[sizeof(TIMESTAMP_STRUCT) * vp->size()]; sqlType = SQL_TYPE_TIMESTAMP; cType = SQL_C_TYPE_TIMESTAMP; data = buf; size = 19; // This number is not the size in bytes, but the number // of characters in the date if it was written out // yyyy-mm-dd hh:mm:ss } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } colSize = size; } void db2_vector_use_type_backend::bind_helper(int &position, void *data, details::exchange_type type) { this->data = data; // for future reference this->type = type; // for future reference SQLSMALLINT sqlType; SQLSMALLINT cType; SQLUINTEGER size; prepare_for_bind(data, size, sqlType, cType); SQLINTEGER arraySize = (SQLINTEGER)indVec.size(); SQLSetStmtAttr(statement_.hStmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)arraySize, 0); SQLRETURN cliRC = SQLBindParameter(statement_.hStmt, static_cast(position++), SQL_PARAM_INPUT, cType, sqlType, size, 0, static_cast(data), size, indptr); if ( cliRC != SQL_SUCCESS ) { throw db2_soci_error("Error while binding value to column", cliRC); } } void db2_vector_use_type_backend::bind_by_pos(int &position, void *data, exchange_type type) { if (statement_.use_binding_method_ == details::db2::BOUND_BY_NAME) { throw soci_error("Binding for use elements must be either by position or by name."); } statement_.use_binding_method_ = details::db2::BOUND_BY_POSITION; bind_helper(position, data, type); } void db2_vector_use_type_backend::bind_by_name( std::string const &name, void *data, exchange_type type) { int position = -1; int count = 1; if (statement_.use_binding_method_ == details::db2::BOUND_BY_POSITION) { throw soci_error("Binding for use elements must be either by position or by name."); } statement_.use_binding_method_ = details::db2::BOUND_BY_NAME; for (std::vector::iterator it = statement_.names.begin(); it != statement_.names.end(); ++it) { if (*it == name) { position = count; break; } count++; } if (position != -1) { bind_helper(position, data, type); } else { std::ostringstream ss; ss << "Unable to find name '" << name << "' to bind to"; throw soci_error(ss.str().c_str()); } } void db2_vector_use_type_backend::pre_use(indicator const *ind) { // first deal with data if (type == x_stdtm) { std::vector *vp = static_cast *>(data); std::vector &v(*vp); char *pos = buf; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { std::tm t = v[i]; TIMESTAMP_STRUCT * ts = reinterpret_cast(pos); ts->year = static_cast(t.tm_year + 1900); ts->month = static_cast(t.tm_mon + 1); ts->day = static_cast(t.tm_mday); ts->hour = static_cast(t.tm_hour); ts->minute = static_cast(t.tm_min); ts->second = static_cast(t.tm_sec); ts->fraction = 0; pos += sizeof(TIMESTAMP_STRUCT); } } // then handle indicators if (ind != NULL) { std::size_t const vsize = size(); for (std::size_t i = 0; i != vsize; ++i, ++ind) { if (*ind == i_null) { indVec[i] = SQL_NULL_DATA; // null } else { // for strings we have already set the values if (type != x_stdstring) { indVec[i] = SQL_NTS; // value is OK } } } } else { // no indicators - treat all fields as OK std::size_t const vsize = size(); for (std::size_t i = 0; i != vsize; ++i, ++ind) { // for strings we have already set the values if (type != x_stdstring) { indVec[i] = SQL_NTS; // value is OK } } } } std::size_t db2_vector_use_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type) { // simple cases case x_char: { std::vector *vp = static_cast *>(data); sz = vp->size(); } break; case x_short: { std::vector *vp = static_cast *>(data); sz = vp->size(); } break; case x_integer: { std::vector *vp = static_cast *>(data); sz = vp->size(); } break; case x_long_long: { std::vector *vp = static_cast *>(data); sz = vp->size(); } break; case x_unsigned_long_long: { std::vector *vp = static_cast *>(data); sz = vp->size(); } break; case x_double: { std::vector *vp = static_cast *>(data); sz = vp->size(); } break; case x_stdstring: { std::vector *vp = static_cast *>(data); sz = vp->size(); } break; case x_stdtm: { std::vector *vp = static_cast *>(data); sz = vp->size(); } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } return sz; } void db2_vector_use_type_backend::clean_up() { if (buf != NULL) { delete [] buf; buf = NULL; } } soci-3.2.3/backends/db2/standard-use-type.cpp0000644000000000000000000001302312511361676017457 0ustar rootroot// // Copyright (C) 2011-2013 Denis Chapligin // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #define SOCI_DB2_SOURCE #include "soci-db2.h" #include #include #include #include #include using namespace soci; using namespace soci::details; void *db2_standard_use_type_backend::prepare_for_bind( void *data, SQLLEN &size, SQLSMALLINT &sqlType, SQLSMALLINT &cType) { switch (type) { // simple cases case x_short: sqlType = SQL_SMALLINT; cType = SQL_C_SSHORT; size = sizeof(short); break; case x_integer: sqlType = SQL_INTEGER; cType = SQL_C_SLONG; size = sizeof(int); break; case x_long_long: sqlType = SQL_BIGINT; cType = SQL_C_SBIGINT; size = sizeof(long long); break; case x_unsigned_long_long: sqlType = SQL_BIGINT; cType = SQL_C_UBIGINT; size = sizeof(unsigned long long); break; case x_double: sqlType = SQL_DOUBLE; cType = SQL_C_DOUBLE; size = sizeof(double); break; // cases that require adjustments and buffer management case x_char: { sqlType = SQL_CHAR; cType = SQL_C_CHAR; size = sizeof(char) + 1; buf = new char[size]; char *c = static_cast(data); buf[0] = *c; buf[1] = '\0'; ind = SQL_NTS; } break; case x_stdstring: { // TODO: No textual value is assigned here! std::string* s = static_cast(data); sqlType = SQL_LONGVARCHAR; cType = SQL_C_CHAR; size = s->size() + 1; buf = new char[size]; strncpy(buf, s->c_str(), size); ind = SQL_NTS; } break; case x_stdtm: { sqlType = SQL_TIMESTAMP; cType = SQL_C_TIMESTAMP; buf = new char[sizeof(TIMESTAMP_STRUCT)]; std::tm *t = static_cast(data); data = buf; size = 19; // This number is not the size in bytes, but the number // of characters in the date if it was written out // yyyy-mm-dd hh:mm:ss TIMESTAMP_STRUCT * ts = reinterpret_cast(buf); ts->year = static_cast(t->tm_year + 1900); ts->month = static_cast(t->tm_mon + 1); ts->day = static_cast(t->tm_mday); ts->hour = static_cast(t->tm_hour); ts->minute = static_cast(t->tm_min); ts->second = static_cast(t->tm_sec); ts->fraction = 0; } break; case x_blob: break; case x_statement: case x_rowid: break; } // Return either the pointer to C++ data itself or the buffer that we // allocated, if any. return buf ? buf : data; } void db2_standard_use_type_backend::bind_by_pos( int &position, void *data, exchange_type type, bool /* readOnly */) { if (statement_.use_binding_method_ == details::db2::BOUND_BY_NAME) { throw soci_error("Binding for use elements must be either by position or by name."); } statement_.use_binding_method_ = details::db2::BOUND_BY_POSITION; this->data = data; // for future reference this->type = type; // for future reference this->position = position++; } void db2_standard_use_type_backend::bind_by_name( std::string const &name, void *data, exchange_type type, bool /* readOnly */) { if (statement_.use_binding_method_ == details::db2::BOUND_BY_POSITION) { throw soci_error("Binding for use elements must be either by position or by name."); } statement_.use_binding_method_ = details::db2::BOUND_BY_NAME; int position = -1; int count = 1; for (std::vector::iterator it = statement_.names.begin(); it != statement_.names.end(); ++it) { if (*it == name) { position = count; break; } count++; } if (position != -1) { this->data = data; // for future reference this->type = type; // for future reference this->position = position; } else { std::ostringstream ss; ss << "Unable to find name '" << name << "' to bind to"; throw soci_error(ss.str().c_str()); } } void db2_standard_use_type_backend::pre_use(indicator const *ind_ptr) { // first deal with data SQLSMALLINT sqlType; SQLSMALLINT cType; SQLLEN size; void *sqlData = prepare_for_bind(data, size, sqlType, cType); SQLRETURN cliRC = SQLBindParameter(statement_.hStmt, static_cast(position), SQL_PARAM_INPUT, cType, sqlType, size, 0, sqlData, size, &ind); if (cliRC != SQL_SUCCESS) { throw db2_soci_error("Error while binding value",cliRC); } // then handle indicators if (ind_ptr != NULL && *ind_ptr == i_null) { ind = SQL_NULL_DATA; // null } } void db2_standard_use_type_backend::post_use(bool /*gotData*/, indicator* /*ind*/) { } void db2_standard_use_type_backend::clean_up() { if (buf != NULL) { delete [] buf; buf = NULL; } } soci-3.2.3/backends/db2/session.cpp0000644000000000000000000001640212511361676015575 0ustar rootroot// // Copyright (C) 2011-2013 Denis Chapligin // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_DB2_SOURCE #include "soci-db2.h" #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; const std::string db2_soci_error::sqlState(std::string const & msg,const SQLSMALLINT htype,const SQLHANDLE hndl) { std::ostringstream ss(msg, std::ostringstream::app); SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; SQLINTEGER sqlcode; SQLSMALLINT length; if ( SQLGetDiagRec(htype, hndl, 1, sqlstate, &sqlcode, message, SQL_MAX_MESSAGE_LENGTH + 1, &length) == SQL_SUCCESS ) { ss<<" SQLMESSAGE: "; ss<dsn=value; } if (!key.compare("Uid")) { this->username=value; } if (!key.compare("Pwd")) { this->password=value; } this->autocommit=true; //Default value if (!key.compare("autocommit")) { if (!value.compare("off")) { this->autocommit=false; } } } /* DSN=SAMPLE;Uid=db2inst1;Pwd=db2inst1;AutoCommit=off */ void db2_session_backend::parseConnectString(std::string const & connectString) { std::string processingString(connectString); size_t delimiter=processingString.find_first_of(";"); while(delimiter!=std::string::npos) { std::string keyVal=processingString.substr(0,delimiter); parseKeyVal(keyVal); processingString=processingString.erase(0,delimiter+1); delimiter=processingString.find_first_of(";"); } if (!processingString.empty()) { parseKeyVal(processingString); } } db2_session_backend::db2_session_backend( connection_parameters const & parameters) : in_transaction(false) { parseConnectString(parameters.get_connect_string()); SQLRETURN cliRC = SQL_SUCCESS; /* Prepare handles */ cliRC = SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&hEnv); if (cliRC != SQL_SUCCESS) { throw db2_soci_error("Error while allocating the enironment handle",cliRC); } cliRC = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc); if (cliRC != SQL_SUCCESS) { std::string msg=db2_soci_error::sqlState("Error while allocating the connection handle",SQL_HANDLE_ENV,hEnv); SQLFreeHandle(SQL_HANDLE_ENV,hEnv); throw db2_soci_error(msg,cliRC); } /* Set autocommit */ if(this->autocommit) { cliRC = SQLSetConnectAttr(hDbc,SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_NTS); } else { cliRC = SQLSetConnectAttr(hDbc,SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_NTS); } if (cliRC != SQL_SUCCESS) { std::string msg=db2_soci_error::sqlState("Error while setting autocommit attribute",SQL_HANDLE_DBC,hDbc); SQLFreeHandle(SQL_HANDLE_DBC,hDbc); SQLFreeHandle(SQL_HANDLE_ENV,hEnv); throw db2_soci_error(msg,cliRC); } /* Connect to database */ cliRC = SQLConnect(hDbc, const_cast((const SQLCHAR *) dsn.c_str()), SQL_NTS, const_cast((const SQLCHAR *) username.c_str()), SQL_NTS, const_cast((const SQLCHAR *) password.c_str()), SQL_NTS); if (cliRC != SQL_SUCCESS) { std::string msg=db2_soci_error::sqlState("Error connecting to database",SQL_HANDLE_DBC,hDbc); SQLFreeHandle(SQL_HANDLE_DBC,hDbc); SQLFreeHandle(SQL_HANDLE_ENV,hEnv); throw db2_soci_error(msg,cliRC); } } db2_session_backend::~db2_session_backend() { clean_up(); } void db2_session_backend::begin() { // In DB2, transations begin implicitly; however, autocommit must be disabled for the duration of the transaction if(autocommit) { SQLRETURN cliRC = SQLSetConnectAttr(hDbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_OFF, SQL_NTS); if (cliRC != SQL_SUCCESS && cliRC != SQL_SUCCESS_WITH_INFO) { std::string msg=db2_soci_error::sqlState("Clearing the autocommit attribute failed", SQL_HANDLE_DBC, hDbc); SQLFreeHandle(SQL_HANDLE_DBC,hDbc); SQLFreeHandle(SQL_HANDLE_ENV,hEnv); throw db2_soci_error(msg,cliRC); } } in_transaction = true; } void db2_session_backend::commit() { if (!autocommit || in_transaction) { in_transaction = false; SQLRETURN cliRC = SQLEndTran(SQL_HANDLE_DBC,hDbc,SQL_COMMIT); if(autocommit) { SQLRETURN cliRC2 = SQLSetConnectAttr(hDbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_ON, SQL_NTS); if ((cliRC == SQL_SUCCESS || cliRC == SQL_SUCCESS_WITH_INFO) && cliRC2 != SQL_SUCCESS && cliRC2 != SQL_SUCCESS_WITH_INFO) { std::string msg=db2_soci_error::sqlState("Setting the autocommit attribute failed", SQL_HANDLE_DBC, hDbc); SQLFreeHandle(SQL_HANDLE_DBC,hDbc); SQLFreeHandle(SQL_HANDLE_ENV,hEnv); throw db2_soci_error(msg,cliRC); } } if (cliRC != SQL_SUCCESS && cliRC != SQL_SUCCESS_WITH_INFO) { throw db2_soci_error("Commit failed",cliRC); } } } void db2_session_backend::rollback() { if (!autocommit || in_transaction) { in_transaction = false; SQLRETURN cliRC = SQLEndTran(SQL_HANDLE_DBC,hDbc,SQL_ROLLBACK); if(autocommit) { SQLRETURN cliRC2 = SQLSetConnectAttr(hDbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_ON, SQL_NTS); if ((cliRC == SQL_SUCCESS || cliRC == SQL_SUCCESS_WITH_INFO) && cliRC2 != SQL_SUCCESS && cliRC2 != SQL_SUCCESS_WITH_INFO) { std::string msg=db2_soci_error::sqlState("Setting the autocommit attribute failed", SQL_HANDLE_DBC, hDbc); SQLFreeHandle(SQL_HANDLE_DBC,hDbc); SQLFreeHandle(SQL_HANDLE_ENV,hEnv); throw db2_soci_error(msg,cliRC); } } if (cliRC != SQL_SUCCESS && cliRC != SQL_SUCCESS_WITH_INFO) { throw db2_soci_error("Rollback failed",cliRC); } } } void db2_session_backend::clean_up() { // if a transaction is in progress, it will automatically be rolled back upon when the connection is disconnected/freed in_transaction = false; SQLDisconnect(hDbc); SQLFreeHandle(SQL_HANDLE_DBC,hDbc); SQLFreeHandle(SQL_HANDLE_ENV,hEnv); } db2_statement_backend * db2_session_backend::make_statement_backend() { return new db2_statement_backend(*this); } db2_rowid_backend * db2_session_backend::make_rowid_backend() { return new db2_rowid_backend(*this); } db2_blob_backend * db2_session_backend::make_blob_backend() { return new db2_blob_backend(*this); } soci-3.2.3/backends/db2/soci-db2.h0000644000000000000000000001644012511362240015147 0ustar rootroot// // Copyright (C) 2011-2013 Denis Chapligin // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_DB2_H_INCLUDED #define SOCI_DB2_H_INCLUDED #ifdef _WIN32 # ifdef SOCI_DLL # ifdef SOCI_DB2_SOURCE # define SOCI_DB2_DECL __declspec(dllexport) # else # define SOCI_DB2_DECL __declspec(dllimport) # endif // SOCI_DB2_SOURCE # endif // SOCI_DLL #endif // _WIN32 // // If SOCI_DB2_DECL isn't defined yet define it now #ifndef SOCI_DB2_DECL # define SOCI_DB2_DECL #endif #include "soci-backend.h" #include #include #include #include #include #include #include #include namespace soci { namespace details { namespace db2 { enum binding_method { BOUND_BY_NONE, BOUND_BY_NAME, BOUND_BY_POSITION }; }} static const std::size_t maxBuffer = 1024 * 1024 * 1024; //CLI limit is about 3 GB, but 1GB should be enough class db2_soci_error : public soci_error { public: db2_soci_error(std::string const & msg, SQLRETURN rc) : soci_error(msg),errorCode(rc) {}; ~db2_soci_error() throw() { }; //We have to extract error information before exception throwing, cause CLI handles could be broken at the construction time static const std::string sqlState(std::string const & msg,const SQLSMALLINT htype,const SQLHANDLE hndl); SQLRETURN errorCode; }; struct db2_statement_backend; struct SOCI_DB2_DECL db2_standard_into_type_backend : details::standard_into_type_backend { db2_standard_into_type_backend(db2_statement_backend &st) : statement_(st),buf(NULL) {} void define_by_pos(int& position, void* data, details::exchange_type type); void pre_fetch(); void post_fetch(bool gotData, bool calledFromFetch, indicator* ind); void clean_up(); db2_statement_backend& statement_; char* buf; void *data; details::exchange_type type; int position; SQLSMALLINT cType; SQLLEN valueLen; }; struct SOCI_DB2_DECL db2_vector_into_type_backend : details::vector_into_type_backend { db2_vector_into_type_backend(db2_statement_backend &st) : statement_(st),buf(NULL) {} void define_by_pos(int& position, void* data, details::exchange_type type); void pre_fetch(); void post_fetch(bool gotData, indicator* ind); void resize(std::size_t sz); std::size_t size(); void clean_up(); db2_statement_backend& statement_; void prepare_indicators(std::size_t size); SQLLEN *indptr; std::vector indVec; void *data; char *buf; int position_; details::exchange_type type; SQLSMALLINT cType; std::size_t colSize; }; struct SOCI_DB2_DECL db2_standard_use_type_backend : details::standard_use_type_backend { db2_standard_use_type_backend(db2_statement_backend &st) : statement_(st),buf(NULL),ind(0) {} void bind_by_pos(int& position, void* data, details::exchange_type type, bool readOnly); void bind_by_name(std::string const& name, void* data, details::exchange_type type, bool readOnly); void pre_use(indicator const* ind); void post_use(bool gotData, indicator* ind); void clean_up(); db2_statement_backend& statement_; void *prepare_for_bind(void *data, SQLLEN &size, SQLSMALLINT &sqlType, SQLSMALLINT &cType); void *data; details::exchange_type type; int position; std::string name; char* buf; SQLLEN ind; }; struct SOCI_DB2_DECL db2_vector_use_type_backend : details::vector_use_type_backend { db2_vector_use_type_backend(db2_statement_backend &st) : statement_(st),buf(NULL) {} void bind_by_pos(int& position, void* data, details::exchange_type type); void bind_by_name(std::string const& name, void* data, details::exchange_type type); void pre_use(indicator const* ind); std::size_t size(); void clean_up(); db2_statement_backend& statement_; void prepare_indicators(std::size_t size); void prepare_for_bind(void *&data, SQLUINTEGER &size,SQLSMALLINT &sqlType, SQLSMALLINT &cType); void bind_helper(int &position, void *data, details::exchange_type type); SQLLEN *indptr; std::vector indVec; void *data; char *buf; details::exchange_type type; std::size_t colSize; }; struct db2_session_backend; struct SOCI_DB2_DECL db2_statement_backend : details::statement_backend { db2_statement_backend(db2_session_backend &session); void alloc(); void clean_up(); void prepare(std::string const& query, details::statement_type eType); exec_fetch_result execute(int number); exec_fetch_result fetch(int number); long long get_affected_rows(); int get_number_of_rows(); std::string rewrite_for_procedure_call(std::string const& query); int prepare_for_describe(); void describe_column(int colNum, data_type& dtype, std::string& columnName); std::size_t column_size(int col); db2_standard_into_type_backend* make_into_type_backend(); db2_standard_use_type_backend* make_use_type_backend(); db2_vector_into_type_backend* make_vector_into_type_backend(); db2_vector_use_type_backend* make_vector_use_type_backend(); db2_session_backend& session_; SQLHANDLE hStmt; std::string query_; std::vector names; bool hasVectorUseElements; SQLUINTEGER numRowsFetched; details::db2::binding_method use_binding_method_; }; struct db2_rowid_backend : details::rowid_backend { db2_rowid_backend(db2_session_backend &session); ~db2_rowid_backend(); }; struct db2_blob_backend : details::blob_backend { db2_blob_backend(db2_session_backend& session); ~db2_blob_backend(); std::size_t get_len(); std::size_t read(std::size_t offset, char* buf, std::size_t toRead); std::size_t write(std::size_t offset, char const* buf, std::size_t toWrite); std::size_t append(char const* buf, std::size_t toWrite); void trim(std::size_t newLen); db2_session_backend& session_; }; struct db2_session_backend : details::session_backend { db2_session_backend(connection_parameters const& parameters); ~db2_session_backend(); void begin(); void commit(); void rollback(); std::string get_backend_name() const { return "DB2"; } void clean_up(); db2_statement_backend* make_statement_backend(); db2_rowid_backend* make_rowid_backend(); db2_blob_backend* make_blob_backend(); void parseConnectString(std::string const &); void parseKeyVal(std::string const &); std::string dsn; std::string username; std::string password; bool autocommit; bool in_transaction; SQLHANDLE hEnv; /* Environment handle */ SQLHANDLE hDbc; /* Connection handle */ }; struct SOCI_DB2_DECL db2_backend_factory : backend_factory { db2_backend_factory() {} db2_session_backend* make_session( connection_parameters const & parameters) const; }; extern SOCI_DB2_DECL db2_backend_factory const db2; extern "C" { // for dynamic backend loading SOCI_DB2_DECL backend_factory const* factory_db2(); SOCI_DB2_DECL void register_factory_db2(); } // extern "C" } // namespace soci #endif // SOCI_DB2_H_INCLUDED soci-3.2.3/backends/db2/factory.cpp0000644000000000000000000000162112511361676015556 0ustar rootroot// // Copyright (C) 2011-2013 Denis Chapligin // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_DB2_SOURCE #include "soci-db2.h" #include using namespace soci; using namespace soci::details; // concrete factory for ODBC concrete strategies db2_session_backend * db2_backend_factory::make_session( connection_parameters const & parameters) const { return new db2_session_backend(parameters); } db2_backend_factory const soci::db2; extern "C" { // for dynamic backend loading SOCI_DB2_DECL backend_factory const * factory_db2() { return &soci::db2; } SOCI_DB2_DECL void register_factory_db2() { soci::dynamic_backends::register_backend("db2", soci::db2); } } // extern "C" soci-3.2.3/backends/db2/row-id.cpp0000644000000000000000000000106512511361676015312 0ustar rootroot// // Copyright (C) 2011-2013 Denis Chapligin // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_DB2_SOURCE #include "soci-db2.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; db2_rowid_backend::db2_rowid_backend(db2_session_backend & /* session */) { // ... } db2_rowid_backend::~db2_rowid_backend() { // ... } soci-3.2.3/backends/db2/standard-into-type.cpp0000644000000000000000000001044312511361676017637 0ustar rootroot// // Copyright (C) 2011-2013 Denis Chapligin // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_DB2_SOURCE #include "soci-db2.h" #include "common.h" #include using namespace soci; using namespace soci::details; void db2_standard_into_type_backend::define_by_pos( int & position, void * data, exchange_type type) { this->data = data; this->type = type; this->position = position; position++; SQLUINTEGER size = 0; switch (type) { case x_char: cType = SQL_C_CHAR; size = sizeof(char) + 1; buf = new char[size]; data = buf; break; case x_stdstring: cType = SQL_C_CHAR; // Patch: set to min between column size and 100MB (used ot be 32769) // Column size for text data type can be too large for buffer allocation size = statement_.column_size(this->position); size = size > details::db2::cli_max_buffer ? details::db2::cli_max_buffer : size; size++; buf = new char[size]; data = buf; break; case x_short: cType = SQL_C_SSHORT; size = sizeof(short); break; case x_integer: cType = SQL_C_SLONG; size = sizeof(SQLINTEGER); break; case x_long_long: cType = SQL_C_SBIGINT; size = sizeof(long long); break; case x_unsigned_long_long: cType = SQL_C_UBIGINT; size = sizeof(unsigned long long); break; case x_double: cType = SQL_C_DOUBLE; size = sizeof(double); break; case x_stdtm: cType = SQL_C_TYPE_TIMESTAMP; size = sizeof(TIMESTAMP_STRUCT); buf = new char[size]; data = buf; break; case x_rowid: cType = SQL_C_UBIGINT; size = sizeof(unsigned long long); break; default: throw soci_error("Into element used with non-supported type."); } valueLen = 0; SQLRETURN cliRC = SQLBindCol(statement_.hStmt, static_cast(this->position), static_cast(cType), data, size, &valueLen); if (cliRC != SQL_SUCCESS) { throw db2_soci_error("Error while pre-fething into type",cliRC); } } void db2_standard_into_type_backend::pre_fetch() { //... } void db2_standard_into_type_backend::post_fetch( bool gotData, bool calledFromFetch, indicator * ind) { if (calledFromFetch == true && gotData == false) { // this is a normal end-of-rowset condition, // no need to do anything (fetch() will return false) return; } if (gotData) { // first, deal with indicators if (SQL_NULL_DATA == valueLen) { if (ind == NULL) { throw soci_error( "Null value fetched and no indicator defined."); } *ind = i_null; return; } else { if (ind != NULL) { *ind = i_ok; } } // only std::string and std::tm need special handling if (type == x_char) { char *c = static_cast(data); *c = buf[0]; } if (type == x_stdstring) { std::string *s = static_cast(data); *s = buf; if (s->size() >= (details::db2::cli_max_buffer - 1)) { throw soci_error("Buffer size overflow; maybe got too large string"); } } else if (type == x_stdtm) { std::tm *t = static_cast(data); TIMESTAMP_STRUCT * ts = reinterpret_cast(buf); t->tm_isdst = -1; t->tm_year = ts->year - 1900; t->tm_mon = ts->month - 1; t->tm_mday = ts->day; t->tm_hour = ts->hour; t->tm_min = ts->minute; t->tm_sec = ts->second; // normalize and compute the remaining fields std::mktime(t); } } } void db2_standard_into_type_backend::clean_up() { if (buf) { delete [] buf; buf = 0; } } soci-3.2.3/backends/db2/test/0000755000000000000000000000000012511362240014346 5ustar rootrootsoci-3.2.3/backends/db2/test/test-db2.cpp0000644000000000000000000003260212511362240016501 0ustar rootroot// // Copyright (C) 2011-2013 Denis Chapligin // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci.h" #include "soci-db2.h" #include "common-tests.h" #include #include #include #include #include using namespace soci; using namespace soci::tests; std::string connectString; backend_factory const &backEnd = *soci::factory_db2(); // // Support for soci Common Tests // struct table_creator_one : public table_creator_base { table_creator_one(session & sql) : table_creator_base(sql) { sql << "CREATE TABLE SOCI_TEST(ID INTEGER, VAL SMALLINT, C CHAR, STR VARCHAR(20), SH SMALLINT, UL NUMERIC(20), D DOUBLE, " "TM TIMESTAMP, I1 INTEGER, I2 INTEGER, I3 INTEGER, NAME VARCHAR(20))"; } }; struct table_creator_two : public table_creator_base { table_creator_two(session & sql) : table_creator_base(sql) { sql << "CREATE TABLE SOCI_TEST(NUM_FLOAT DOUBLE, NUM_INT INTEGER, NAME VARCHAR(20), SOMETIME TIMESTAMP, CHR CHAR)"; } }; struct table_creator_three : public table_creator_base { table_creator_three(session & sql) : table_creator_base(sql) { sql << "CREATE TABLE SOCI_TEST(NAME VARCHAR(100) NOT NULL, PHONE VARCHAR(15))"; } }; struct table_creator_for_get_affected_rows : table_creator_base { table_creator_for_get_affected_rows(session & sql) : table_creator_base(sql) { sql << "CREATE TABLE SOCI_TEST(VAL INTEGER)"; } }; class test_context :public test_context_base { public: test_context(backend_factory const & pi_back_end, std::string const & pi_connect_string) : test_context_base(pi_back_end, pi_connect_string) {} table_creator_base* table_creator_1(session & pr_s) const { pr_s << "SET CURRENT SCHEMA = 'DB2INST1'"; return new table_creator_one(pr_s); } table_creator_base* table_creator_2(session & pr_s) const { pr_s << "SET CURRENT SCHEMA = 'DB2INST1'"; return new table_creator_two(pr_s); } table_creator_base* table_creator_3(session & pr_s) const { pr_s << "SET CURRENT SCHEMA = 'DB2INST1'"; return new table_creator_three(pr_s); } table_creator_base* table_creator_4(session& s) const { return new table_creator_for_get_affected_rows(s); } std::string to_date_time(std::string const & pi_datdt_string) const { return "to_date('" + pi_datdt_string + "', 'YYYY-MM-DD HH24:MI:SS')"; } }; // // Additional tests to exercise the DB2 backend // void test1() { { session sql(backEnd, connectString); sql << "SELECT CURRENT TIMESTAMP FROM SYSIBM.SYSDUMMY1"; sql << "SELECT " << 123 << " FROM SYSIBM.SYSDUMMY1"; std::string query = "CREATE TABLE DB2INST1.SOCI_TEST (ID BIGINT,DATA VARCHAR(8))"; sql << query; { const int i = 7; sql << "insert into db2inst1.SOCI_TEST (id) values (:id)", use(i,"id"); int j = 0; sql << "select id from db2inst1.SOCI_TEST where id=7", into(j); assert(j == i); } { const long int li = 9; sql << "insert into db2inst1.SOCI_TEST (id) values (:id)", use(li,"id"); long int lj = 0;; sql << "select id from db2inst1.SOCI_TEST where id=9", into(lj); assert(lj == li); } { const long long ll = 11; sql << "insert into db2inst1.SOCI_TEST (id) values (:id)", use(ll,"id"); long long lj = 0; sql << "select id from db2inst1.SOCI_TEST where id=11", into(lj); assert(lj == ll); } { const int i = 13; indicator i_ind = i_ok; sql << "insert into db2inst1.SOCI_TEST (id) values (:id)", use(i,i_ind,"id"); int j = 0; indicator j_ind = i_null; sql << "select id from db2inst1.SOCI_TEST where id=13", into(j,j_ind); assert(j == i); assert(j_ind == i_ok); } { std::vector numbers(100); for (int i = 0 ; i < 100 ; i++) { numbers[i] = i + 1000; } sql << "insert into db2inst1.SOCI_TEST (id) values (:id)", use(numbers,"id"); sql << "select id from db2inst1.SOCI_TEST where id >= 1000 and id < 2000 order by id", into(numbers); for (int i = 0 ; i < 100 ; i++) { assert(numbers[i] == i + 1000); } } { std::vector numbers(100); std::vector inds(100); for (int i = 0 ; i < 100 ; i++) { numbers[i] = i + 2000; inds[i] = i_ok; } sql << "insert into db2inst1.SOCI_TEST (id) values (:id)", use(numbers,inds,"id"); for (int i = 0 ; i < 100 ; i++) { numbers[i] = 0; inds[i] = i_null; } sql << "select id from db2inst1.SOCI_TEST where id >= 2000 and id < 3000 order by id", into(numbers,inds); for (int i = 0 ; i < 100 ; i++) { assert(numbers[i] == i + 2000); assert(inds[i] == i_ok); } } { int i = 0; statement st = (sql.prepare << "select id from db2inst1.SOCI_TEST where id < 1000", into(i)); st.execute(); st.fetch(); assert (i == 7); st.fetch(); assert (i == 9); st.fetch(); assert (i == 11); st.fetch(); assert (i == 13); } { int i = 0; indicator i_ind = i_null; std::string d; indicator d_ind = i_ok; statement st = (sql.prepare << "select id, data from db2inst1.SOCI_TEST where id = 13", into(i, i_ind), into(d, d_ind)); st.execute(); st.fetch(); assert (i == 13); assert (i_ind == i_ok); assert (d_ind == i_null); } { std::vector numbers(100); for (int i = 0 ; i < 100 ; i++) { numbers[i] = 0; } statement st = (sql.prepare << "select id from db2inst1.SOCI_TEST where id >= 1000 order by id", into(numbers)); st.execute(); st.fetch(); for (int i = 0 ; i < 100 ; i++) { assert(numbers[i] == i + 1000); } st.fetch(); for (int i = 0 ; i < 100 ; i++) { assert(numbers[i] == i + 2000); } } { std::vector numbers(100); std::vector inds(100); for (int i = 0 ; i < 100 ; i++) { numbers[i] = 0; inds[i] = i_null; } statement st = (sql.prepare << "select id from db2inst1.SOCI_TEST where id >= 1000 order by id", into(numbers, inds)); st.execute(); st.fetch(); for (int i = 0 ; i < 100 ; i++) { assert(numbers[i] == i + 1000); assert(inds[i] == i_ok); } st.fetch(); for (int i = 0 ; i < 100 ; i++) { assert(numbers[i] == i + 2000); assert(inds[i] == i_ok); } } { // XXX: what is the purpose of this test?? what is the expected value? int i = 0; statement st = (sql.prepare << "select id from db2inst1.SOCI_TEST", use(i)); } { // XXX: what is the purpose of this test?? what is the expected value? int i = 0; indicator ind = i_ok; statement st = (sql.prepare << "select id from db2inst1.SOCI_TEST", use(i, ind)); } { // XXX: what is the purpose of this test?? what is the expected value? std::vector numbers(100); statement st = (sql.prepare << "select id from db2inst1.SOCI_TEST", use(numbers)); } { // XXX: what is the purpose of this test?? what is the expected value? std::vector numbers(100); std::vector inds(100); statement st = (sql.prepare << "select id from db2inst1.SOCI_TEST", use(numbers, inds)); } sql<<"DROP TABLE DB2INST1.SOCI_TEST"; sql.commit(); } std::cout << "test 1 passed" << std::endl; } void test2() { { session sql(backEnd, connectString); std::string query = "CREATE TABLE DB2INST1.SOCI_TEST (ID BIGINT,DATA VARCHAR(8),DT TIMESTAMP)"; sql << query; { int i = 7; std::string n("test"); sql << "insert into db2inst1.SOCI_TEST (id,data) values (:id,:name)", use(i,"id"),use(n,"name"); int j; std::string m; sql << "select id,data from db2inst1.SOCI_TEST where id=7", into(j),into(m); assert (j == i); assert (m == n); } { int i = 8; sql << "insert into db2inst1.SOCI_TEST (id) values (:id)", use(i,"id"); int j; std::string m; indicator ind = i_ok; sql << "select id,data from db2inst1.SOCI_TEST where id=8", into(j),into(m,ind); assert(j == i); assert(ind==i_null); } { std::tm dt; sql << "select current timestamp from sysibm.sysdummy1",into(dt); sql << "insert into db2inst1.SOCI_TEST (dt) values (:dt)",use(dt,"dt"); std::tm dt2; sql << "select dt from db2inst1.SOCI_TEST where dt is not null", into(dt2); assert(dt2.tm_year == dt.tm_year && dt2.tm_mon == dt.tm_mon && dt2.tm_mday == dt.tm_mday && dt2.tm_hour == dt.tm_hour && dt2.tm_min == dt.tm_min && dt2.tm_sec == dt.tm_sec); } sql<<"DROP TABLE DB2INST1.SOCI_TEST"; sql.commit(); } std::cout << "test 2 passed" << std::endl; } void test3() { { session sql(backEnd, connectString); int i; std::string query = "CREATE TABLE DB2INST1.SOCI_TEST (ID BIGINT,DATA VARCHAR(8),DT TIMESTAMP)"; sql << query; std::vector ids(100); std::vector data(100); std::vector dts(100); for (int i = 0; i < 100; i++) { ids[i] = 1000000000LL + i; data[i] = "test"; dts[i].tm_year = 112; dts[i].tm_mon = 7; dts[i].tm_mday = 17; dts[i].tm_hour = 0; dts[i].tm_min = 0; dts[i].tm_sec = i % 60; } sql << "insert into db2inst1.SOCI_TEST (id, data, dt) values (:id, :data, :dt)", use(ids, "id"), use(data,"data"), use(dts, "dt"); i = 0; rowset rs = (sql.prepare<<"SELECT ID, DATA, DT FROM DB2INST1.SOCI_TEST"); for (rowset::const_iterator it = rs.begin(); it != rs.end(); it++) { const row & r = *it; const long long id = r.get(0); const std::string data = r.get(1); const std::tm dt = r.get(2); assert(id == 1000000000LL + i); assert(data == "test"); assert(dt.tm_year == 112); assert(dt.tm_mon == 7); assert(dt.tm_mday == 17); assert(dt.tm_hour == 0); assert(dt.tm_min == 0); assert(dt.tm_sec == i % 60); i += 1; } sql<<"DROP TABLE DB2INST1.SOCI_TEST"; sql.commit(); } std::cout << "test 3 passed" << std::endl; } int main(int argc, char** argv) { #ifdef _MSC_VER // Redirect errors, unrecoverable problems, and assert() failures to STDERR, // instead of debug message window. // This hack is required to run asser()-driven tests by Buildbot. // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); #endif //_MSC_VER if (argc == 2) { connectString = argv[1]; } else { std::cout << "usage: " << argv[0] << " connectstring\n" << "example: " << argv[0] << " \'DSN=SAMPLE;Uid=db2inst1;Pwd=db2inst1;autocommit=off\'\n"; std::exit(1); } test_context tc(backEnd, connectString); common_tests tests(tc); tests.run(); try { std::cout<<"\nSOCI DB2 Tests:\n\n"; session sql(backEnd, connectString); try { // attempt to delete the test table from previous runs sql << "DROP TABLE DB2INST1.SOCI_TEST"; } catch (soci_error const & e) { // if the table didn't exist, then proceed } test1(); test2(); test3(); // ... std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; } catch (std::exception const & e) { std::cout << e.what() << '\n'; } return EXIT_FAILURE; } soci-3.2.3/backends/db2/test/CMakeLists.txt0000644000000000000000000000103012511361676017114 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2011 Denis Chapligin # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend_test( BACKEND DB2 SOURCE test-db2.cpp CONNSTR "DSN=SAMPLE;Uid=db2inst1;Pwd=db2inst1;autocommit=off") soci-3.2.3/backends/db2/vector-into-type.cpp0000644000000000000000000002566512511361676017355 0ustar rootroot// // Copyright (C) 2011-2013 Denis Chapligin // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_DB2_SOURCE #include "soci-db2.h" #include #include #include #include #include using namespace soci; using namespace soci::details; void db2_vector_into_type_backend::prepare_indicators(std::size_t size) { if (size == 0) { throw soci_error("Vectors of size 0 are not allowed."); } indVec.resize(size); indptr = &indVec[0]; } void db2_vector_into_type_backend::define_by_pos( int &position, void *data, exchange_type type) { this->data = data; // for future reference this->type = type; // for future reference SQLINTEGER size = 0; // also dummy switch (type) { // simple cases case x_short: { cType = SQL_C_SSHORT; size = sizeof(short); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_integer: { cType = SQL_C_SLONG; size = sizeof(SQLINTEGER); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_long_long: { cType = SQL_C_SBIGINT; size = sizeof(long long); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_unsigned_long_long: { cType = SQL_C_UBIGINT; size = sizeof(unsigned long long); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; case x_double: { cType = SQL_C_DOUBLE; size = sizeof(double); std::vector *vp = static_cast *>(data); std::vector &v(*vp); prepare_indicators(v.size()); data = &v[0]; } break; // cases that require adjustments and buffer management case x_char: { cType = SQL_C_CHAR; std::vector *v = static_cast *>(data); prepare_indicators(v->size()); size = sizeof(char) * 2; std::size_t bufSize = size * v->size(); colSize = size; buf = new char[bufSize]; data = buf; } break; case x_stdstring: { cType = SQL_C_CHAR; std::vector *v = static_cast *>(data); colSize = statement_.column_size(position) + 1; std::size_t bufSize = colSize * v->size(); buf = new char[bufSize]; prepare_indicators(v->size()); size = static_cast(colSize); data = buf; } break; case x_stdtm: { cType = SQL_C_TYPE_TIMESTAMP; std::vector *v = static_cast *>(data); prepare_indicators(v->size()); size = sizeof(TIMESTAMP_STRUCT); colSize = size; std::size_t bufSize = size * v->size(); buf = new char[bufSize]; data = buf; } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } SQLRETURN cliRC = SQLBindCol(statement_.hStmt, static_cast(position++), cType, data, size, indptr); if (cliRC != SQL_SUCCESS) { throw db2_soci_error("Error while pre-fetching into vector",cliRC); } } void db2_vector_into_type_backend::pre_fetch() { // nothing to do for the supported types } void db2_vector_into_type_backend::post_fetch(bool gotData, indicator *ind) { if (gotData) { // first, deal with data // only std::string, std::tm and Statement need special handling if (type == x_char) { std::vector *vp = static_cast *>(data); std::vector &v(*vp); char *pos = buf; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { v[i] = *pos; pos += colSize; } } if (type == x_stdstring) { std::vector *vp = static_cast *>(data); std::vector &v(*vp); char *pos = buf; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { v[i].assign(pos, strlen(pos)); pos += colSize; } } else if (type == x_stdtm) { std::vector *vp = static_cast *>(data); std::vector &v(*vp); char *pos = buf; std::size_t const vsize = v.size(); for (std::size_t i = 0; i != vsize; ++i) { std::tm t; TIMESTAMP_STRUCT * ts = reinterpret_cast(pos); t.tm_isdst = -1; t.tm_year = ts->year - 1900; t.tm_mon = ts->month - 1; t.tm_mday = ts->day; t.tm_hour = ts->hour; t.tm_min = ts->minute; t.tm_sec = ts->second; // normalize and compute the remaining fields std::mktime(&t); v[i] = t; pos += colSize; } } // then - deal with indicators if (ind != NULL) { std::size_t const indSize = statement_.get_number_of_rows(); for (std::size_t i = 0; i != indSize; ++i) { if (indVec[i] > 0) { ind[i] = i_ok; } else if (indVec[i] == SQL_NULL_DATA) { ind[i] = i_null; } else { ind[i] = i_truncated; } } } else { std::size_t const indSize = statement_.get_number_of_rows(); for (std::size_t i = 0; i != indSize; ++i) { if (indVec[i] == SQL_NULL_DATA) { // fetched null and no indicator - programming error! throw soci_error( "Null value fetched and no indicator defined."); } } } } else // gotData == false { // nothing to do here, vectors are truncated anyway } } void db2_vector_into_type_backend::resize(std::size_t sz) { indVec.resize(sz); switch (type) { // simple cases case x_char: { std::vector *v = static_cast *>(data); v->resize(sz); } break; case x_short: { std::vector *v = static_cast *>(data); v->resize(sz); } break; case x_integer: { std::vector *v = static_cast *>(data); v->resize(sz); } break; case x_long_long: { std::vector *v = static_cast *>(data); v->resize(sz); } break; case x_unsigned_long_long: { std::vector *v = static_cast *>(data); v->resize(sz); } break; case x_double: { std::vector *v = static_cast *>(data); v->resize(sz); } break; case x_stdstring: { std::vector *v = static_cast *>(data); v->resize(sz); } break; case x_stdtm: { std::vector *v = static_cast *>(data); v->resize(sz); } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } } std::size_t db2_vector_into_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type) { // simple cases case x_char: { std::vector *v = static_cast *>(data); sz = v->size(); } break; case x_short: { std::vector *v = static_cast *>(data); sz = v->size(); } break; case x_integer: { std::vector *v = static_cast *>(data); sz = v->size(); } break; case x_long_long: { std::vector *v = static_cast *>(data); sz = v->size(); } break; case x_unsigned_long_long: { std::vector *v = static_cast *>(data); sz = v->size(); } break; case x_double: { std::vector *v = static_cast *>(data); sz = v->size(); } break; case x_stdstring: { std::vector *v = static_cast *>(data); sz = v->size(); } break; case x_stdtm: { std::vector *v = static_cast *>(data); sz = v->size(); } break; case x_statement: break; // not supported case x_rowid: break; // not supported case x_blob: break; // not supported } return sz; } void db2_vector_into_type_backend::clean_up() { if (buf != NULL) { delete [] buf; buf = NULL; } } soci-3.2.3/backends/db2/CMakeLists.txt0000644000000000000000000000114112511362240016124 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2011 Denis Chapligin # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend(DB2 DEPENDS DB2 HEADERS soci-db2.h DESCRIPTION "SOCI backend for DB2 Universal Database" AUTHORS "Denis Chapligin" MAINTAINERS "Denis Chapligin") add_subdirectory(test) soci-3.2.3/backends/.gitignore0000644000000000000000000000003212505151606014710 0ustar rootroot*.o *.la *.lo .deps .libs soci-3.2.3/backends/firebird/0000755000000000000000000000000012511362240014506 5ustar rootrootsoci-3.2.3/backends/firebird/common.h0000644000000000000000000001343012511362240016150 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_FIREBIRD_COMMON_H_INCLUDED #define SOCI_FIREBIRD_COMMON_H_INCLUDED #include "soci-firebird.h" #include #include #include #include #include #include #include #include #include namespace soci { namespace details { namespace firebird { char * allocBuffer(XSQLVAR* var); void tmEncode(short type, std::tm * src, void * dst); void tmDecode(short type, void * src, std::tm * dst); void setTextParam(char const * s, std::size_t size, char * buf_, XSQLVAR * var); std::string getTextParam(XSQLVAR const *var); template const char *str2dec(const char * s, IntType &out, int &scale) { int sign = 1; if ('+' == *s) ++s; else if ('-' == *s) { sign = -1; ++s; } scale = 0; bool period = false; IntType res = 0; for (out = 0; *s; ++s, out = res) { if (*s == '.') { if (period) return s; period = true; continue; } int d = *s - '0'; if (d < 0 || d > 9) return s; res = res * 10 + d * sign; if (1 == sign) { if (res < out) return s; } else { if (res > out) return s; } if (period) ++scale; } return s; } template void to_isc(void * val, XSQLVAR * var, int x_scale = 0) { T1 value = *reinterpret_cast(val); short scale = var->sqlscale + x_scale; short type = var->sqltype & ~1; long long divisor = 1, multiplier = 1; if ((std::numeric_limits::is_integer == false) && scale >= 0 && (type == SQL_SHORT || type == SQL_LONG || type == SQL_INT64)) { throw soci_error("Can't convert non-integral value to integral column type"); } for (int i = 0; i > scale; --i) multiplier *= 10; for (int i = 0; i < scale; ++i) divisor *= 10; switch (type) { case SQL_SHORT: { short tmp = static_cast(value*multiplier/divisor); std::memcpy(var->sqldata, &tmp, sizeof(short)); } break; case SQL_LONG: { int tmp = static_cast(value*multiplier/divisor); std::memcpy(var->sqldata, &tmp, sizeof(int)); } break; case SQL_INT64: { long long tmp = static_cast(value*multiplier/divisor); std::memcpy(var->sqldata, &tmp, sizeof(long long)); } break; case SQL_FLOAT: { float sql_value = static_cast(value); std::memcpy(var->sqldata, &sql_value, sizeof(float)); } break; case SQL_DOUBLE: { double sql_value = static_cast(value); std::memcpy(var->sqldata, &sql_value, sizeof(double)); } break; default: throw soci_error("Incorrect data type for numeric conversion"); } } template void parse_decimal(void * val, XSQLVAR * var, const char * s) { int scale; UIntType t1; IntType t2; if (!*str2dec(s, t1, scale)) std::memcpy(val, &t1, sizeof(t1)); else if (!*str2dec(s, t2, scale)) std::memcpy(val, &t2, sizeof(t2)); else throw soci_error("Could not parse decimal value."); to_isc(val, var, scale); } template std::string format_decimal(const void *sqldata, int sqlscale) { IntType x = *reinterpret_cast(sqldata); std::stringstream out; out << x; std::string r = out.str(); if (sqlscale < 0) { if (static_cast(r.size()) - (x < 0) <= -sqlscale) { r = std::string(size_t(x < 0), '-') + std::string(-sqlscale - (r.size() - (x < 0)) + 1, '0') + r.substr(size_t(x < 0), std::string::npos); } return r.substr(0, r.size() + sqlscale) + '.' + r.substr(r.size() + sqlscale, std::string::npos); } return r + std::string(sqlscale, '0'); } template T1 from_isc(XSQLVAR * var) { short scale = var->sqlscale; T1 tens = 1; if (scale < 0) { if (std::numeric_limits::is_integer) { std::ostringstream msg; msg << "Can't convert value with scale " << -scale << " to integral type"; throw soci_error(msg.str()); } for (int i = 0; i > scale; --i) { tens *= 10; } } switch (var->sqltype & ~1) { case SQL_SHORT: return static_cast(*reinterpret_cast(var->sqldata)/tens); case SQL_LONG: return static_cast(*reinterpret_cast(var->sqldata)/tens); case SQL_INT64: return static_cast(*reinterpret_cast(var->sqldata)/tens); case SQL_FLOAT: return static_cast(*reinterpret_cast(var->sqldata)); case SQL_DOUBLE: return static_cast(*reinterpret_cast(var->sqldata)); default: throw soci_error("Incorrect data type for numeric conversion"); } } template std::size_t getVectorSize(void *p) { std::vector *v = static_cast *>(p); return v->size(); } template void resizeVector(void *p, std::size_t sz) { std::vector *v = static_cast *>(p); v->resize(sz); } } // namespace firebird } // namespace details } // namespace soci #endif // SOCI_FIREBIRD_COMMON_H_INCLUDED soci-3.2.3/backends/firebird/error-firebird.h0000644000000000000000000000142112511362240017572 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_FIREBIRD_ERROR_H_INCLUDED #define SOCI_FIREBIRD_ERROR_H_INCLUDED #include "soci-firebird.h" #include namespace soci { namespace details { namespace firebird { void SOCI_FIREBIRD_DECL get_iscerror_details(ISC_STATUS * status_vector, std::string &msg); bool SOCI_FIREBIRD_DECL check_iscerror(ISC_STATUS const * status_vector, long errNum); void SOCI_FIREBIRD_DECL throw_iscerror(ISC_STATUS * status_vector); } // namespace firebird } // namespace details } // namespace soci #endif // SOCI_FIREBIRD_ERROR_H_INCLUDED soci-3.2.3/backends/firebird/blob.cpp0000644000000000000000000001524612511361676016154 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_FIREBIRD_SOURCE #include "soci-firebird.h" #include "error-firebird.h" using namespace soci; using namespace soci::details::firebird; firebird_blob_backend::firebird_blob_backend(firebird_session_backend &session) : session_(session), from_db_(false), bhp_(0), loaded_(false), max_seg_size_(0) {} firebird_blob_backend::~firebird_blob_backend() { cleanUp(); } std::size_t firebird_blob_backend::get_len() { if (from_db_ && bhp_ == 0) { open(); } return data_.size(); } std::size_t firebird_blob_backend::read( std::size_t offset, char * buf, std::size_t toRead) { if (from_db_ && (loaded_ == false)) { // this is blob fetched from database, but not loaded yet load(); } std::size_t size = data_.size(); if (offset > size) { throw soci_error("Can't read past-the-end of BLOB data"); } char * itr = buf; std::size_t limit = size - offset < toRead ? size - offset : toRead; std::size_t index = 0; while (index < limit) { *itr = data_[offset+index]; ++index; ++itr; } return limit; } std::size_t firebird_blob_backend::write(std::size_t offset, char const * buf, std::size_t toWrite) { if (from_db_ && (loaded_ == false)) { // this is blob fetched from database, but not loaded yet load(); } std::size_t size = data_.size(); if (offset > size) { throw soci_error("Can't write past-the-end of BLOB data"); } // make sure there is enough space in buffer if (toWrite > (size - offset)) { data_.resize(size + (toWrite - (size - offset))); } writeBuffer(offset, buf, toWrite); return toWrite; } std::size_t firebird_blob_backend::append( char const * buf, std::size_t toWrite) { if (from_db_ && (loaded_ == false)) { // this is blob fetched from database, but not loaded yet load(); } std::size_t size = data_.size(); data_.resize(size + toWrite); writeBuffer(size, buf, toWrite); return toWrite; } void firebird_blob_backend::trim(std::size_t newLen) { if (from_db_ && (loaded_ == false)) { // this is blob fetched from database, but not loaded yet load(); } data_.resize(newLen); } void firebird_blob_backend::writeBuffer(std::size_t offset, char const * buf, std::size_t toWrite) { char const * itr = buf; char const * end_itr = buf + toWrite; while (itr!=end_itr) { data_[offset++] = *itr++; } } void firebird_blob_backend::open() { if (bhp_ != 0) { // BLOB already opened return; } ISC_STATUS stat[20]; if (isc_open_blob2(stat, &session_.dbhp_, &session_.trhp_, &bhp_, &bid_, 0, NULL)) { bhp_ = 0L; throw_iscerror(stat); } // get basic blob info long blob_size = getBLOBInfo(); data_.resize(blob_size); } void firebird_blob_backend::cleanUp() { from_db_ = false; loaded_ = false; max_seg_size_ = 0; data_.resize(0); if (bhp_ != 0) { // close blob ISC_STATUS stat[20]; if (isc_close_blob(stat, &bhp_)) { throw_iscerror(stat); } bhp_ = 0; } } // loads blob data into internal buffer void firebird_blob_backend::load() { if (bhp_ == 0) { open(); } ISC_STATUS stat[20]; unsigned short bytes; std::vector::size_type total_bytes = 0; bool keep_reading = false; do { bytes = 0; // next segment of data // data_ is large-enough because we know total size of blob isc_get_segment(stat, &bhp_, &bytes, static_cast(max_seg_size_), &data_[total_bytes]); total_bytes += bytes; if (total_bytes == data_.size()) { // we have all BLOB data keep_reading = false; } else if (stat[1] == 0 || stat[1] == isc_segment) { // there is more data to read from current segment (0) // or there is next segment (isc_segment) keep_reading = true; } else if (stat[1] == isc_segstr_eof) { // BLOB is shorter then we expected ??? keep_reading = false; } else { // an error has occured throw_iscerror(stat); } } while (keep_reading); loaded_ = true; } // this method saves BLOB content to database // (a new BLOB will be created at this point) // BLOB will be closed after save. void firebird_blob_backend::save() { // close old blob if necessary ISC_STATUS stat[20]; if (bhp_ != 0) { if (isc_close_blob(stat, &bhp_)) { throw_iscerror(stat); } bhp_ = 0; } // create new blob if (isc_create_blob(stat, &session_.dbhp_, &session_.trhp_, &bhp_, &bid_)) { throw_iscerror(stat); } if (data_.size() > 0) { // write data if (isc_put_segment(stat, &bhp_, static_cast(data_.size()), &data_[0])) { throw_iscerror(stat); } } cleanUp(); from_db_ = true; } // retrives number of segments and total length of BLOB // returns total length of BLOB long firebird_blob_backend::getBLOBInfo() { char blob_items[] = {isc_info_blob_max_segment, isc_info_blob_total_length}; char res_buffer[20], *p, item; short length; long total_length = 0; ISC_STATUS stat[20]; if (isc_blob_info(stat, &bhp_, sizeof(blob_items), blob_items, sizeof(res_buffer), res_buffer)) { throw_iscerror(stat); } for (p = res_buffer; *p != isc_info_end ;) { item = *p++; length = static_cast(isc_vax_integer(p, 2)); p += 2; switch (item) { case isc_info_blob_max_segment: max_seg_size_ = isc_vax_integer(p, length); break; case isc_info_blob_total_length: total_length = isc_vax_integer(p, length); break; case isc_info_truncated: throw soci_error("Fatal Error: BLOB info truncated!"); break; default: break; } p += length; } return total_length; } soci-3.2.3/backends/firebird/error-firebird.cpp0000644000000000000000000000350012511361676020141 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_FIREBIRD_SOURCE #include "soci-firebird.h" #include "error-firebird.h" #include #include namespace soci { firebird_soci_error::firebird_soci_error(std::string const & msg, ISC_STATUS const * status) : soci_error(msg) { if (status != 0) { std::size_t i = 0; while (i < stat_size && status[i] != 0) { status_.push_back(status[i++]); } } } namespace details { namespace firebird { void get_iscerror_details(ISC_STATUS * status_vector, std::string &msg) { char msg_buffer[SOCI_FIREBIRD_ERRMSG]; const ISC_STATUS *pvector = status_vector; try { // fetching first error message fb_interpret(msg_buffer, SOCI_FIREBIRD_ERRMSG, &pvector); msg = msg_buffer; // fetching next errors while (fb_interpret(msg_buffer, SOCI_FIREBIRD_ERRMSG, &pvector)) { msg += "\n"; msg += msg_buffer; } } catch (...) { throw firebird_soci_error("Exception catched while fetching error information"); } } bool check_iscerror(ISC_STATUS const * status_vector, long errNum) { std::size_t i=0; while (status_vector[i] != 0) { if (status_vector[i] == 1 && status_vector[i+1] == errNum) { return true; } ++i; } return false; } void throw_iscerror(ISC_STATUS * status_vector) { std::string msg; get_iscerror_details(status_vector, msg); throw firebird_soci_error(msg, status_vector); } } // namespace firebird } // namespace details } // namespace soci soci-3.2.3/backends/firebird/statement.cpp0000644000000000000000000004554012511362240017226 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_FIREBIRD_SOURCE #include "soci-firebird.h" #include "error-firebird.h" #include #include #include using namespace soci; using namespace soci::details; using namespace soci::details::firebird; firebird_statement_backend::firebird_statement_backend(firebird_session_backend &session) : session_(session), stmtp_(0), sqldap_(NULL), sqlda2p_(NULL), boundByName_(false), boundByPos_(false), rowsFetched_(0), endOfRowSet_(false), rowsAffectedBulk_(-1LL), intoType_(eStandard), useType_(eStandard), procedure_(false) {} void firebird_statement_backend::prepareSQLDA(XSQLDA ** sqldap, int size) { if (*sqldap != NULL) { *sqldap = reinterpret_cast(realloc(*sqldap, XSQLDA_LENGTH(size))); } else { *sqldap = reinterpret_cast(malloc(XSQLDA_LENGTH(size))); } (*sqldap)->sqln = size; (*sqldap)->version = 1; } void firebird_statement_backend::alloc() { ISC_STATUS stat[stat_size]; if (isc_dsql_allocate_statement(stat, &session_.dbhp_, &stmtp_)) { throw_iscerror(stat); } } void firebird_statement_backend::clean_up() { rowsAffectedBulk_ = -1LL; ISC_STATUS stat[stat_size]; if (stmtp_ != NULL) { if (isc_dsql_free_statement(stat, &stmtp_, DSQL_drop)) { throw_iscerror(stat); } stmtp_ = NULL; } if (sqldap_ != NULL) { free(sqldap_); sqldap_ = NULL; } if (sqlda2p_ != NULL) { free(sqlda2p_); sqlda2p_ = NULL; } } void firebird_statement_backend::rewriteParameters( std::string const & src, std::vector & dst) { std::vector::iterator dst_it = dst.begin(); // rewrite the query by transforming all named parameters into // the Firebird question marks (:abc -> ?, etc.) enum { eNormal, eInQuotes, eInName } state = eNormal; std::string name; int position = 0; for (std::string::const_iterator it = src.begin(), end = src.end(); it != end; ++it) { switch (state) { case eNormal: if (*it == '\'') { *dst_it++ = *it; state = eInQuotes; } else if (*it == ':') { state = eInName; } else // regular character, stay in the same state { *dst_it++ = *it; } break; case eInQuotes: if (*it == '\'') { *dst_it++ = *it; state = eNormal; } else // regular quoted character { *dst_it++ = *it; } break; case eInName: if (std::isalnum(*it) || *it == '_') { name += *it; } else // end of name { names_.insert(std::pair(name, position++)); name.clear(); *dst_it++ = '?'; *dst_it++ = *it; state = eNormal; } break; } } if (state == eInName) { names_.insert(std::pair(name, position++)); *dst_it++ = '?'; } *dst_it = '\0'; } namespace { int statementType(isc_stmt_handle stmt) { int stype; int length; char type_item[] = {isc_info_sql_stmt_type}; char res_buffer[8]; ISC_STATUS stat[stat_size]; if (isc_dsql_sql_info(stat, &stmt, sizeof(type_item), type_item, sizeof(res_buffer), res_buffer)) { throw_iscerror(stat); } if (res_buffer[0] == isc_info_sql_stmt_type) { length = isc_vax_integer(res_buffer+1, 2); stype = isc_vax_integer(res_buffer+3, length); } else { throw soci_error("Can't determine statement type."); } return stype; } } void firebird_statement_backend::rewriteQuery( std::string const &query, std::vector &buffer) { // buffer for temporary query std::vector tmpQuery; std::vector::iterator qItr; // buffer for query with named parameters changed to standard ones std::vector rewQuery(query.size() + 1); // take care of named parameters in original query rewriteParameters(query, rewQuery); std::string const prefix("execute procedure "); std::string const prefix2("select * from "); // for procedures, we are preparing statement to determine // type of procedure. if (procedure_) { tmpQuery.resize(prefix.size() + rewQuery.size()); qItr = tmpQuery.begin(); std::copy(prefix.begin(), prefix.end(), qItr); qItr += prefix.size(); } else { tmpQuery.resize(rewQuery.size()); qItr = tmpQuery.begin(); } // prepare temporary query std::copy(rewQuery.begin(), rewQuery.end(), qItr); // preparing buffers for output parameters if (sqldap_ == NULL) { prepareSQLDA(&sqldap_); } ISC_STATUS stat[stat_size]; isc_stmt_handle tmpStmtp = 0; // allocate temporary statement to determine its type if (isc_dsql_allocate_statement(stat, &session_.dbhp_, &tmpStmtp)) { throw_iscerror(stat); } // prepare temporary statement if (isc_dsql_prepare(stat, &(session_.trhp_), &tmpStmtp, 0, &tmpQuery[0], SQL_DIALECT_V6, sqldap_)) { throw_iscerror(stat); } // get statement type int stType = statementType(tmpStmtp); // free temporary prepared statement if (isc_dsql_free_statement(stat, &tmpStmtp, DSQL_drop)) { throw_iscerror(stat); } // take care of special cases if (procedure_) { // for procedures that return values, we need to use correct syntax if (sqldap_->sqld != 0) { // this is "select" procedure, so we have to change syntax buffer.resize(prefix2.size() + rewQuery.size()); qItr = buffer.begin(); std::copy(prefix2.begin(), prefix2.end(), qItr); qItr += prefix2.size(); std::copy(rewQuery.begin(), rewQuery.end(), qItr); // that won't be needed anymore procedure_ = false; return; } } else { // this is not procedure, so syntax is ok except for named // parameters in ddl if (stType == isc_info_sql_stmt_ddl) { // this statement is a DDL - we can't rewrite named parameters // so, we will use original query buffer.resize(query.size() + 1); std::copy(query.begin(), query.end(), buffer.begin()); // that won't be needed anymore procedure_ = false; return; } } // here we know, that temporary query is OK, so we leave it as is buffer.resize(tmpQuery.size()); std::copy(tmpQuery.begin(), tmpQuery.end(), buffer.begin()); // that won't be needed anymore procedure_ = false; } void firebird_statement_backend::prepare(std::string const & query, statement_type /* eType */) { //std::cerr << "prepare: query=" << query << std::endl; // clear named parametes names_.clear(); std::vector queryBuffer; // modify query's syntax and prepare buffer for use with // firebird's api rewriteQuery(query, queryBuffer); ISC_STATUS stat[stat_size]; // prepare real statement if (isc_dsql_prepare(stat, &(session_.trhp_), &stmtp_, 0, &queryBuffer[0], SQL_DIALECT_V6, sqldap_)) { throw_iscerror(stat); } if (sqldap_->sqln < sqldap_->sqld) { // sqlda is too small for all columns. it must be reallocated prepareSQLDA(&sqldap_, sqldap_->sqld); if (isc_dsql_describe(stat, &stmtp_, SQL_DIALECT_V6, sqldap_)) { throw_iscerror(stat); } } // preparing input parameters if (sqlda2p_ == NULL) { prepareSQLDA(&sqlda2p_); } if (isc_dsql_describe_bind(stat, &stmtp_, SQL_DIALECT_V6, sqlda2p_)) { throw_iscerror(stat); } if (sqlda2p_->sqln < sqlda2p_->sqld) { // sqlda is too small for all columns. it must be reallocated prepareSQLDA(&sqlda2p_, sqlda2p_->sqld); if (isc_dsql_describe_bind(stat, &stmtp_, SQL_DIALECT_V6, sqlda2p_)) { throw_iscerror(stat); } } // prepare buffers for indicators inds_.clear(); inds_.resize(sqldap_->sqld); // reset types of into buffers intoType_ = eStandard; intos_.resize(0); // reset types of use buffers useType_ = eStandard; uses_.resize(0); } namespace { void checkSize(std::size_t actual, std::size_t expected, std::string const & name) { if (actual != expected) { std::ostringstream msg; msg << "Incorrect number of " << name << " variables. " << "Expected " << expected << ", got " << actual; throw soci_error(msg.str()); } } } statement_backend::exec_fetch_result firebird_statement_backend::execute(int number) { ISC_STATUS stat[stat_size]; XSQLDA *t = NULL; std::size_t usize = uses_.size(); // do we have enough into variables ? checkSize(intos_.size(), sqldap_->sqld, "into"); // do we have enough use variables ? checkSize(usize, sqlda2p_->sqld, "use"); // do we have parameters ? if (sqlda2p_->sqld) { t = sqlda2p_; if (useType_ == eStandard) { for (std::size_t col=0; col(uses_[col])->exchangeData(); } } } // make sure there is no active cursor if (isc_dsql_free_statement(stat, &stmtp_, DSQL_close)) { // ignore attempt to close already closed cursor if (check_iscerror(stat, isc_dsql_cursor_close_err) == false) { throw_iscerror(stat); } } if (useType_ == eVector) { long long rowsAffectedBulkTemp = 0; // Here we have to explicitly loop to achieve the // effect of inserting or updating with vector use elements. std::size_t rows = static_cast(uses_[0])->size(); for (std::size_t row=0; row < rows; ++row) { // first we have to prepare input parameters for (std::size_t col=0; col(uses_[col])->exchangeData(row); } // then execute query if (isc_dsql_execute(stat, &session_.trhp_, &stmtp_, SQL_DIALECT_V6, t)) { // preserve the number of rows affected so far. rowsAffectedBulk_ = rowsAffectedBulkTemp; throw_iscerror(stat); } else { rowsAffectedBulkTemp += get_affected_rows(); } // soci does not allow bulk insert/update and bulk select operations // in same query. So here, we know that into elements are not // vectors. So, there is no need to fetch data here. } rowsAffectedBulk_ = rowsAffectedBulkTemp; } else { // use elements aren't vectors if (isc_dsql_execute(stat, &session_.trhp_, &stmtp_, SQL_DIALECT_V6, t)) { throw_iscerror(stat); } } // Successfully re-executing the statement must reset the "end of rowset" // flag, we might be able to fetch data again now. endOfRowSet_ = false; if (sqldap_->sqld) { // query may return some data if (number > 0) { // number contains size of input variables, so we may fetch() data here return fetch(number); } else { // execute(0) was meant to only perform the query return ef_success; } } else { // query can't return any data return ef_no_data; } } statement_backend::exec_fetch_result firebird_statement_backend::fetch(int number) { if (endOfRowSet_) return ef_no_data; ISC_STATUS stat[stat_size]; for (size_t i = 0; i(sqldap_->sqld); ++i) { inds_[i].resize(number > 0 ? number : 1); } // Here we have to explicitly loop to achieve the effect of fetching // vector into elements. After each fetch, we have to exchange data // with into buffers. rowsFetched_ = 0; for (int i = 0; i < number; ++i) { long fetch_stat = isc_dsql_fetch(stat, &stmtp_, SQL_DIALECT_V6, sqldap_); // there is more data to read if (fetch_stat == 0) { ++rowsFetched_; exchangeData(true, i); } else if (fetch_stat == 100L) { endOfRowSet_ = true; return ef_no_data; } else { // error endOfRowSet_ = true; throw_iscerror(stat); return ef_no_data; // unreachable, for compiler only } } // for return ef_success; } // here we put data fetched from database into user buffers void firebird_statement_backend::exchangeData(bool gotData, int row) { if (gotData) { for (size_t i = 0; i < static_cast(sqldap_->sqld); ++i) { // first save indicators if (((sqldap_->sqlvar+i)->sqltype & 1) == 0) { // there is no indicator for this column inds_[i][row] = i_ok; } else if (*((sqldap_->sqlvar+i)->sqlind) == 0) { inds_[i][row] = i_ok; } else if (*((sqldap_->sqlvar+i)->sqlind) == -1) { inds_[i][row] = i_null; } else { throw soci_error("Unknown state in firebird_statement_backend::exchangeData()"); } // then deal with data if (inds_[i][row] != i_null) { if (intoType_ == eVector) { static_cast( intos_[i])->exchangeData(row); } else { static_cast( intos_[i])->exchangeData(); } } } } } long long firebird_statement_backend::get_affected_rows() { if (rowsAffectedBulk_ >= 0) { return rowsAffectedBulk_; } ISC_STATUS_ARRAY stat; char type_item[] = { isc_info_sql_records }; char res_buffer[256]; if (isc_dsql_sql_info(stat, &stmtp_, sizeof(type_item), type_item, sizeof(res_buffer), res_buffer)) { throw_iscerror(stat); } // We must get back a isc_info_sql_records block, that we parse below, // followed by isc_info_end. if (res_buffer[0] != isc_info_sql_records) { throw soci_error("Can't determine the number of affected rows"); } char* sql_rec_buf = res_buffer + 1; const int length = isc_vax_integer(sql_rec_buf, 2); sql_rec_buf += 2; if (sql_rec_buf[length] != isc_info_end) { throw soci_error("Unexpected isc_info_sql_records return format"); } // Examine the 4 sub-blocks each of which has a header indicating the block // type, its value length in bytes and the value itself. long long row_count = 0; for ( char* p = sql_rec_buf; !row_count && p < sql_rec_buf + length; ) { switch (*p++) { case isc_info_req_select_count: case isc_info_req_insert_count: case isc_info_req_update_count: case isc_info_req_delete_count: { int len = isc_vax_integer(p, 2); p += 2; row_count += isc_vax_integer(p, len); p += len; } break; case isc_info_end: break; default: throw soci_error("Unknown record counter"); } } return row_count; } int firebird_statement_backend::get_number_of_rows() { return rowsFetched_; } std::string firebird_statement_backend::rewrite_for_procedure_call( std::string const &query) { procedure_ = true; return query; } int firebird_statement_backend::prepare_for_describe() { return static_cast(sqldap_->sqld); } void firebird_statement_backend::describe_column(int colNum, data_type & type, std::string & columnName) { XSQLVAR * var = sqldap_->sqlvar+(colNum-1); columnName.assign(var->aliasname, var->aliasname_length); switch (var->sqltype & ~1) { case SQL_TEXT: case SQL_VARYING: type = dt_string; break; case SQL_TYPE_DATE: case SQL_TYPE_TIME: case SQL_TIMESTAMP: type = dt_date; break; case SQL_FLOAT: case SQL_DOUBLE: type = dt_double; break; case SQL_SHORT: case SQL_LONG: if (var->sqlscale < 0) { if (session_.get_option_decimals_as_strings()) type = dt_string; else type = dt_double; } else { type = dt_integer; } break; case SQL_INT64: if (var->sqlscale < 0) { if (session_.get_option_decimals_as_strings()) type = dt_string; else type = dt_double; } else { type = dt_long_long; } break; /* case SQL_BLOB: case SQL_ARRAY:*/ default: std::ostringstream msg; msg << "Type of column ["<< colNum << "] \"" << columnName << "\" is not supported for dynamic queries"; throw soci_error(msg.str()); break; } } firebird_standard_into_type_backend * firebird_statement_backend::make_into_type_backend() { return new firebird_standard_into_type_backend(*this); } firebird_standard_use_type_backend * firebird_statement_backend::make_use_type_backend() { return new firebird_standard_use_type_backend(*this); } firebird_vector_into_type_backend * firebird_statement_backend::make_vector_into_type_backend() { return new firebird_vector_into_type_backend(*this); } firebird_vector_use_type_backend * firebird_statement_backend::make_vector_use_type_backend() { return new firebird_vector_use_type_backend(*this); } soci-3.2.3/backends/firebird/vector-use-type.cpp0000644000000000000000000001216012511361676020301 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_FIREBIRD_SOURCE #include "soci-firebird.h" #include "common.h" using namespace soci; using namespace soci::details; using namespace soci::details::firebird; void firebird_vector_use_type_backend::bind_by_pos(int & position, void * data, exchange_type type) { if (statement_.boundByName_) { throw soci_error( "Binding for use elements must be either by position or by name."); } position_ = position-1; data_ = data; type_ = type; ++position; statement_.useType_ = eVector; statement_.uses_.push_back(static_cast(this)); XSQLVAR *var = statement_.sqlda2p_->sqlvar+position_; buf_ = allocBuffer(var); var->sqldata = buf_; var->sqlind = &indISCHolder_; statement_.boundByPos_ = true; } void firebird_vector_use_type_backend::bind_by_name( std::string const & name, void * data, exchange_type type) { if (statement_.boundByPos_) { throw soci_error( "Binding for use elements must be either by position or by name."); } std::map :: iterator idx = statement_.names_.find(name); if (idx == statement_.names_.end()) { throw soci_error("Missing use element for bind by name (" + name + ")"); } position_ = idx->second; data_ = data; type_ = type; statement_.useType_ = eVector; statement_.uses_.push_back(static_cast(this)); XSQLVAR *var = statement_.sqlda2p_->sqlvar+position_; buf_ = allocBuffer(var); var->sqldata = buf_; var->sqlind = &indISCHolder_; statement_.boundByName_ = true; } void firebird_vector_use_type_backend::pre_use(indicator const * ind) { inds_ = ind; } namespace { template T* getUseVectorValue(void *v, std::size_t index) { std::vector *src = static_cast *>(v); std::vector &v_ = *src; return &(v_[index]); } } void firebird_vector_use_type_backend::exchangeData(std::size_t row) { // first prepare indicators if (inds_ != NULL) { switch (inds_[row]) { case i_null: indISCHolder_ = -1; break; case i_ok: indISCHolder_ = 0; break; default: throw soci_error("Use element used with non-supported indicator type."); } } XSQLVAR * var = statement_.sqlda2p_->sqlvar+position_; // then set parameters for query execution switch (type_) { // simple cases case x_char: setTextParam(getUseVectorValue(data_, row), 1, buf_, var); break; case x_short: to_isc( static_cast(getUseVectorValue(data_, row)), var); break; case x_integer: to_isc( static_cast(getUseVectorValue(data_, row)), var); break; case x_long_long: to_isc( static_cast(getUseVectorValue(data_, row)), var); break; case x_double: to_isc( static_cast(getUseVectorValue(data_, row)), var); break; // cases that require adjustments and buffer management case x_stdstring: { std::string *tmp = getUseVectorValue(data_, row); setTextParam(tmp->c_str(), tmp->size(), buf_, var); } break; case x_stdtm: tmEncode(var->sqltype, getUseVectorValue(data_, row), buf_); break; // Not supported // case x_cstring: // case x_blob: default: throw soci_error("Use element used with non-supported type."); } // switch } std::size_t firebird_vector_use_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type_) { // simple cases case x_char: sz = getVectorSize (data_); break; case x_short: sz = getVectorSize (data_); break; case x_integer: sz = getVectorSize (data_); break; case x_long_long: sz = getVectorSize (data_); break; case x_double: sz = getVectorSize (data_); break; case x_stdstring: sz = getVectorSize (data_); break; case x_stdtm: sz = getVectorSize (data_); break; default: throw soci_error("Use vector element used with non-supported type."); } return sz; } void firebird_vector_use_type_backend::clean_up() { if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } std::vector::iterator it = std::find(statement_.uses_.begin(), statement_.uses_.end(), this); if (it != statement_.uses_.end()) statement_.uses_.erase(it); } soci-3.2.3/backends/firebird/standard-use-type.cpp0000644000000000000000000001172512511361676020605 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_FIREBIRD_SOURCE #include "soci-firebird.h" #include "common.h" #include using namespace soci; using namespace soci::details; using namespace soci::details::firebird; void firebird_standard_use_type_backend::bind_by_pos( int & position, void * data, exchange_type type, bool /* readOnly */) { if (statement_.boundByName_) { throw soci_error( "Binding for use elements must be either by position or by name."); } position_ = position-1; data_ = data; type_ = type; ++position; statement_.useType_ = eStandard; statement_.uses_.push_back(static_cast(this)); XSQLVAR *var = statement_.sqlda2p_->sqlvar+position_; buf_ = allocBuffer(var); var->sqldata = buf_; var->sqlind = &indISCHolder_; statement_.boundByPos_ = true; } void firebird_standard_use_type_backend::bind_by_name( std::string const & name, void * data, exchange_type type, bool /* readOnly */) { if (statement_.boundByPos_) { throw soci_error( "Binding for use elements must be either by position or by name."); } std::map :: iterator idx = statement_.names_.find(name); if (idx == statement_.names_.end()) { throw soci_error("Missing use element for bind by name (" + name + ")"); } position_ = idx->second; data_ = data; type_ = type; statement_.useType_ = eStandard; statement_.uses_.push_back(static_cast(this)); XSQLVAR *var = statement_.sqlda2p_->sqlvar+position_; buf_ = allocBuffer(var); var->sqldata = buf_; var->sqlind = &indISCHolder_; statement_.boundByName_ = true; } void firebird_standard_use_type_backend::pre_use(indicator const * ind) { indISCHolder_ = 0; if (ind) { switch (*ind) { case i_null: indISCHolder_ = -1; break; case i_ok: indISCHolder_ = 0; break; default: throw soci_error("Unsupported indicator value."); } } } void firebird_standard_use_type_backend::exchangeData() { XSQLVAR *var = statement_.sqlda2p_->sqlvar+position_; if (0 != indISCHolder_) return; switch (type_) { case x_char: setTextParam(static_cast(data_), 1, buf_, var); break; case x_short: to_isc(data_, var); break; case x_integer: to_isc(data_, var); break; case x_long_long: to_isc(data_, var); break; case x_double: to_isc(data_, var); break; case x_stdstring: { std::string *tmp = static_cast(data_); setTextParam(tmp->c_str(), tmp->size(), buf_, var); } break; case x_stdtm: tmEncode(var->sqltype, static_cast(data_), buf_); break; // cases that require special handling case x_blob: { blob *tmp = static_cast(data_); firebird_blob_backend* blob = dynamic_cast(tmp->get_backend()); if (NULL == blob) { throw soci_error("Can't get Firebid BLOB BackEnd"); } blob->save(); memcpy(buf_, &blob->bid_, var->sqllen); } break; default: throw soci_error("Use element used with non-supported type."); } // switch } void firebird_standard_use_type_backend::post_use( bool /* gotData */, indicator * /* ind */) { // TODO: Is it possible to have the bound element being overwritten // by the database? // If not, then nothing to do here, please remove this comment. // If yes, then use the value of the readOnly parameter: // - true: the given object should not be modified and the backend // should detect if the modification was performed on the // isolated buffer and throw an exception if the buffer was modified // (this indicates logic error, because the user used const object // and executed a query that attempted to modified it) // - false: the modification should be propagated to the given object. // ... } void firebird_standard_use_type_backend::clean_up() { if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } std::vector::iterator it = std::find(statement_.uses_.begin(), statement_.uses_.end(), this); if (it != statement_.uses_.end()) statement_.uses_.erase(it); } soci-3.2.3/backends/firebird/session.cpp0000644000000000000000000002225012511361676016712 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_FIREBIRD_SOURCE #include "soci-firebird.h" #include "error-firebird.h" #include "session.h" #include #include #include #include using namespace soci; using namespace soci::details::firebird; namespace { // Helpers of explodeISCConnectString() for reading words from a string. "Word" // here is defined very loosely as just a sequence of non-space characters. // // All these helper functions update the input iterator to point to the first // character not consumed by them. // Advance the input iterator until the first non-space character or end of the // string. void skipWhiteSpace(std::string::const_iterator& i, std::string::const_iterator const &end) { std::locale const loc; for (; i != end; ++i) { if (!std::isspace(*i, loc)) break; } } // Return the string of all characters until the first space or the specified // delimiter. // // Throws if the first non-space character after the end of the word is not the // delimiter. However just returns en empty string, without throwing, if // nothing is left at all in the string except for white space. std::string getWordUntil(std::string const &s, std::string::const_iterator &i, char delim) { std::string::const_iterator const end = s.end(); skipWhiteSpace(i, end); // We need to handle this case specially because it's not an error if // nothing at all remains in the string. But if anything does remain, then // we must have the delimiter. if (i == end) return std::string(); // Simply put anything until the delimiter into the word, stopping at the // first white space character. std::string word; std::locale const loc; for (; i != end; ++i) { if (*i == delim) break; if (std::isspace(*i, loc)) { skipWhiteSpace(i, end); if (i == end || *i != delim) { std::ostringstream os; os << "Expected '" << delim << "' at position " << (i - s.begin() + 1) << " in Firebird connection string \"" << s << "\"."; throw soci_error(os.str()); } break; } word += *i; } if (i == end) { std::ostringstream os; os << "Expected '" << delim << "' not found before the end of the string " << "in Firebird connection string \"" << s << "\"."; throw soci_error(os.str()); } ++i; // Skip the delimiter itself. return word; } // Return a possibly quoted word, i.e. either just a sequence of non-space // characters or everything inside a double-quoted string. // // Throws if the word is quoted and the closing quote is not found. However // doesn't throw, just returns an empty string if there is nothing left. std::string getPossiblyQuotedWord(std::string const &s, std::string::const_iterator &i) { std::string::const_iterator const end = s.end(); skipWhiteSpace(i, end); std::string word; if (i != end && *i == '"') { for (;;) { if (++i == end) { std::ostringstream os; os << "Expected '\"' not found before the end of the string " "in Firebird connection string \"" << s << "\"."; throw soci_error(os.str()); } if (*i == '"') { ++i; break; } word += *i; } } else // Not quoted. { std::locale const loc; for (; i != end; ++i) { if (std::isspace(*i, loc)) break; word += *i; } } return word; } // retrieves parameters from the uniform connect string which is supposed to be // in the form "key=value[ key2=value2 ...]" and the values may be quoted to // allow including spaces into them. Notice that currently there is no way to // include both a space and a double quote in a value. std::map explodeISCConnectString(std::string const &connectString) { std::map parameters; std::string key, value; for (std::string::const_iterator i = connectString.begin(); ; ) { key = getWordUntil(connectString, i, '='); if (key.empty()) break; value = getPossiblyQuotedWord(connectString, i); parameters.insert(std::pair(key, value)); } return parameters; } // extracts given parameter from map previusly build with explodeISCConnectString bool getISCConnectParameter(std::map const & m, std::string const & key, std::string & value) { std::map :: const_iterator i; value.clear(); i = m.find(key); if (i != m.end()) { value = i->second; return true; } else { return false; } } } // namespace anonymous firebird_session_backend::firebird_session_backend( connection_parameters const & parameters) : dbhp_(0), trhp_(0) , decimals_as_strings_(false) { // extract connection parameters std::map params(explodeISCConnectString(parameters.get_connect_string())); ISC_STATUS stat[stat_size]; std::string param; // preparing connection options if (getISCConnectParameter(params, "user", param)) { setDPBOption(isc_dpb_user_name, param); } if (getISCConnectParameter(params, "password", param)) { setDPBOption(isc_dpb_password, param); } if (getISCConnectParameter(params, "role", param)) { setDPBOption(isc_dpb_sql_role_name, param); } if (getISCConnectParameter(params, "charset", param)) { setDPBOption(isc_dpb_lc_ctype, param); } if (getISCConnectParameter(params, "service", param) == false) { throw soci_error("Service name not specified."); } // connecting data base if (isc_attach_database(stat, static_cast(param.size()), const_cast(param.c_str()), &dbhp_, static_cast(dpb_.size()), const_cast(dpb_.c_str()))) { throw_iscerror(stat); } if (getISCConnectParameter(params, "decimals_as_strings", param)) { decimals_as_strings_ = param == "1" || param == "Y" || param == "y"; } // starting transaction begin(); } void firebird_session_backend::begin() { // Transaction is always started in ctor, because Firebird can't work // without active transaction. // Transaction will be automatically commited in cleanUp method. if (trhp_ == 0) { ISC_STATUS stat[stat_size]; if (isc_start_transaction(stat, &trhp_, 1, &dbhp_, 0, NULL)) { throw_iscerror(stat); } } } firebird_session_backend::~firebird_session_backend() { cleanUp(); } void firebird_session_backend::setDPBOption(int const option, std::string const & value) { if (dpb_.size() == 0) { dpb_.append(1, static_cast(isc_dpb_version1)); } // now we are adding new option dpb_.append(1, static_cast(option)); dpb_.append(1, static_cast(value.size())); dpb_.append(value); } void firebird_session_backend::commit() { ISC_STATUS stat[stat_size]; if (trhp_ != 0) { if (isc_commit_transaction(stat, &trhp_)) { throw_iscerror(stat); } trhp_ = 0; } #ifndef SOCI_FIREBIRD_NORESTARTTRANSACTION begin(); #endif } void firebird_session_backend::rollback() { ISC_STATUS stat[stat_size]; if (trhp_ != 0) { if (isc_rollback_transaction(stat, &trhp_)) { throw_iscerror(stat); } trhp_ = 0; } #ifndef SOCI_FIREBIRD_NORESTARTTRANSACTION begin(); #endif } void firebird_session_backend::cleanUp() { ISC_STATUS stat[stat_size]; // at the end of session our transaction is finally commited. if (trhp_ != 0) { if (isc_commit_transaction(stat, &trhp_)) { throw_iscerror(stat); } trhp_ = 0; } if (isc_detach_database(stat, &dbhp_)) { throw_iscerror(stat); } dbhp_ = 0L; } bool firebird_session_backend::get_next_sequence_value( session & s, std::string const & sequence, long & value) { // We could use isq_execute2() directly but this is even simpler. s << "select next value for " + sequence + " from rdb$database", into(value); return true; } firebird_statement_backend * firebird_session_backend::make_statement_backend() { return new firebird_statement_backend(*this); } firebird_rowid_backend * firebird_session_backend::make_rowid_backend() { return new firebird_rowid_backend(*this); } firebird_blob_backend * firebird_session_backend::make_blob_backend() { return new firebird_blob_backend(*this); } soci-3.2.3/backends/firebird/Makefile.basic0000644000000000000000000000560412511361676017247 0ustar rootroot# The following variable is specific to this backend and its correct # values might depend on your environment - feel free to set it accordingly. FIREBIRDINCLUDEDIR = -I/usr/local/firebird/include # The rest of the Makefile is indepentent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long CXXFLAGSSO = ${CXXFLAGS} -fPIC INCLUDEDIRS = -I../../core ${FIREBIRDINCLUDEDIR} OBJECTS = blob.o factory.o row-id.o session.o standard-into-type.o \ standard-use-type.o statement.o vector-into-type.o vector-use-type.o \ error-firebird.o common.o OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \ standard-into-type-s.o standard-use-type-s.o statement-s.o \ vector-into-type-s.o vector-use-type-s.o error-firebird-s.o common-s.o FIREBIRDLIBS = -lfbclient -lpthread libsoci_firebird.a : ${OBJECTS} ar rv $@ $? rm *.o soci-firebird.o : soci-firebird.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} blob.o : blob.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} error-firebird.o : error-firebird.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} common.o : common.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} factory.o : factory.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} row-id.o : row-id.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} session.o : session.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-into-type.o : standard-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-use-type.o : standard-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} statement.o : statement.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-into-type.o : vector-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-use-type.o : vector-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} shared : ${OBJECTSSO} ${COMPILER} -shared -o libsoci_firebird.so ${OBJECTSSO} ${FIREBIRDLIBS} rm *.o blob-s.o : blob.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} error-firebird-s.o : error-firebird.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} common-s.o : common.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} factory-s.o : factory.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} row-id-s.o : row-id.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} session-s.o : session.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} standard-into-type-s.o : standard-into-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} standard-use-type-s.o : standard-use-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} statement-s.o : statement.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} vector-into-type-s.o : vector-into-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} vector-use-type-s.o : vector-use-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} clean : rm -f *.o libsoci_firebird.a libsoci_firebird.so soci-3.2.3/backends/firebird/factory.cpp0000644000000000000000000000153212511361676016676 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_FIREBIRD_SOURCE #include "soci-firebird.h" #include using namespace soci; firebird_session_backend * firebird_backend_factory::make_session( connection_parameters const & parameters) const { return new firebird_session_backend(parameters); } firebird_backend_factory const soci::firebird; extern "C" { // for dynamic backend loading SOCI_FIREBIRD_DECL backend_factory const * factory_firebird() { return &soci::firebird; } SOCI_FIREBIRD_DECL void register_factory_firebird() { soci::dynamic_backends::register_backend("firebird", soci::firebird); } } // extern "C" soci-3.2.3/backends/firebird/row-id.cpp0000644000000000000000000000105312511361676016426 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_FIREBIRD_SOURCE #include "soci-firebird.h" using namespace soci; firebird_rowid_backend::firebird_rowid_backend(firebird_session_backend & /* session */) { // Unsupported in Firebird backend throw soci_error("RowIDs are not supported"); } firebird_rowid_backend::~firebird_rowid_backend() { } soci-3.2.3/backends/firebird/standard-into-type.cpp0000644000000000000000000001005612511361676020756 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_FIREBIRD_SOURCE #include "soci-firebird.h" #include "common.h" #include using namespace soci; using namespace soci::details; using namespace soci::details::firebird; void firebird_standard_into_type_backend::define_by_pos( int & position, void * data, exchange_type type) { position_ = position-1; data_ = data; type_ = type; ++position; statement_.intoType_ = eStandard; statement_.intos_.push_back(static_cast(this)); XSQLVAR *var = statement_.sqldap_->sqlvar+position_; buf_ = allocBuffer(var); var->sqldata = buf_; var->sqlind = &indISCHolder_; } void firebird_standard_into_type_backend::pre_fetch() { // nothing to do } void firebird_standard_into_type_backend::post_fetch( bool gotData, bool calledFromFetch, indicator * ind) { if (calledFromFetch && (gotData == false)) { // this is a normal end-of-rowset condition, // no need to set anything (fetch() will return false) return; } if (gotData) { if (i_null == statement_.inds_[position_][0] && NULL == ind) { throw soci_error("Null value fetched and no indicator defined."); } else if (NULL != ind) { *ind = statement_.inds_[position_][0]; } } } void firebird_standard_into_type_backend::exchangeData() { XSQLVAR *var = statement_.sqldap_->sqlvar+position_; switch (type_) { // simple cases case x_char: *reinterpret_cast(data_) = getTextParam(var)[0]; break; case x_short: { short t = from_isc(var); *reinterpret_cast(data_) = t; } break; case x_integer: { int t = from_isc(var); *reinterpret_cast(data_) = t; } break; case x_long_long: { long long t = from_isc(var); *reinterpret_cast(data_) = t; } break; case x_double: { double t = from_isc(var); *reinterpret_cast(data_) = t; } break; // cases that require adjustments and buffer management case x_stdstring: *(reinterpret_cast(data_)) = getTextParam(var); break; case x_stdtm: tmDecode(var->sqltype, buf_, static_cast(data_)); // isc_decode_timestamp() used by tmDecode() incorrectly sets // tm_isdst to 0 in the struct that it creates, see // http://tracker.firebirdsql.org/browse/CORE-3877, work around it // by pretending the DST is actually unknown. static_cast(data_)->tm_isdst = -1; break; // cases that require special handling case x_blob: { blob *tmp = reinterpret_cast(data_); firebird_blob_backend *blob = dynamic_cast(tmp->get_backend()); if (0 == blob) { throw soci_error("Can't get Firebid BLOB BackEnd"); } blob->assign(*reinterpret_cast(buf_)); } break; default: throw soci_error("Into element used with non-supported type."); } // switch } void firebird_standard_into_type_backend::clean_up() { if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } std::vector::iterator it = std::find(statement_.intos_.begin(), statement_.intos_.end(), this); if (it != statement_.intos_.end()) statement_.intos_.erase(it); } soci-3.2.3/backends/firebird/test/0000755000000000000000000000000012511362240015465 5ustar rootrootsoci-3.2.3/backends/firebird/test/test-firebird.cpp0000644000000000000000000010437012511362240020741 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // #include "soci.h" #include "soci-firebird.h" #include "error-firebird.h" // soci::details::Firebird::throw_iscerror() #include "common-tests.h" #include "common.h" #include #include #include #include #include #include using namespace soci; std::string connectString; soci::backend_factory const &backEnd = *factory_firebird(); // fundamental tests - transactions in Firebird void test1() { { session sql(backEnd, connectString); // In Firebird transaction is always required and is started // automatically when session is opened. There is no need to // call session::begin(); it will do nothing if there is active // transaction. // sql.begin(); try { sql << "drop table test1"; } catch (soci_error const &) {} // ignore if error sql << "create table test1 (id integer)"; // After DDL statement transaction must be commited or changes // won't be visible to active transaction. sql.commit(); // After commit or rollback, transaction must be started manually. sql.begin(); sql << "insert into test1(id) values(5)"; sql << "drop table test1"; // Transaction is automatically commited in session's destructor } std::cout << "test 1 passed" << std::endl; } // character types void test2() { session sql(backEnd, connectString); try { sql << "drop table test2"; } catch (soci_error const &) {} // ignore if error sql << "create table test2 (p1 char(10), p2 varchar(10))"; sql.commit(); sql.begin(); { char a('a'), b('b'), c1, c2; sql << "insert into test2(p1,p2) values(?,?)", use(a), use(b); sql << "select p1,p2 from test2", into(c1), into(c2); assert(c1 == 'a' && c2 == 'b'); sql << "delete from test2"; } #if 0 // SOCI doesn't support binding into(char *, ...) anymore, use std::string { char msg[] = "Hello, Firebird!"; char buf1[100], buf2[100], buf3[100]; char *b1 = buf1, *b2 = buf2, *b3 = buf3; strcpy(b1, msg); sql << "insert into test2(p1, p2) values (?,?)", use(b1, 100), use(b1, 100); sql << "select p1, p2 from test2", into(b2, 100), into(b3, 100); assert(!std::strcmp(buf2, buf3) && !std::strcmp(buf2, "Hello, Fir")); sql << "delete from test2"; } { char msg[] = "Hello, Firebird!"; char buf1[100], buf2[100], buf3[100]; strcpy(buf1, msg); sql << "insert into test2(p1, p2) values (?,?)", use(buf1), use(buf1); sql << "select p1, p2 from test2", into(buf2), into(buf3); assert(!std::strcmp(buf2, buf3) && !std::strcmp(buf2, "Hello, Fir")); sql << "delete from test2"; } #endif { std::string b1("Hello, Firebird!"), b2, b3; sql << "insert into test2(p1, p2) values (?,?)", use(b1), use(b1); sql << "select p1, p2 from test2", into(b2), into(b3); assert(b2 == b3 && b2 == "Hello, Fir"); sql << "delete from test2"; } { // verify blank padding in CHAR fields // In Firebird, CHAR fields are always padded with whitespaces. char msg[] = "Hello"; sql << "insert into test2(p1) values(\'" << msg << "\')"; char buf[20]; std::string buf_str; sql << "select p1 from test2", into(buf_str); std::strcpy(buf, buf_str.c_str()); assert(std::strncmp(buf, msg, 5) == 0); assert(std::strncmp(buf+5, " ", 5) == 0); sql << "delete from test2"; } { std::string str1("Hello, Firebird!"), str2, str3; sql << "insert into test2(p1, p2) values (?, ?)", use(str1), use(str1); sql << "select p1, p2 from test2", into(str2), into(str3); assert(str2 == "Hello, Fir" && str3 == "Hello, Fir"); sql << "delete from test2"; } sql << "drop table test2"; std::cout << "test 2 passed" << std::endl; } // date and time void test3() { session sql(backEnd, connectString); try { sql << "drop table test3"; } catch (soci_error const &) {} // ignore if error sql << "create table test3 (p1 timestamp, p2 date, p3 time)"; sql.commit(); sql.begin(); std::tm t1, t2, t3; std::time_t now = std::time(NULL); std::tm t = *std::localtime(&now); sql << "insert into test3(p1, p2, p3) " << "values (?,?,?)", use(t), use(t), use(t); sql << "select p1, p2, p3 from test3", into(t1), into(t2), into(t3); // timestamp assert(t1.tm_year == t.tm_year); assert(t1.tm_mon == t.tm_mon); assert(t1.tm_mday == t.tm_mday); assert(t1.tm_hour == t.tm_hour); assert(t1.tm_min == t.tm_min); assert(t1.tm_sec == t.tm_sec); // date assert(t2.tm_year == t.tm_year); assert(t2.tm_mon == t.tm_mon); assert(t2.tm_mday == t.tm_mday); assert(t2.tm_hour == 0); assert(t2.tm_min == 0); assert(t2.tm_sec == 0); // time assert(t3.tm_year == 0); assert(t3.tm_mon == 0); assert(t3.tm_mday == 0); assert(t3.tm_hour == t.tm_hour); assert(t3.tm_min == t.tm_min); assert(t3.tm_sec == t.tm_sec); sql << "drop table test3"; std::cout << "test 3 passed" << std::endl; } // floating points void test4() { session sql(backEnd, connectString); try { sql << "drop table test4"; } catch (soci_error const &) {} // ignore if error sql << "create table test4 (p1 numeric(8,2), " << "p2 decimal(14,8), p3 double precision, p4 integer)"; sql.commit(); sql.begin(); double d1 = 1234.23, d2 = 1e8, d3 = 1.0/1440.0, d4, d5, d6; sql << "insert into test4(p1, p2, p3) values (?,?,?)", use(d1), use(d2), use(d3); sql << "select p1, p2, p3 from test4", into(d4), into(d5), into(d6); assert(d1 == d4 && d2 == d5 && d3 == d6); // test negative doubles too sql << "delete from test4"; d1 = -d1; d2 = -d2; d3 = -d3; sql << "insert into test4(p1, p2, p3) values (?,?,?)", use(d1), use(d2), use(d3); sql << "select p1, p2, p3 from test4", into(d4), into(d5), into(d6); assert(d1 == d4 && d2 == d5 && d3 == d6); // verify an exception is thrown when fetching non-integral value // to integral variable try { int i; sql << "select p1 from test4", into(i); // expecting error assert(false); } catch (soci_error const &e) { std::string error = e.what(); assert(error == "Can't convert value with scale 2 to integral type"); } // verify an exception is thrown when inserting non-integral value // to integral column try { sql << "insert into test4(p4) values(?)", use(d1); // expecting error assert(false); } catch (soci_error const &e) { std::string error = e.what(); assert(error == "Can't convert non-integral value to integral column type"); } sql << "drop table test4"; std::cout << "test 4 passed" << std::endl; } // integer types and indicators void test5() { session sql(backEnd, connectString); { short sh(0); sql << "select 3 from rdb$database", into(sh); assert(sh == 3); } { int i(0); sql << "select 5 from rdb$database", into(i); assert(i == 5); } { unsigned long ul(0); sql << "select 7 from rdb$database", into(ul); assert(ul == 7); } { // test indicators indicator ind; int i; sql << "select 2 from rdb$database", into(i, ind); assert(ind == i_ok); sql << "select NULL from rdb$database", into(i, ind); assert(ind == i_null); #if 0 // SOCI doesn't support binding into(char *, ...) anymore, use std::string char buf[4]; sql << "select \'Hello\' from rdb$database", into(buf, ind); assert(ind == i_truncated); #endif sql << "select 5 from rdb$database where 0 = 1", into(i, ind); assert(sql.got_data() == false); try { // expect error sql << "select NULL from rdb$database", into(i); assert(false); } catch (soci_error const &e) { std::string error = e.what(); assert(error == "Null value fetched and no indicator defined."); } // expect no data sql << "select 5 from rdb$database where 0 = 1", into(i); assert(!sql.got_data()); } std::cout << "test 5 passed" << std::endl; } // repeated fetch and bulk operations for character types void test6() { session sql(backEnd, connectString); try { sql << "drop table test6"; } catch (soci_error const &) {} // ignore if error sql << "create table test6 (p1 char(10), p2 varchar(10))"; sql.commit(); sql.begin(); for (char c = 'a'; c <= 'z'; ++c) { sql << "insert into test6(p1, p2) values(?,?)", use(c), use(c); } { char c, c1, c2; statement st = (sql.prepare << "select p1,p2 from test6 order by p1", into(c1), into(c2)); // Verify that fetch after re-executing the same statement works. for (int n = 0; n < 2; ++n) { st.execute(); c='a'; while (st.fetch()) { assert(c == c1 && c == c2); ++c; } assert(c == 'z'+1); } } { char c='a'; std::vector c1(10), c2(10); statement st = (sql.prepare << "select p1,p2 from test6 order by p1", into(c1), into(c2)); st.execute(); while (st.fetch()) { for (std::size_t i = 0; i != c1.size(); ++i) { assert(c == c1[i] && c == c2[i]); ++c; } } assert(c == 'z' + 1); } { // verify an exception is thrown when empty vector is used std::vector vec; try { sql << "select p1 from test6", into(vec); assert(false); } catch (soci_error const &e) { std::string msg = e.what(); assert(msg == "Vectors of size 0 are not allowed."); } } sql << "delete from test6"; // verifying std::string int const rowsToTest = 10; for (int i = 0; i != rowsToTest; ++i) { std::ostringstream ss; ss << "Hello_" << i; std::string const &x = ss.str(); sql << "insert into test6(p1, p2) values(\'" << x << "\', \'" << x << "\')"; } int count; sql << "select count(*) from test6", into(count); assert(count == rowsToTest); { int i = 0; std::string s1, s2; statement st = (sql.prepare << "select p1, p2 from test6 order by p1", into(s1), into(s2)); st.execute(); while (st.fetch()) { std::ostringstream ss; ss << "Hello_" << i; std::string const &x = ss.str(); // Note: CHAR fields are always padded with whitespaces ss << " "; assert(s1 == ss.str() && s2 == x); ++i; } assert(i == rowsToTest); } { int i = 0; std::vector s1(4), s2(4); statement st = (sql.prepare << "select p1, p2 from test6 order by p1", into(s1), into(s2)); st.execute(); while (st.fetch()) { for (std::size_t j = 0; j != s1.size(); ++j) { std::ostringstream ss; ss << "Hello_" << i; std::string const &x = ss.str(); // Note: CHAR fields are always padded with whitespaces ss << " "; assert(ss.str() == s1[j] && x == s2[j]); ++i; } } assert(i == rowsToTest); } sql << "drop table test6"; std::cout << "test 6 passed" << std::endl; } // blob test void test7() { session sql(backEnd, connectString); try { sql << "drop table test7"; } catch (std::runtime_error &) {} // ignore if error sql << "create table test7(id integer, img blob)"; sql.commit(); sql.begin(); { // verify empty blob blob b(sql); indicator ind; sql << "insert into test7(id, img) values(1,?)", use(b); sql << "select img from test7 where id = 1", into(b, ind); assert(ind == i_ok); assert(b.get_len() == 0); sql << "delete from test7"; } { // create a new blob blob b(sql); char str1[] = "Hello"; b.write(0, str1, strlen(str1)); char str2[20]; std::size_t i = b.read(3, str2, 2); str2[i] = '\0'; assert(str2[0] == 'l' && str2[1] == 'o' && str2[2] == '\0'); char str3[] = ", Firebird!"; b.append(str3, strlen(str3)); sql << "insert into test7(id, img) values(1,?)", use(b); } { // read & update blob blob b(sql); sql << "select img from test7 where id = 1", into(b); std::vector text(b.get_len()); b.read(0, &text[0], b.get_len()); assert(strncmp(&text[0], "Hello, Firebird!", b.get_len()) == 0); char str1[] = "FIREBIRD"; b.write(7, str1, strlen(str1)); // after modification blob must be written to database sql << "update test7 set img=? where id=1", use(b); } { // read blob from database, modify and write to another record blob b(sql); sql << "select img from test7 where id = 1", into(b); std::vector text(b.get_len()); b.read(0, &text[0], b.get_len()); char str1[] = "HELLO"; b.write(0, str1, strlen(str1)); b.read(0, &text[0], b.get_len()); assert(strncmp(&text[0], "HELLO, FIREBIRD!", b.get_len()) == 0); b.trim(5); sql << "insert into test7(id, img) values(2,?)", use(b); } { blob b(sql); statement st = (sql.prepare << "select img from test7", into(b)); st.execute(); st.fetch(); std::vector text(b.get_len()); b.read(0, &text[0], b.get_len()); assert(strncmp(&text[0], "Hello, FIREBIRD!", b.get_len()) == 0); st.fetch(); text.resize(b.get_len()); b.read(0, &text[0], b.get_len()); assert(strncmp(&text[0], "HELLO", b.get_len()) == 0); } { // delete blob blob b(sql); indicator ind=i_null; sql << "update test7 set img=? where id = 1", use(b, ind); sql << "select img from test7 where id = 2", into(b, ind); assert(ind==i_ok); sql << "select img from test7 where id = 1", into(b, ind); assert(ind==i_null); } sql << "drop table test7"; std::cout << "test 7 passed" << std::endl; } // named parameters void test8() { session sql(backEnd, connectString); try { sql << "drop table test8"; } catch (std::runtime_error &) {} // ignore if error sql << "create table test8(id1 integer, id2 integer)"; sql.commit(); sql.begin(); int j = 13, k = 4, i, m; sql << "insert into test8(id1, id2) values(:id1, :id2)", use(k, "id2"), use(j, "id1"); sql << "select id1, id2 from test8", into(i), into(m); assert(i == j && m == k); sql << "delete from test8"; std::vector in1(3), in2(3); in1[0] = 3; in1[1] = 2; in1[2] = 1; in2[0] = 4; in2[1] = 5; in2[2] = 6; { statement st = (sql.prepare << "insert into test8(id1, id2) values(:id1, :id2)", use(k, "id2"), use(j, "id1")); std::size_t s = in1.size(); for (std::size_t x = 0; x < s; ++x) { j = in1[x]; k = in2[x]; st.execute(); } } { statement st = ( sql.prepare << "select id1, id2 from test8", into(i), into(m)); st.execute(); std::size_t x(0); while (st.fetch()) { assert(i = in1[x] && m == in2[x]); ++x; } } sql << "delete from test8"; // test vectors sql << "insert into test8(id1, id2) values(:id1, :id2)", use(in1, "id1"), use(in2, "id2"); std::vector out1(3), out2(3); sql << "select id1, id2 from test8", into(out1), into(out2); std::size_t s = out1.size(); assert(s == 3); for (std::size_t x = 0; x(0) == 1); assert(r.get(1) == "Hello"); assert(r.get(2) == d); // get values by name assert(r.get("ID") == 1); assert(r.get("MSG") == "Hello"); assert(r.get("NTEST") == d); st.fetch(); assert(r.get(0) == 2); assert(r.get("MSG") == "Firebird"); assert(r.get_indicator(2) == i_null); // verify default values assert(r.get("NTEST", 2) == 2); bool caught = false; try { double d1 = r.get("NTEST"); std::cout << d1 << std::endl; // just for compiler } catch (soci_error&) { caught = true; } assert(caught); // verify exception thrown on invalid get<> caught = false; try { r.get(0); } catch (std::bad_cast const &) { caught = true; } assert(caught); sql << "drop table test9"; std::cout << "test 9 passed" << std::endl; } // stored procedures void test10() { session sql(backEnd, connectString); try { sql << "drop procedure sp_test10"; } catch (std::runtime_error &) {} // ignore if error try { sql << "drop procedure sp_test10a"; } catch (std::runtime_error &) {} // ignore if error try { sql << "drop table test10"; } catch (std::runtime_error &) {} // ignore if error sql << "create table test10(id integer, id2 integer)"; sql << "create procedure sp_test10\n" << "returns (rid integer, rid2 integer)\n" << "as begin\n" << "for select id, id2 from test10 into rid, rid2 do begin\n" << "suspend;\n" << "end\n" << "end;\n"; sql << "create procedure sp_test10a (pid integer, pid2 integer)\n" << "as begin\n" << "insert into test10(id, id2) values (:pid, :pid2);\n" << "end;\n"; sql.commit(); sql.begin(); row r; int p1 = 3, p2 = 4; // calling procedures that do not return values requires // 'execute procedure ...' statement sql << "execute procedure sp_test10a ?, ?", use(p1), use(p2); // calling procedures that return values requires // 'select ... from ...' statement sql << "select * from sp_test10", into(r); assert(r.get(0) == p1 && r.get(1) == p2); sql << "delete from test10"; p1 = 5; p2 = 6; { procedure proc = ( sql.prepare << "sp_test10a :p1, :p2", use(p2, "p2"), use(p1, "p1")); proc.execute(1); } { row rw; procedure proc = (sql.prepare << "sp_test10", into(rw)); proc.execute(1); assert(rw.get(0) == p1 && rw.get(1) == p2); } sql << "delete from test10"; // test vectors std::vector in1(3), in2(3); in1[0] = 3; in1[1] = 2; in1[2] = 1; in2[0] = 4; in2[1] = 5; in2[2] = 6; { procedure proc = ( sql.prepare << "sp_test10a :p1, :p2", use(in2, "p2"), use(in1, "p1")); proc.execute(1); } { row rw; procedure proc = (sql.prepare << "sp_test10", into(rw)); proc.execute(1); assert(rw.get(0) == in1[0] && rw.get(1) == in2[0]); proc.fetch(); assert(rw.get(0) == in1[1] && rw.get(1) == in2[1]); proc.fetch(); assert(rw.get(0) == in1[2] && rw.get(1) == in2[2]); assert(proc.fetch() == false); } { std::vector out1(3), out2(3); procedure proc = (sql.prepare << "sp_test10", into(out1), into(out2)); proc.execute(1); std::size_t s = out1.size(); assert(s == 3); for (std::size_t x = 0; x < s; ++x) { assert(out1[x] == in1[x] && out2[x] == in2[x]); } } sql.rollback(); sql.begin(); sql << "drop procedure sp_test10"; sql << "drop procedure sp_test10a"; sql << "drop table test10"; std::cout << "test 10 passed" << std::endl; } // direct access to Firebird using handles exposed by // soci::FirebirdStatmentBackend namespace soci { enum eRowCountType { eRowsSelected = isc_info_req_select_count, eRowsInserted = isc_info_req_insert_count, eRowsUpdated = isc_info_req_update_count, eRowsDeleted = isc_info_req_delete_count }; // Returns number of rows afected by last statement // or -1 if there is no such counter available. long getRowCount(soci::statement & statement, eRowCountType type) { ISC_STATUS stat[20]; char cnt_req[2], cnt_info[128]; cnt_req[0]=isc_info_sql_records; cnt_req[1]=isc_info_end; firebird_statement_backend* statementBackEnd = static_cast(statement.get_backend()); // Note: This is very poorly documented function. // It can extract number of rows returned by select statement, // but it appears that this is only number of rows prefetched by // client library, not total number of selected rows. if (isc_dsql_sql_info(stat, &statementBackEnd->stmtp_, sizeof(cnt_req), cnt_req, sizeof(cnt_info), cnt_info)) { soci::details::firebird::throw_iscerror(stat); } long count = -1; char type_ = static_cast(type); for (char *ptr = cnt_info + 3; *ptr != isc_info_end;) { char count_type = *ptr++; int m = isc_vax_integer(ptr, 2); ptr += 2; count = isc_vax_integer(ptr, m); if (count_type == type_) { // this is requested number break; } ptr += m; } return count; } } // namespace soci void test11() { session sql(backEnd, connectString); try { sql << "drop table test11"; } catch (std::runtime_error &) {} // ignore if error sql << "create table test11(id integer)"; sql.commit(); sql.begin(); { std::vector in(3); in[0] = 3; in[1] = 2; in[2] = 1; statement st = (sql.prepare << "insert into test11(id) values(?)", use(in)); st.execute(1); // Note: Firebird backend inserts every row with separate insert // statement to achieve the effect of inserting vectors of values. // Since getRowCount() returns number of rows affected by the *last* // statement, it will return 1 here. assert(getRowCount(st, eRowsInserted) == 1); } { int i = 5; statement st = (sql.prepare << "update test11 set id = ? where id<3", use(i)); st.execute(1); assert(getRowCount(st, eRowsUpdated) == 2); // verify that no rows were deleted assert(getRowCount(st, eRowsDeleted) == 0); } { std::vector out(3); statement st = (sql.prepare << "select id from test11", into(out)); st.execute(1); assert(getRowCount(st, eRowsSelected) == 3); } { statement st = (sql.prepare << "delete from test11 where id=10"); st.execute(1); assert(getRowCount(st, eRowsDeleted) == 0); } { statement st = (sql.prepare << "delete from test11"); st.execute(1); assert(getRowCount(st, eRowsDeleted) == 3); } sql << "drop table test11"; std::cout << "test 11 passed" << std::endl; } void test12() { session sql(backEnd, connectString); try { sql << "drop table test12"; } catch (std::runtime_error &) {} // ignore if error sql << "create table test12(a decimal(10,3), b timestamp, c date, d time)"; sql.commit(); sql.begin(); // Check if passing input parameters as strings works // for different column types. { std::string a = "-3.14150", b = "2013-02-28 23:36:01", c = "2013-02-28", d = "23:36:01"; statement st = (sql.prepare << "insert into test12(a, b, c, d) values (?, ?, ?, ?)", use(a), use(b), use(c), use(d)); st.execute(1); assert(getRowCount(st, eRowsInserted) == 1); } { double a; std::tm b, c, d; sql << "select a, b, c, d from test12", into(a), into(b), into(c), into(d); assert(std::fabs(a - (-3.141)) < 0.000001); assert(b.tm_year + 1900 == 2013 && b.tm_mon + 1 == 2 && b.tm_mday == 28); assert(b.tm_hour == 23 && b.tm_min == 36 && b.tm_sec == 1); assert(c.tm_year + 1900 == 2013 && c.tm_mon + 1 == 2 && c.tm_mday == 28); assert(c.tm_hour == 0 && c.tm_min == 0 && c.tm_sec == 0); assert(d.tm_hour == 23 && d.tm_min == 36 && d.tm_sec == 1); } sql << "drop table test12"; std::cout << "test 12 passed" << std::endl; } // Dynamic binding to row objects: decimals_as_strings void test13() { using namespace soci::details::firebird; int a = -12345678; assert(format_decimal(&a, 1) == "-123456780"); assert(format_decimal(&a, 0) == "-12345678"); assert(format_decimal(&a, -3) == "-12345.678"); assert(format_decimal(&a, -8) == "-0.12345678"); assert(format_decimal(&a, -9) == "-0.012345678"); a = 12345678; assert(format_decimal(&a, 1) == "123456780"); assert(format_decimal(&a, 0) == "12345678"); assert(format_decimal(&a, -3) == "12345.678"); assert(format_decimal(&a, -8) == "0.12345678"); assert(format_decimal(&a, -9) == "0.012345678"); session sql(backEnd, connectString + " decimals_as_strings=1"); try { sql << "drop table test13"; } catch (std::runtime_error &) {} // ignore if error sql << "create table test13(ntest1 decimal(10,2), " << "ntest2 decimal(4,4), ntest3 decimal(3,1))"; sql.commit(); sql.begin(); { row r; sql << "select * from test13", into(r); assert(sql.got_data() == false); } std::string d_str0("+03.140"), d_str1("3.14"), d_str2("3.1400"), d_str3("3.1"); indicator ind(i_ok); { statement st((sql.prepare << "insert into test13(ntest1, ntest2, ntest3) " "values(:ntest1, :ntest2, :ntest3)", use(d_str0, ind, "ntest1"), use(d_str0, "ntest2"), use(d_str0, "ntest3"))); st.execute(1); ind = i_null; st.execute(1); } row r; statement st = (sql.prepare << "select * from test13", into(r)); st.execute(1); assert(r.size() == 3); // get properties by position assert(r.get_properties(0).get_name() == "NTEST1"); assert(r.get_properties(0).get_data_type() == dt_string); assert(r.get_properties(1).get_name() == "NTEST2"); assert(r.get_properties(1).get_data_type() == dt_string); assert(r.get_properties(2).get_name() == "NTEST3"); assert(r.get_properties(2).get_data_type() == dt_string); // get properties by name assert(r.get_properties("NTEST1").get_name() == "NTEST1"); assert(r.get_properties("NTEST1").get_data_type() == dt_string); assert(r.get_properties("NTEST2").get_name() == "NTEST2"); assert(r.get_properties("NTEST2").get_data_type() == dt_string); assert(r.get_properties("NTEST3").get_name() == "NTEST3"); assert(r.get_properties("NTEST3").get_data_type() == dt_string); // get values by position assert(r.get(0) == d_str1); assert(r.get(1) == d_str2); assert(r.get(2) == d_str3); // get values by name assert(r.get("NTEST1") == d_str1); assert(r.get("NTEST2") == d_str2); assert(r.get("NTEST3") == d_str3); st.fetch(); assert(r.get_indicator(0) == i_null); assert(r.get_indicator(1) == i_ok); assert(r.get_indicator(2) == i_ok); sql << "drop table test13"; std::cout << "test 13 passed" << std::endl; } // // Support for soci Common Tests // struct TableCreator1 : public tests::table_creator_base { TableCreator1(session & sql) : tests::table_creator_base(sql) { sql << "create table soci_test(id integer, val integer, c char, " "str varchar(20), sh smallint, ul bigint, d double precision, " "tm timestamp, i1 integer, i2 integer, i3 integer, name varchar(20))"; sql.commit(); sql.begin(); } }; struct TableCreator2 : public tests::table_creator_base { TableCreator2(session & sql) : tests::table_creator_base(sql) { sql << "create table soci_test(num_float float, num_int integer, " "name varchar(20), sometime timestamp, chr char)"; sql.commit(); sql.begin(); } }; struct TableCreator3 : public tests::table_creator_base { TableCreator3(session & sql) : tests::table_creator_base(sql) { sql << "create table soci_test(name varchar(100) not null, " "phone varchar(15))"; sql.commit(); sql.begin(); } }; struct TableCreator4 : public tests::table_creator_base { TableCreator4(session & sql) : tests::table_creator_base(sql) { sql << "create table soci_test(val integer)"; sql.commit(); sql.begin(); } }; class test_context : public tests::test_context_base { public: test_context(backend_factory const &backEnd, std::string const &connectString) : test_context_base(backEnd, connectString) {} tests::table_creator_base* table_creator_1(session& s) const { return new TableCreator1(s); } tests::table_creator_base* table_creator_2(session& s) const { return new TableCreator2(s); } tests::table_creator_base* table_creator_3(session& s) const { return new TableCreator3(s); } tests::table_creator_base* table_creator_4(session& s) const { return new TableCreator4(s); } std::string to_date_time(std::string const &datdt_string) const { return "'" + datdt_string + "'"; } }; int main(int argc, char** argv) { #ifdef _MSC_VER // Redirect errors, unrecoverable problems, and assert() failures to STDERR, // instead of debug message window. // This hack is required to run asser()-driven tests by Buildbot. // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); #endif //_MSC_VER if (argc == 2) { connectString = argv[1]; } else { std::cout << "usage: " << argv[0] << " connectstring\n" << "example: " << argv[0] << " \"service=/usr/local/firebird/db/test.fdb user=SYSDBA password=masterkey\"\n"; return EXIT_FAILURE; } try { test_context tc(backEnd, connectString); tests::common_tests tests(tc); tests.run(); std::cout << "\nSOCI Firebird Tests:\n\n"; test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; } catch (std::exception const & e) { std::cout << e.what() << '\n'; } return EXIT_FAILURE; } soci-3.2.3/backends/firebird/test/Makefile.basic0000644000000000000000000000130412511361676020217 0ustar rootroot# The following variable is specific to this backend and its correct # values might depend on your environment - feel free to set it accordingly. FIREBIRDINCLUDEDIR = -I/usr/local/firebird/include FIREBIRDLIBDIR = -L/usr/local/firebird/lib FIREBIRDLIBS = -lfbclient -lpthread # The rest of the Makefile is indepentent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long INCLUDEDIRS = -I.. -I../../../core ${FIREBIRDINCLUDEDIR} LIBDIRS = -L.. -L../../../core ${FIREBIRDLIBDIR} LIBS = -lsoci_core -lsoci_firebird -ldl ${FIREBIRDLIBS} test-firebird : test-firebird.cpp ${COMPILER} -o $@ $? ${CXXFLAGS} ${INCLUDEDIRS} ${LIBDIRS} ${LIBS} clean : rm -f *.o test-firebird soci-3.2.3/backends/firebird/test/CMakeLists.txt0000644000000000000000000000077112511361676020246 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2013 Viacheslav Naydenov # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend_test( BACKEND Firebird SOURCE test-firebird.cpp CONNSTR "dummy") soci-3.2.3/backends/firebird/common.cpp0000644000000000000000000001307612511361676016525 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "common.h" #include #include // FireBird #include #include #include #include #include #include namespace soci { namespace details { namespace firebird { char * allocBuffer(XSQLVAR* var) { std::size_t size; int type = var->sqltype & ~1; if (type == SQL_VARYING) { size = var->sqllen + sizeof(short); } else if (type == SQL_TIMESTAMP || type == SQL_TYPE_TIME || type == SQL_TYPE_DATE) { size = sizeof(std::tm); } else { size = var->sqllen; } return new char[size]; } void tmEncode(short type, std::tm * src, void * dst) { switch (type & ~1) { // In Interbase v6 DATE represents a date-only data type, // in InterBase v5 DATE represents a date+time data type. case SQL_TIMESTAMP: isc_encode_timestamp(src, static_cast(dst)); break; case SQL_TYPE_TIME: isc_encode_sql_time(src, static_cast(dst)); break; case SQL_TYPE_DATE: isc_encode_sql_date(src, static_cast(dst)); break; default: std::ostringstream msg; msg << "Unexpected type of date/time field (" << type << ")"; throw soci_error(msg.str()); } } void tmDecode(short type, void * src, std::tm * dst) { switch (type & ~1) { case SQL_TIMESTAMP: isc_decode_timestamp(static_cast(src), dst); break; case SQL_TYPE_TIME: isc_decode_sql_time(static_cast(src), dst); break; case SQL_TYPE_DATE: isc_decode_sql_date(static_cast(src), dst); break; default: std::ostringstream msg; msg << "Unexpected type of date/time field (" << type << ")"; throw soci_error(msg.str()); } } void setTextParam(char const * s, std::size_t size, char * buf_, XSQLVAR * var) { //std::cerr << "setTextParam: var->sqltype=" << var->sqltype << std::endl; short sz = 0; if (size < static_cast(var->sqllen)) { sz = static_cast(size); } else { sz = var->sqllen; } if ((var->sqltype & ~1) == SQL_VARYING) { std::memcpy(buf_, &sz, sizeof(short)); std::memcpy(buf_ + sizeof(short), s, sz); } else if ((var->sqltype & ~1) == SQL_TEXT) { std::memcpy(buf_, s, sz); if (sz < var->sqllen) { std::memset(buf_+sz, ' ', var->sqllen - sz); } } else if ((var->sqltype & ~1) == SQL_SHORT) { parse_decimal(buf_, var, s); } else if ((var->sqltype & ~1) == SQL_LONG) { parse_decimal(buf_, var, s); } else if ((var->sqltype & ~1) == SQL_INT64) { parse_decimal(buf_, var, s); } else if ((var->sqltype & ~1) == SQL_TIMESTAMP || (var->sqltype & ~1) == SQL_TYPE_DATE) { unsigned short year, month, day, hour, min, sec; if (std::sscanf(s, "%hu-%hu-%hu %hu:%hu:%hu", &year, &month, &day, &hour, &min, &sec) != 6) { if (std::sscanf(s, "%hu-%hu-%huT%hu:%hu:%hu", &year, &month, &day, &hour, &min, &sec) != 6) { hour = min = sec = 0; if (std::sscanf(s, "%hu-%hu-%hu", &year, &month, &day) != 3) { throw soci_error("Could not parse timestamp value."); } } } std::tm t; std::memset(&t, 0, sizeof(t)); t.tm_year = year - 1900; t.tm_mon = month - 1; t.tm_mday = day; t.tm_hour = hour; t.tm_min = min; t.tm_sec = sec; std::memcpy(buf_, &t, sizeof(t)); tmEncode(var->sqltype, &t, buf_); } else if ((var->sqltype & ~1) == SQL_TYPE_TIME) { unsigned short hour, min, sec; if (std::sscanf(s, "%hu:%hu:%hu", &hour, &min, &sec) != 3) { throw soci_error("Could not parse timestamp value."); } std::tm t; std::memset(&t, 0, sizeof(t)); t.tm_hour = hour; t.tm_min = min; t.tm_sec = sec; std::memcpy(buf_, &t, sizeof(t)); tmEncode(var->sqltype, &t, buf_); } else { throw soci_error("Unexpected string type."); } } std::string getTextParam(XSQLVAR const *var) { //std::cerr << "getTextParam: var->sqltype=" << var->sqltype << std::endl; short size; std::size_t offset = 0; if ((var->sqltype & ~1) == SQL_VARYING) { size = *reinterpret_cast(var->sqldata); offset = sizeof(short); } else if ((var->sqltype & ~1) == SQL_TEXT) { size = var->sqllen; } else if ((var->sqltype & ~1) == SQL_SHORT) { return format_decimal(var->sqldata, var->sqlscale); } else if ((var->sqltype & ~1) == SQL_LONG) { return format_decimal(var->sqldata, var->sqlscale); } else if ((var->sqltype & ~1) == SQL_INT64) { return format_decimal(var->sqldata, var->sqlscale); } else throw soci_error("Unexpected string type"); return std::string(var->sqldata + offset, size); } } // namespace firebird } // namespace details } // namespace soci soci-3.2.3/backends/firebird/vector-into-type.cpp0000644000000000000000000001173412511361676020464 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_FIREBIRD_SOURCE #include "soci-firebird.h" #include "common.h" using namespace soci; using namespace soci::details; using namespace soci::details::firebird; void firebird_vector_into_type_backend::define_by_pos( int & position, void * data, exchange_type type) { position_ = position-1; data_ = data; type_ = type; ++position; statement_.intoType_ = eVector; statement_.intos_.push_back(static_cast(this)); XSQLVAR *var = statement_.sqldap_->sqlvar+position_; buf_ = allocBuffer(var); var->sqldata = buf_; var->sqlind = &indISCHolder_; } void firebird_vector_into_type_backend::pre_fetch() { // Nothing to do here. } namespace // anonymous { template void setIntoVector(void *p, std::size_t indx, T const &val) { std::vector *dest = static_cast *>(p); std::vector &v = *dest; v[indx] = val; } } // namespace anonymous // this will exchange data with vector user buffers void firebird_vector_into_type_backend::exchangeData(std::size_t row) { XSQLVAR *var = statement_.sqldap_->sqlvar+position_; switch (type_) { // simple cases case x_char: setIntoVector(data_, row, getTextParam(var)[0]); break; case x_short: { short tmp = from_isc(var); setIntoVector(data_, row, tmp); } break; case x_integer: { int tmp = from_isc(var); setIntoVector(data_, row, tmp); } break; case x_long_long: { long long tmp = from_isc(var); setIntoVector(data_, row, tmp); } break; case x_double: { double tmp = from_isc(var); setIntoVector(data_, row, tmp); } break; // cases that require adjustments and buffer management case x_stdstring: setIntoVector(data_, row, getTextParam(var)); break; case x_stdtm: { std::tm data; tmDecode(var->sqltype, buf_, &data); setIntoVector(data_, row, data); } break; default: throw soci_error("Into vector element used with non-supported type."); } // switch } void firebird_vector_into_type_backend::post_fetch( bool gotData, indicator * ind) { // Here we have to set indicators only. Data was exchanged with user // buffers during fetch() if (gotData) { std::size_t rows = statement_.rowsFetched_; for (std::size_t i = 0; i (data_, sz); break; case x_short: resizeVector (data_, sz); break; case x_integer: resizeVector (data_, sz); break; case x_long_long: resizeVector (data_, sz); break; case x_double: resizeVector (data_, sz); break; case x_stdstring: resizeVector (data_, sz); break; case x_stdtm: resizeVector (data_, sz); break; default: throw soci_error("Into vector element used with non-supported type."); } } std::size_t firebird_vector_into_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type_) { // simple cases case x_char: sz = getVectorSize (data_); break; case x_short: sz = getVectorSize (data_); break; case x_integer: sz = getVectorSize (data_); break; case x_long_long: sz = getVectorSize (data_); break; case x_double: sz = getVectorSize (data_); break; case x_stdstring: sz = getVectorSize (data_); break; case x_stdtm: sz = getVectorSize (data_); break; default: throw soci_error("Into vector element used with non-supported type."); } return sz; } void firebird_vector_into_type_backend::clean_up() { if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } std::vector::iterator it = std::find(statement_.intos_.begin(), statement_.intos_.end(), this); if (it != statement_.intos_.end()) statement_.intos_.erase(it); } soci-3.2.3/backends/firebird/CMakeLists.txt0000644000000000000000000000120512511362240017244 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2013 Viacheslav Naydenov # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend(Firebird DEPENDS Firebird HEADERS soci-firebird.h common.h DESCRIPTION "SOCI backend for Firebird database engine" AUTHORS "Rafał Bobrowski" MAINTAINERS "Viacheslav Naydenov") add_subdirectory(test) soci-3.2.3/backends/firebird/soci-firebird.h0000644000000000000000000002170412511362240017404 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // #ifndef SOCI_FIREBIRD_H_INCLUDED #define SOCI_FIREBIRD_H_INCLUDED #ifdef _WIN32 # ifdef SOCI_DLL # ifdef SOCI_FIREBIRD_SOURCE # define SOCI_FIREBIRD_DECL __declspec(dllexport) # else # define SOCI_FIREBIRD_DECL __declspec(dllimport) # endif // SOCI_DLL # endif // SOCI_FIREBIRD_SOURCE #endif // _WIN32 // // If SOCI_FIREBIRD_DECL isn't defined yet define it now #ifndef SOCI_FIREBIRD_DECL # define SOCI_FIREBIRD_DECL #endif #ifdef _WIN32 #include // To understand and/or/not on MSVC9 #endif #include #include // FireBird #include #include #include namespace soci { std::size_t const stat_size = 20; // size of buffer for error messages. All examples use this value. // Anyone knows, where it is stated that 512 bytes is enough ? std::size_t const SOCI_FIREBIRD_ERRMSG = 512; class SOCI_FIREBIRD_DECL firebird_soci_error : public soci_error { public: firebird_soci_error(std::string const & msg, ISC_STATUS const * status = 0); ~firebird_soci_error() throw() {}; std::vector status_; }; enum BuffersType { eStandard, eVector }; struct firebird_statement_backend; struct firebird_standard_into_type_backend : details::standard_into_type_backend { firebird_standard_into_type_backend(firebird_statement_backend &st) : statement_(st), buf_(NULL) {} virtual void define_by_pos(int &position, void *data, details::exchange_type type); virtual void pre_fetch(); virtual void post_fetch(bool gotData, bool calledFromFetch, indicator *ind); virtual void clean_up(); firebird_statement_backend &statement_; virtual void exchangeData(); void *data_; details::exchange_type type_; int position_; char *buf_; short indISCHolder_; }; struct firebird_vector_into_type_backend : details::vector_into_type_backend { firebird_vector_into_type_backend(firebird_statement_backend &st) : statement_(st), buf_(NULL) {} virtual void define_by_pos(int &position, void *data, details::exchange_type type); virtual void pre_fetch(); virtual void post_fetch(bool gotData, indicator *ind); virtual void resize(std::size_t sz); virtual std::size_t size(); virtual void clean_up(); firebird_statement_backend &statement_; virtual void exchangeData(std::size_t row); void *data_; details::exchange_type type_; int position_; char *buf_; short indISCHolder_; }; struct firebird_standard_use_type_backend : details::standard_use_type_backend { firebird_standard_use_type_backend(firebird_statement_backend &st) : statement_(st), buf_(NULL), indISCHolder_(0) {} virtual void bind_by_pos(int &position, void *data, details::exchange_type type, bool readOnly); virtual void bind_by_name(std::string const &name, void *data, details::exchange_type type, bool readOnly); virtual void pre_use(indicator const *ind); virtual void post_use(bool gotData, indicator *ind); virtual void clean_up(); firebird_statement_backend &statement_; virtual void exchangeData(); void *data_; details::exchange_type type_; int position_; char *buf_; short indISCHolder_; }; struct firebird_vector_use_type_backend : details::vector_use_type_backend { firebird_vector_use_type_backend(firebird_statement_backend &st) : statement_(st), inds_(NULL), buf_(NULL), indISCHolder_(0) {} virtual void bind_by_pos(int &position, void *data, details::exchange_type type); virtual void bind_by_name(std::string const &name, void *data, details::exchange_type type); virtual void pre_use(indicator const *ind); virtual std::size_t size(); virtual void clean_up(); firebird_statement_backend &statement_; virtual void exchangeData(std::size_t row); void *data_; details::exchange_type type_; int position_; indicator const *inds_; char *buf_; short indISCHolder_; }; struct firebird_session_backend; struct firebird_statement_backend : details::statement_backend { firebird_statement_backend(firebird_session_backend &session); virtual void alloc(); virtual void clean_up(); virtual void prepare(std::string const &query, details::statement_type eType); virtual exec_fetch_result execute(int number); virtual exec_fetch_result fetch(int number); virtual long long get_affected_rows(); virtual int get_number_of_rows(); virtual std::string rewrite_for_procedure_call(std::string const &query); virtual int prepare_for_describe(); virtual void describe_column(int colNum, data_type &dtype, std::string &columnName); virtual firebird_standard_into_type_backend * make_into_type_backend(); virtual firebird_standard_use_type_backend * make_use_type_backend(); virtual firebird_vector_into_type_backend * make_vector_into_type_backend(); virtual firebird_vector_use_type_backend * make_vector_use_type_backend(); firebird_session_backend &session_; isc_stmt_handle stmtp_; XSQLDA * sqldap_; XSQLDA * sqlda2p_; bool boundByName_; bool boundByPos_; friend struct firebird_vector_into_type_backend; friend struct firebird_standard_into_type_backend; friend struct firebird_vector_use_type_backend; friend struct firebird_standard_use_type_backend; protected: int rowsFetched_; bool endOfRowSet_; long long rowsAffectedBulk_; // number of rows affected by the last bulk operation virtual void exchangeData(bool gotData, int row); virtual void prepareSQLDA(XSQLDA ** sqldap, int size = 10); virtual void rewriteQuery(std::string const & query, std::vector & buffer); virtual void rewriteParameters(std::string const & src, std::vector & dst); BuffersType intoType_; BuffersType useType_; std::vector > inds_; std::vector intos_; std::vector uses_; // named parameters std::map names_; bool procedure_; }; struct firebird_rowid_backend : details::rowid_backend { firebird_rowid_backend(firebird_session_backend &session); ~firebird_rowid_backend(); }; struct firebird_blob_backend : details::blob_backend { firebird_blob_backend(firebird_session_backend &session); ~firebird_blob_backend(); virtual std::size_t get_len(); virtual std::size_t read(std::size_t offset, char *buf, std::size_t toRead); virtual std::size_t write(std::size_t offset, char const *buf, std::size_t toWrite); virtual std::size_t append(char const *buf, std::size_t toWrite); virtual void trim(std::size_t newLen); firebird_session_backend &session_; virtual void save(); virtual void assign(ISC_QUAD const & bid) { cleanUp(); bid_ = bid; from_db_ = true; } // BLOB id from in database ISC_QUAD bid_; // BLOB id was fetched from database (true) // or this is new BLOB bool from_db_; // BLOB handle isc_blob_handle bhp_; protected: virtual void open(); virtual long getBLOBInfo(); virtual void load(); virtual void writeBuffer(std::size_t offset, char const * buf, std::size_t toWrite); virtual void cleanUp(); // buffer for BLOB data std::vector data_; bool loaded_; long max_seg_size_; }; struct firebird_session_backend : details::session_backend { firebird_session_backend(connection_parameters const & parameters); ~firebird_session_backend(); virtual void begin(); virtual void commit(); virtual void rollback(); virtual bool get_next_sequence_value(session & s, std::string const & sequence, long & value); virtual std::string get_backend_name() const { return "firebird"; } void cleanUp(); virtual firebird_statement_backend * make_statement_backend(); virtual firebird_rowid_backend * make_rowid_backend(); virtual firebird_blob_backend * make_blob_backend(); virtual void setDPBOption(int const option, std::string const & value); bool get_option_decimals_as_strings() { return decimals_as_strings_; } isc_db_handle dbhp_; isc_tr_handle trhp_; std::string dpb_; bool decimals_as_strings_; }; struct firebird_backend_factory : backend_factory { firebird_backend_factory() {} virtual firebird_session_backend * make_session( connection_parameters const & parameters) const; }; extern SOCI_FIREBIRD_DECL firebird_backend_factory const firebird; extern "C" { // for dynamic backend loading SOCI_FIREBIRD_DECL backend_factory const * factory_firebird(); SOCI_FIREBIRD_DECL void register_factory_firebird(); } // extern "C" } // namespace soci #endif // SOCI_FIREBIRD_H_INCLUDED soci-3.2.3/backends/sqlite3/0000755000000000000000000000000012511401144014301 5ustar rootrootsoci-3.2.3/backends/sqlite3/common.h0000644000000000000000000000450112511361676015761 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_SQLITE3_COMMON_H_INCLUDED #define SOCI_SQLITE3_COMMON_H_INCLUDED #include #include #include #include #include #include #include namespace soci { namespace details { namespace sqlite3 { // helper function for parsing datetime values void parse_std_tm(char const *buf, std::tm &t); // helper for vector operations template std::size_t get_vector_size(void *p) { std::vector *v = static_cast *>(p); return v->size(); } template void resize_vector(void *p, std::size_t sz) { std::vector *v = static_cast *>(p); v->resize(sz); } // helper function for parsing integers template T string_to_integer(char const * buf) { long long t(0); int n(0); int const converted = std::sscanf(buf, "%" LL_FMT_FLAGS "d%n", &t, &n); if (converted == 1 && static_cast(n) == std::strlen(buf)) { // successfully converted to long long // and no other characters were found in the buffer const T max = (std::numeric_limits::max)(); const T min = (std::numeric_limits::min)(); if (t <= static_cast(max) && t >= static_cast(min)) { return static_cast(t); } } throw soci_error("Cannot convert data."); } // helper function for parsing unsigned integers template T string_to_unsigned_integer(char const * buf) { unsigned long long t(0); int n(0); int const converted = std::sscanf(buf, "%" LL_FMT_FLAGS "u%n", &t, &n); if (converted == 1 && static_cast(n) == std::strlen(buf)) { // successfully converted to unsigned long long // and no other characters were found in the buffer T const max = (std::numeric_limits::max)(); if (t <= static_cast(max)) { return static_cast(t); } } throw soci_error("Cannot convert data."); } }}} // namespace soci::details::sqlite3 #endif // SOCI_SQLITE3_COMMON_H_INCLUDED soci-3.2.3/backends/sqlite3/soci-sqlite3.h0000644000000000000000000001672312511401144017002 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_SQLITE3_H_INCLUDED #define SOCI_SQLITE3_H_INCLUDED #ifdef _WIN32 # ifdef SOCI_DLL # ifdef SOCI_SQLITE3_SOURCE # define SOCI_SQLITE3_DECL __declspec(dllexport) # else # define SOCI_SQLITE3_DECL __declspec(dllimport) # endif // SOCI_SQLITE3_SOURCE # endif // SOCI_DLL #endif // _WIN32 // // If SOCI_SQLITE3_DECL isn't defined yet define it now #ifndef SOCI_SQLITE3_DECL # define SOCI_SQLITE3_DECL #endif #include #include #include "soci-backend.h" // Disable flood of nonsense warnings generated for SQLite #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4510 4512 4610) #endif namespace sqlite_api { #if SQLITE_VERSION_NUMBER < 3003010 // The sqlite3_destructor_type typedef introduced in 3.3.10 // http://www.sqlite.org/cvstrac/tktview?tn=2191 typedef void (*sqlite3_destructor_type)(void*); #endif #include } // namespace sqlite_api #undef SQLITE_STATIC #define SQLITE_STATIC ((sqlite_api::sqlite3_destructor_type)0) #ifdef _MSC_VER #pragma warning(pop) #endif namespace soci { class sqlite3_soci_error : public soci_error { public: sqlite3_soci_error(std::string const & msg, int result); int result() const; private: int result_; }; struct sqlite3_statement_backend; struct sqlite3_standard_into_type_backend : details::standard_into_type_backend { sqlite3_standard_into_type_backend(sqlite3_statement_backend &st) : statement_(st) {} virtual void define_by_pos(int &position, void *data, details::exchange_type type); virtual void pre_fetch(); virtual void post_fetch(bool gotData, bool calledFromFetch, indicator *ind); virtual void clean_up(); sqlite3_statement_backend &statement_; void *data_; details::exchange_type type_; int position_; }; struct sqlite3_vector_into_type_backend : details::vector_into_type_backend { sqlite3_vector_into_type_backend(sqlite3_statement_backend &st) : statement_(st) {} void define_by_pos(int& position, void* data, details::exchange_type type); void pre_fetch(); void post_fetch(bool gotData, indicator* ind); void resize(std::size_t sz); std::size_t size(); virtual void clean_up(); sqlite3_statement_backend& statement_; void *data_; details::exchange_type type_; int position_; }; struct sqlite3_standard_use_type_backend : details::standard_use_type_backend { sqlite3_standard_use_type_backend(sqlite3_statement_backend &st) : statement_(st), buf_(0) {} virtual void bind_by_pos(int &position, void *data, details::exchange_type type, bool readOnly); virtual void bind_by_name(std::string const &name, void *data, details::exchange_type type, bool readOnly); virtual void pre_use(indicator const *ind); virtual void post_use(bool gotData, indicator *ind); virtual void clean_up(); sqlite3_statement_backend &statement_; void *data_; details::exchange_type type_; int position_; std::string name_; char *buf_; }; struct sqlite3_vector_use_type_backend : details::vector_use_type_backend { sqlite3_vector_use_type_backend(sqlite3_statement_backend &st) : statement_(st) {} virtual void bind_by_pos(int &position, void *data, details::exchange_type type); virtual void bind_by_name(std::string const &name, void *data, details::exchange_type type); virtual void pre_use(indicator const *ind); virtual std::size_t size(); virtual void clean_up(); sqlite3_statement_backend &statement_; void *data_; details::exchange_type type_; int position_; std::string name_; }; struct sqlite3_column { std::string data_; bool isNull_; char * blobBuf_; std::size_t blobSize_; }; typedef std::vector sqlite3_row; typedef std::vector sqlite3_recordset; struct sqlite3_session_backend; struct sqlite3_statement_backend : details::statement_backend { sqlite3_statement_backend(sqlite3_session_backend &session); virtual void alloc(); virtual void clean_up(); virtual void prepare(std::string const &query, details::statement_type eType); void reset_if_needed(); virtual exec_fetch_result execute(int number); virtual exec_fetch_result fetch(int number); virtual long long get_affected_rows(); virtual int get_number_of_rows(); virtual std::string rewrite_for_procedure_call(std::string const &query); virtual int prepare_for_describe(); virtual void describe_column(int colNum, data_type &dtype, std::string &columnName); virtual sqlite3_standard_into_type_backend * make_into_type_backend(); virtual sqlite3_standard_use_type_backend * make_use_type_backend(); virtual sqlite3_vector_into_type_backend * make_vector_into_type_backend(); virtual sqlite3_vector_use_type_backend * make_vector_use_type_backend(); sqlite3_session_backend &session_; sqlite_api::sqlite3_stmt *stmt_; sqlite3_recordset dataCache_; sqlite3_recordset useData_; bool databaseReady_; bool boundByName_; bool boundByPos_; long long rowsAffectedBulk_; // number of rows affected by the last bulk operation private: exec_fetch_result load_rowset(int totalRows); exec_fetch_result load_one(); exec_fetch_result bind_and_execute(int number); }; struct sqlite3_rowid_backend : details::rowid_backend { sqlite3_rowid_backend(sqlite3_session_backend &session); ~sqlite3_rowid_backend(); unsigned long value_; }; struct sqlite3_blob_backend : details::blob_backend { sqlite3_blob_backend(sqlite3_session_backend &session); ~sqlite3_blob_backend(); virtual std::size_t get_len(); virtual std::size_t read(std::size_t offset, char *buf, std::size_t toRead); virtual std::size_t write(std::size_t offset, char const *buf, std::size_t toWrite); virtual std::size_t append(char const *buf, std::size_t toWrite); virtual void trim(std::size_t newLen); sqlite3_session_backend &session_; std::size_t set_data(char const *buf, std::size_t toWrite); private: char *buf_; size_t len_; }; struct sqlite3_session_backend : details::session_backend { sqlite3_session_backend(connection_parameters const & parameters); ~sqlite3_session_backend(); virtual void begin(); virtual void commit(); virtual void rollback(); virtual std::string get_backend_name() const { return "sqlite3"; } void clean_up(); virtual sqlite3_statement_backend * make_statement_backend(); virtual sqlite3_rowid_backend * make_rowid_backend(); virtual sqlite3_blob_backend * make_blob_backend(); sqlite_api::sqlite3 *conn_; }; struct sqlite3_backend_factory : backend_factory { sqlite3_backend_factory() {} virtual sqlite3_session_backend * make_session( connection_parameters const & parameters) const; }; extern SOCI_SQLITE3_DECL sqlite3_backend_factory const sqlite3; extern "C" { // for dynamic backend loading SOCI_SQLITE3_DECL backend_factory const * factory_sqlite3(); SOCI_SQLITE3_DECL void register_factory_sqlite3(); } // extern "C" } // namespace soci #endif // SOCI_SQLITE3_H_INCLUDED soci-3.2.3/backends/sqlite3/blob.cpp0000644000000000000000000000423412511361676015745 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci-sqlite3.h" #include #include using namespace soci; sqlite3_blob_backend::sqlite3_blob_backend(sqlite3_session_backend &session) : session_(session), buf_(0), len_(0) { } sqlite3_blob_backend::~sqlite3_blob_backend() { if (buf_) { delete [] buf_; buf_ = 0; len_ = 0; } } std::size_t sqlite3_blob_backend::get_len() { return len_; } std::size_t sqlite3_blob_backend::read( std::size_t offset, char * buf, std::size_t toRead) { size_t r = toRead; // make sure that we don't try to read // past the end of the data if (r > len_ - offset) { r = len_ - offset; } memcpy(buf, buf_ + offset, r); return r; } std::size_t sqlite3_blob_backend::write( std::size_t offset, char const * buf, std::size_t toWrite) { const char* oldBuf = buf_; std::size_t oldLen = len_; len_ = (std::max)(len_, offset + toWrite); buf_ = new char[len_]; if (oldBuf) { // we need to copy both old and new buffers // it is possible that the new does not // completely cover the old memcpy(buf_, oldBuf, oldLen); delete [] oldBuf; } memcpy(buf_ + offset, buf, toWrite); return len_; } std::size_t sqlite3_blob_backend::append( char const * buf, std::size_t toWrite) { const char* oldBuf = buf_; buf_ = new char[len_ + toWrite]; memcpy(buf_, oldBuf, len_); memcpy(buf_ + len_, buf, toWrite); delete [] oldBuf; len_ += toWrite; return len_; } void sqlite3_blob_backend::trim(std::size_t newLen) { const char* oldBuf = buf_; len_ = newLen; buf_ = new char[len_]; memcpy(buf_, oldBuf, len_); delete [] oldBuf; } std::size_t sqlite3_blob_backend::set_data(char const *buf, std::size_t toWrite) { if (buf_) { delete [] buf_; buf_ = 0; len_ = 0; } return write(0, buf, toWrite); } soci-3.2.3/backends/sqlite3/statement.cpp0000644000000000000000000002615612511401144017023 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci-sqlite3.h" // std #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace sqlite_api; sqlite3_statement_backend::sqlite3_statement_backend( sqlite3_session_backend &session) : session_(session) , stmt_(0) , dataCache_() , useData_(0) , databaseReady_(false) , boundByName_(false) , boundByPos_(false) , rowsAffectedBulk_(-1LL) { } void sqlite3_statement_backend::alloc() { // ... } void sqlite3_statement_backend::clean_up() { rowsAffectedBulk_ = -1LL; if (stmt_) { sqlite3_finalize(stmt_); stmt_ = 0; databaseReady_ = false; } } void sqlite3_statement_backend::prepare(std::string const & query, statement_type /* eType */) { clean_up(); char const* tail = 0; // unused; int const res = sqlite3_prepare_v2(session_.conn_, query.c_str(), static_cast(query.size()), &stmt_, &tail); if (res != SQLITE_OK) { char const* zErrMsg = sqlite3_errmsg(session_.conn_); std::ostringstream ss; ss << "sqlite3_statement_backend::prepare: " << zErrMsg; throw sqlite3_soci_error(ss.str(), res); } databaseReady_ = true; } // sqlite3_reset needs to be called before a prepared statment can // be executed a second time. void sqlite3_statement_backend::reset_if_needed() { if (stmt_ && databaseReady_ == false) { int const res = sqlite3_reset(stmt_); if (SQLITE_OK == res) { databaseReady_ = true; } } } // This is used by bulk operations statement_backend::exec_fetch_result sqlite3_statement_backend::load_rowset(int totalRows) { statement_backend::exec_fetch_result retVal = ef_success; int numCols = -1; int i = 0; if (!databaseReady_) { retVal = ef_no_data; } else { // make the vector big enough to hold the data we need dataCache_.resize(totalRows); for (i = 0; i < totalRows && databaseReady_; ++i) { int const res = sqlite3_step(stmt_); if (SQLITE_DONE == res) { databaseReady_ = false; retVal = ef_no_data; break; } else if (SQLITE_ROW == res) { // only need to set the number of columns once if (-1 == numCols) { numCols = sqlite3_column_count(stmt_); for (sqlite3_recordset::iterator it = dataCache_.begin(), end = dataCache_.end(); it != end; ++it) { (*it).resize(numCols); } } for (int c = 0; c < numCols; ++c) { char const* buf = reinterpret_cast(sqlite3_column_text(stmt_, c)); bool isNull = false; if (0 == buf) { isNull = true; buf = ""; } dataCache_[i][c].data_ = buf; dataCache_[i][c].isNull_ = isNull; } } else { clean_up(); char const* zErrMsg = sqlite3_errmsg(session_.conn_); std::ostringstream ss; ss << "sqlite3_statement_backend::loadRS: " << zErrMsg; throw sqlite3_soci_error(ss.str(), res); } } } // if we read less than requested then shrink the vector dataCache_.resize(i); return retVal; } // This is used for non-bulk operations statement_backend::exec_fetch_result sqlite3_statement_backend::load_one() { statement_backend::exec_fetch_result retVal = ef_success; int const res = sqlite3_step(stmt_); if (SQLITE_DONE == res) { databaseReady_ = false; retVal = ef_no_data; } else if (SQLITE_ROW == res) { } else { clean_up(); char const* zErrMsg = sqlite3_errmsg(session_.conn_); std::ostringstream ss; ss << "sqlite3_statement_backend::loadOne: " << zErrMsg; throw sqlite3_soci_error(ss.str(), res); } return retVal; } // Execute statements once for every row of useData statement_backend::exec_fetch_result sqlite3_statement_backend::bind_and_execute(int number) { statement_backend::exec_fetch_result retVal = ef_no_data; long long rowsAffectedBulkTemp = 0; int const rows = static_cast(useData_.size()); for (int row = 0; row < rows; ++row) { sqlite3_reset(stmt_); int const totalPositions = static_cast(useData_[0].size()); for (int pos = 1; pos <= totalPositions; ++pos) { int bindRes = SQLITE_OK; const sqlite3_column& curCol = useData_[row][pos-1]; if (curCol.isNull_) { bindRes = sqlite3_bind_null(stmt_, pos); } else if (curCol.blobBuf_) { bindRes = sqlite3_bind_blob(stmt_, pos, curCol.blobBuf_, static_cast(curCol.blobSize_), SQLITE_STATIC); } else { bindRes = sqlite3_bind_text(stmt_, pos, curCol.data_.c_str(), static_cast(curCol.data_.length()), SQLITE_STATIC); } if (SQLITE_OK != bindRes) { // preserve the number of rows affected so far. rowsAffectedBulk_ = rowsAffectedBulkTemp; throw sqlite3_soci_error("Failure to bind on bulk operations", bindRes); } } // Handle the case where there are both into and use elements // in the same query and one of the into binds to a vector object. if (1 == rows && number != rows) { return load_rowset(number); } retVal = load_one(); //execute each bound line rowsAffectedBulkTemp += get_affected_rows(); } rowsAffectedBulk_ = rowsAffectedBulkTemp; return retVal; } statement_backend::exec_fetch_result sqlite3_statement_backend::execute(int number) { if (stmt_ == NULL) { throw soci_error("No sqlite statement created"); } sqlite3_reset(stmt_); databaseReady_ = true; statement_backend::exec_fetch_result retVal = ef_no_data; if (useData_.empty() == false) { retVal = bind_and_execute(number); } else { if (1 == number) { retVal = load_one(); } else { retVal = load_rowset(number); } } return retVal; } statement_backend::exec_fetch_result sqlite3_statement_backend::fetch(int number) { return load_rowset(number); } long long sqlite3_statement_backend::get_affected_rows() { if (rowsAffectedBulk_ >= 0) { return rowsAffectedBulk_; } return sqlite3_changes(session_.conn_); } int sqlite3_statement_backend::get_number_of_rows() { return static_cast(dataCache_.size()); } std::string sqlite3_statement_backend::rewrite_for_procedure_call( std::string const &query) { return query; } int sqlite3_statement_backend::prepare_for_describe() { return sqlite3_column_count(stmt_); } void sqlite3_statement_backend::describe_column(int colNum, data_type & type, std::string & columnName) { columnName = sqlite3_column_name(stmt_, colNum-1); // This is a hack, but the sqlite3 type system does not // have a date or time field. Also it does not reliably // id other data types. It has a tendency to see everything // as text. sqlite3_column_decltype returns the text that is // used in the create table statement bool typeFound = false; char const* declType = sqlite3_column_decltype(stmt_, colNum-1); if ( declType == NULL ) { static char const* s_char = "char"; declType = s_char; } std::string dt = declType; // do all comparisons in lower case std::transform(dt.begin(), dt.end(), dt.begin(), tolower); if (dt.find("time", 0) != std::string::npos) { type = dt_date; typeFound = true; } if (dt.find("date", 0) != std::string::npos) { type = dt_date; typeFound = true; } if (dt.find("int8", 0) != std::string::npos || dt.find("bigint", 0) != std::string::npos) { type = dt_long_long; typeFound = true; } else if (dt.find("unsigned big int", 0) != std::string::npos) { type = dt_unsigned_long_long; typeFound = true; } else if (dt.find("int", 0) != std::string::npos) { type = dt_integer; typeFound = true; } if (dt.find("float", 0) != std::string::npos || dt.find("double", 0) != std::string::npos) { type = dt_double; typeFound = true; } if (dt.find("text", 0) != std::string::npos) { type = dt_string; typeFound = true; } if (dt.find("char", 0) != std::string::npos) { type = dt_string; typeFound = true; } if (dt.find("boolean", 0) != std::string::npos) { type = dt_integer; typeFound = true; } if (typeFound) { return; } // try to get it from the weak ass type system // total hack - execute the statment once to get the column types // then clear so it can be executed again sqlite3_step(stmt_); int const sqlite3_type = sqlite3_column_type(stmt_, colNum-1); switch (sqlite3_type) { case SQLITE_INTEGER: type = dt_integer; break; case SQLITE_FLOAT: type = dt_double; break; case SQLITE_BLOB: case SQLITE_TEXT: type = dt_string; break; default: type = dt_string; break; } sqlite3_reset(stmt_); } sqlite3_standard_into_type_backend * sqlite3_statement_backend::make_into_type_backend() { return new sqlite3_standard_into_type_backend(*this); } sqlite3_standard_use_type_backend * sqlite3_statement_backend::make_use_type_backend() { return new sqlite3_standard_use_type_backend(*this); } sqlite3_vector_into_type_backend * sqlite3_statement_backend::make_vector_into_type_backend() { return new sqlite3_vector_into_type_backend(*this); } sqlite3_vector_use_type_backend * sqlite3_statement_backend::make_vector_use_type_backend() { return new sqlite3_vector_use_type_backend(*this); } soci-3.2.3/backends/sqlite3/vector-use-type.cpp0000644000000000000000000001756112511361676020111 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci-sqlite3.h" #include #include "common.h" // std #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355 4996) #define snprintf _snprintf // TODO: use soci-platform.h #endif using namespace soci; using namespace soci::details; using namespace soci::details::sqlite3; void sqlite3_vector_use_type_backend::bind_by_pos(int & position, void * data, exchange_type type) { if (statement_.boundByName_) { throw soci_error( "Binding for use elements must be either by position or by name."); } data_ = data; type_ = type; position_ = position++; statement_.boundByPos_ = true; } void sqlite3_vector_use_type_backend::bind_by_name(std::string const & name, void * data, exchange_type type) { if (statement_.boundByPos_) { throw soci_error( "Binding for use elements must be either by position or by name."); } data_ = data; type_ = type; name_ = ":" + name; statement_.reset_if_needed(); position_ = sqlite3_bind_parameter_index(statement_.stmt_, name_.c_str()); if (0 == position_) { std::ostringstream ss; ss << "Cannot bind (by name) to " << name_; throw soci_error(ss.str()); } statement_.boundByName_ = true; } void sqlite3_vector_use_type_backend::pre_use(indicator const * ind) { std::size_t const vsize = size(); // make sure that useData can hold enough rows if (statement_.useData_.size() != vsize) { statement_.useData_.resize(vsize); } int const pos = position_ - 1; for (size_t i = 0; i != vsize; ++i) { char *buf = 0; // make sure that each row can accomodate the number of columns if (statement_.useData_[i].size() < static_cast(position_)) { statement_.useData_[i].resize(position_); } // the data in vector can be either i_ok or i_null if (ind != NULL && ind[i] == i_null) { statement_.useData_[i][pos].isNull_ = true; statement_.useData_[i][pos].data_ = ""; statement_.useData_[i][pos].blobBuf_ = 0; statement_.useData_[i][pos].blobSize_ = 0; } else { // allocate and fill the buffer with text-formatted client data switch (type_) { case x_char: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; buf = new char[2]; buf[0] = v[i]; buf[1] = '\0'; } break; case x_stdstring: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; buf = new char[v[i].size() + 1]; std::strcpy(buf, v[i].c_str()); } break; case x_short: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf = new char[bufSize]; snprintf(buf, bufSize, "%d", static_cast(v[i])); } break; case x_integer: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf = new char[bufSize]; snprintf(buf, bufSize, "%d", v[i]); } break; case x_long_long: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf = new char[bufSize]; snprintf(buf, bufSize, "%" LL_FMT_FLAGS "d", v[i]); } break; case x_unsigned_long_long: { std::vector* pv = static_cast*>(data_); std::vector& v = *pv; std::size_t const bufSize = std::numeric_limits::digits10 + 2; buf = new char[bufSize]; snprintf(buf, bufSize, "%" LL_FMT_FLAGS "u", v[i]); } break; case x_double: { // no need to overengineer it (KISS)... std::vector *pv = static_cast *>(data_); std::vector &v = *pv; std::size_t const bufSize = 100; buf = new char[bufSize]; snprintf(buf, bufSize, "%.20g", v[i]); } break; case x_stdtm: { std::vector *pv = static_cast *>(data_); std::vector &v = *pv; std::size_t const bufSize = 20; buf = new char[bufSize]; snprintf(buf, bufSize, "%d-%02d-%02d %02d:%02d:%02d", v[i].tm_year + 1900, v[i].tm_mon + 1, v[i].tm_mday, v[i].tm_hour, v[i].tm_min, v[i].tm_sec); } break; default: throw soci_error( "Use vector element used with non-supported type."); } statement_.useData_[i][pos].isNull_ = false; statement_.useData_[i][pos].data_ = buf; statement_.useData_[i][pos].blobBuf_ = 0; statement_.useData_[i][pos].blobSize_ = 0; } if (buf) { delete [] buf; } } } std::size_t sqlite3_vector_use_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type_) { // simple cases case x_char: sz = get_vector_size(data_); break; case x_short: sz = get_vector_size(data_); break; case x_integer: sz = get_vector_size(data_); break; case x_long_long: sz = get_vector_size(data_); break; case x_unsigned_long_long: sz = get_vector_size(data_); break; case x_double: sz = get_vector_size(data_); break; case x_stdstring: sz = get_vector_size(data_); break; case x_stdtm: sz = get_vector_size(data_); break; default: throw soci_error("Use vector element used with non-supported type."); } return sz; } void sqlite3_vector_use_type_backend::clean_up() { // ... } soci-3.2.3/backends/sqlite3/standard-use-type.cpp0000644000000000000000000001611612511361676020402 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci-sqlite3.h" #include #include "rowid.h" #include "blob.h" // std #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355 4996) #define snprintf _snprintf // TODO: use soci-platform.h #endif using namespace soci; using namespace soci::details; void sqlite3_standard_use_type_backend::bind_by_pos(int& position, void* data, exchange_type type, bool /*readOnly*/) { if (statement_.boundByName_) { throw soci_error( "Binding for use elements must be either by position or by name."); } data_ = data; type_ = type; position_ = position++; statement_.boundByPos_ = true; } void sqlite3_standard_use_type_backend::bind_by_name(std::string const& name, void* data, exchange_type type, bool /*readOnly*/) { if (statement_.boundByPos_) { throw soci_error( "Binding for use elements must be either by position or by name."); } data_ = data; type_ = type; name_ = ":" + name; statement_.reset_if_needed(); position_ = sqlite3_bind_parameter_index(statement_.stmt_, name_.c_str()); if (0 == position_) { std::ostringstream ss; ss << "Cannot bind to (by name) " << name_; throw soci_error(ss.str()); } statement_.boundByName_ = true; } void sqlite3_standard_use_type_backend::pre_use(indicator const * ind) { statement_.useData_.resize(1); int const pos = position_ - 1; if (statement_.useData_[0].size() < static_cast(position_)) { statement_.useData_[0].resize(position_); } if (ind != NULL && *ind == i_null) { statement_.useData_[0][pos].isNull_ = true; statement_.useData_[0][pos].data_ = ""; statement_.useData_[0][pos].blobBuf_ = 0; statement_.useData_[0][pos].blobSize_ = 0; } else { // allocate and fill the buffer with text-formatted client data switch (type_) { case x_char: { buf_ = new char[2]; buf_[0] = *static_cast(data_); buf_[1] = '\0'; } break; case x_stdstring: { std::string *s = static_cast(data_); buf_ = new char[s->size() + 1]; std::strcpy(buf_, s->c_str()); } break; case x_short: { std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%d", static_cast(*static_cast(data_))); } break; case x_integer: { std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%d", *static_cast(data_)); } break; case x_long_long: { std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%" LL_FMT_FLAGS "d", *static_cast(data_)); } break; case x_unsigned_long_long: { std::size_t const bufSize = std::numeric_limits::digits10 + 2; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%" LL_FMT_FLAGS "u", *static_cast(data_)); } break; case x_double: { // no need to overengineer it (KISS)... std::size_t const bufSize = 100; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%.20g", *static_cast(data_)); } break; case x_stdtm: { std::size_t const bufSize = 20; buf_ = new char[bufSize]; std::tm *t = static_cast(data_); snprintf(buf_, bufSize, "%d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); } break; case x_rowid: { // RowID is internally identical to unsigned long rowid *rid = static_cast(data_); sqlite3_rowid_backend *rbe = static_cast(rid->get_backend()); std::size_t const bufSize = std::numeric_limits::digits10 + 2; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%lu", rbe->value_); } break; case x_blob: { blob *b = static_cast(data_); sqlite3_blob_backend *bbe = static_cast(b->get_backend()); std::size_t len = bbe->get_len(); buf_ = new char[len]; bbe->read(0, buf_, len); statement_.useData_[0][pos].blobBuf_ = buf_; statement_.useData_[0][pos].blobSize_ = len; } break; default: throw soci_error("Use element used with non-supported type."); } statement_.useData_[0][pos].isNull_ = false; if (type_ != x_blob) { statement_.useData_[0][pos].blobBuf_ = 0; statement_.useData_[0][pos].blobSize_ = 0; statement_.useData_[0][pos].data_ = buf_; } } } void sqlite3_standard_use_type_backend::post_use( bool /* gotData */, indicator * /* ind */) { // TODO: Is it possible to have the bound element being overwritten // by the database? // If not, then nothing to do here, please remove this comment. // If yes, then use the value of the readOnly parameter: // - true: the given object should not be modified and the backend // should detect if the modification was performed on the // isolated buffer and throw an exception if the buffer was modified // (this indicates logic error, because the user used const object // and executed a query that attempted to modified it) // - false: the modification should be propagated to the given object. // ... // clean up the working buffer, it might be allocated anew in // the next run of preUse clean_up(); } void sqlite3_standard_use_type_backend::clean_up() { if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } } soci-3.2.3/backends/sqlite3/session.cpp0000644000000000000000000001016712511401144016475 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci-sqlite3.h" #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace sqlite_api; namespace // anonymous { // helper function for hardcoded queries void execude_hardcoded(sqlite_api::sqlite3* conn, char const* const query, char const* const errMsg) { char *zErrMsg = 0; int const res = sqlite3_exec(conn, query, 0, 0, &zErrMsg); if (res != SQLITE_OK) { std::ostringstream ss; ss << errMsg << " " << zErrMsg; sqlite3_free(zErrMsg); throw sqlite3_soci_error(ss.str(), res); } } void check_sqlite_err(sqlite_api::sqlite3* conn, int res, char const* const errMsg) { if (SQLITE_OK != res) { const char *zErrMsg = sqlite3_errmsg(conn); std::ostringstream ss; ss << errMsg << zErrMsg; throw sqlite3_soci_error(ss.str(), res); } } } // namespace anonymous sqlite3_session_backend::sqlite3_session_backend( connection_parameters const & parameters) { int timeout = 0; int connection_flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; std::string synchronous; std::string const & connectString = parameters.get_connect_string(); std::string dbname(connectString); std::stringstream ssconn(connectString); while (!ssconn.eof() && ssconn.str().find('=') != std::string::npos) { std::string key, val; std::getline(ssconn, key, '='); std::getline(ssconn, val, ' '); if (val.size()>0 && val[0]=='\"') { std::string quotedVal = val.erase(0, 1); if (quotedVal[quotedVal.size()-1] == '\"') { quotedVal.erase(val.size()-1); } else // space inside value string { std::getline(ssconn, val, '\"'); quotedVal = quotedVal + " " + val; std::string keepspace; std::getline(ssconn, keepspace, ' '); } val = quotedVal; } if ("dbname" == key || "db" == key) { dbname = val; } else if ("timeout" == key) { std::istringstream converter(val); converter >> timeout; } else if ("synchronous" == key) { synchronous = val; } else if ("shared_cache" == key && "true" == val) { connection_flags |= SQLITE_OPEN_SHAREDCACHE; } } int res = sqlite3_open_v2(dbname.c_str(), &conn_, connection_flags, NULL); check_sqlite_err(conn_, res, "Cannot establish connection to the database. "); if (!synchronous.empty()) { std::string const query("pragma synchronous=" + synchronous); std::string const errMsg("Query failed: " + query); execude_hardcoded(conn_, query.c_str(), errMsg.c_str()); } res = sqlite3_busy_timeout(conn_, timeout * 1000); check_sqlite_err(conn_, res, "Failed to set busy timeout for connection. "); } sqlite3_session_backend::~sqlite3_session_backend() { clean_up(); } void sqlite3_session_backend::begin() { execude_hardcoded(conn_, "BEGIN", "Cannot begin transaction."); } void sqlite3_session_backend::commit() { execude_hardcoded(conn_, "COMMIT", "Cannot commit transaction."); } void sqlite3_session_backend::rollback() { execude_hardcoded(conn_, "ROLLBACK", "Cannot rollback transaction."); } void sqlite3_session_backend::clean_up() { sqlite3_close(conn_); } sqlite3_statement_backend * sqlite3_session_backend::make_statement_backend() { return new sqlite3_statement_backend(*this); } sqlite3_rowid_backend * sqlite3_session_backend::make_rowid_backend() { return new sqlite3_rowid_backend(*this); } sqlite3_blob_backend * sqlite3_session_backend::make_blob_backend() { return new sqlite3_blob_backend(*this); } soci-3.2.3/backends/sqlite3/Makefile.basic0000644000000000000000000000523712511401144017030 0ustar rootroot# The following variable is specific to this backend and its correct # values might depend on your environment - feel free to set it accordingly. SQLITE3INCLUDEDIR = # The rest of the Makefile is indepentent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long CXXFLAGSSO = ${CXXFLAGS} -fPIC INCLUDEDIRS = -I../../core ${SQLITE3INCLUDEDIR} OBJECTS = blob.o error.o factory.o row-id.o session.o standard-into-type.o \ standard-use-type.o statement.o vector-into-type.o vector-use-type.o \ common.o OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \ standard-into-type-s.o standard-use-type-s.o statement-s.o \ vector-into-type-s.o vector-use-type-s.o common-s.o libsoci_sqlite3.a : ${OBJECTS} ar rv $@ $? ranlib $@ rm *.o blob.o : blob.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} error.o : error.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} common.o : common.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} factory.o : factory.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} row-id.o : row-id.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} session.o : session.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-into-type.o : standard-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-use-type.o : standard-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} statement.o : statement.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-into-type.o : vector-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-use-type.o : vector-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} shared : ${OBJECTSSO} ${COMPILER} -shared -o libsoci_sqlite3.so ${OBJECTSSO} rm *.o blob-s.o : blob.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} error-s.o : error.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGS} ${INCLUDEDIRS} common-s.o : common.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} factory-s.o : factory.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} row-id-s.o : row-id.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} session-s.o : session.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} standard-into-type-s.o : standard-into-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} standard-use-type-s.o : standard-use-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} statement-s.o : statement.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} vector-into-type-s.o : vector-into-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} vector-use-type-s.o : vector-use-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} clean : rm -f libsoci_sqlite3.a libsoci_sqlite3.so soci-3.2.3/backends/sqlite3/error.cpp0000644000000000000000000000101512511401144016133 0ustar rootroot// // Copyright 2014 SimpliVT Corporation // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SQLITE3_SOURCE #include "soci-sqlite3.h" #include "error.h" #include #include using namespace soci; sqlite3_soci_error::sqlite3_soci_error( std::string const & msg, int result) : soci_error(msg), result_(result) { } int sqlite3_soci_error::result() const { return result_; } soci-3.2.3/backends/sqlite3/factory.cpp0000644000000000000000000000172412511361676016477 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SQLITE3_SOURCE #include "soci-sqlite3.h" #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; // concrete factory for Empty concrete strategies sqlite3_session_backend * sqlite3_backend_factory::make_session( connection_parameters const & parameters) const { return new sqlite3_session_backend(parameters); } sqlite3_backend_factory const soci::sqlite3; extern "C" { // for dynamic backend loading SOCI_SQLITE3_DECL backend_factory const * factory_sqlite3() { return &soci::sqlite3; } SOCI_SQLITE3_DECL void register_factory_sqlite3() { soci::dynamic_backends::register_backend("sqlite3", soci::sqlite3); } } // extern "C" soci-3.2.3/backends/sqlite3/row-id.cpp0000644000000000000000000000103612511361676016225 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci-sqlite3.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; sqlite3_rowid_backend::sqlite3_rowid_backend( sqlite3_session_backend & /* session */) { // ... } sqlite3_rowid_backend::~sqlite3_rowid_backend() { // ... } soci-3.2.3/backends/sqlite3/standard-into-type.cpp0000644000000000000000000001122212511361676020550 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include "soci-sqlite3.h" #include "rowid.h" #include "common.h" #include "blob.h" // std #include #include #include using namespace soci; using namespace soci::details; using namespace soci::details::sqlite3; void sqlite3_standard_into_type_backend::define_by_pos(int & position, void * data, exchange_type type) { data_ = data; type_ = type; position_ = position++; } void sqlite3_standard_into_type_backend::pre_fetch() { // ... } void sqlite3_standard_into_type_backend::post_fetch(bool gotData, bool calledFromFetch, indicator * ind) { if (calledFromFetch == true && gotData == false) { // this is a normal end-of-rowset condition, // no need to do anything (fetch() will return false) return; } // sqlite columns start at 0 int const pos = position_ - 1; if (gotData) { // first, deal with indicators if (sqlite3_column_type(statement_.stmt_, pos) == SQLITE_NULL) { if (ind == NULL) { throw soci_error( "Null value fetched and no indicator defined."); } *ind = i_null; return; } else { if (ind != NULL) { *ind = i_ok; } } const char *buf = reinterpret_cast( sqlite3_column_text(statement_.stmt_,pos)); if (buf == NULL) { buf = ""; } switch (type_) { case x_char: { char *dest = static_cast(data_); *dest = *buf; } break; case x_stdstring: { std::string *dest = static_cast(data_); dest->assign(buf); } break; case x_short: { short *dest = static_cast(data_); long val = std::strtol(buf, NULL, 10); *dest = static_cast(val); } break; case x_integer: { int *dest = static_cast(data_); long val = std::strtol(buf, NULL, 10); *dest = static_cast(val); } break; case x_long_long: { long long* dest = static_cast(data_); *dest = std::strtoll(buf, NULL, 10); } break; case x_unsigned_long_long: { unsigned long long* dest = static_cast(data_); *dest = string_to_unsigned_integer(buf); } break; case x_double: { double *dest = static_cast(data_); double val = strtod(buf, NULL); *dest = static_cast(val); } break; case x_stdtm: { // attempt to parse the string and convert to std::tm std::tm *dest = static_cast(data_); parse_std_tm(buf, *dest); } break; case x_rowid: { // RowID is internally identical to unsigned long rowid *rid = static_cast(data_); sqlite3_rowid_backend *rbe = static_cast(rid->get_backend()); long long val = std::strtoll(buf, NULL, 10); rbe->value_ = static_cast(val); } break; case x_blob: { blob *b = static_cast(data_); sqlite3_blob_backend *bbe = static_cast(b->get_backend()); buf = reinterpret_cast(sqlite3_column_blob( statement_.stmt_, pos)); int len = sqlite3_column_bytes(statement_.stmt_, pos); bbe->set_data(buf, len); } break; default: throw soci_error("Into element used with non-supported type."); } } } void sqlite3_standard_into_type_backend::clean_up() { // ... } soci-3.2.3/backends/sqlite3/test/0000755000000000000000000000000012511401144015260 5ustar rootrootsoci-3.2.3/backends/sqlite3/test/test-sqlite3.cpp0000644000000000000000000002624412511401144020335 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci.h" #include "soci-sqlite3.h" #include "common-tests.h" #include #include #include #include #include #include #include using namespace soci; using namespace soci::tests; std::string connectString; backend_factory const &backEnd = *soci::factory_sqlite3(); // ROWID test // In sqlite3 the row id can be called ROWID, _ROWID_ or oid void test1() { { session sql(backEnd, connectString); try { sql << "drop table test1"; } catch (soci_error const &) {} // ignore if error sql << "create table test1 (" " id integer," " name varchar(100)" ")"; sql << "insert into test1(id, name) values(7, \'John\')"; rowid rid(sql); sql << "select oid from test1 where id = 7", into(rid); int id; std::string name; sql << "select id, name from test1 where oid = :rid", into(id), into(name), use(rid); assert(id == 7); assert(name == "John"); sql << "drop table test1"; } std::cout << "test 1 passed" << std::endl; } // BLOB test struct blob_table_creator : public table_creator_base { blob_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test (" " id integer," " img blob" ")"; } }; void test2() { { session sql(backEnd, connectString); blob_table_creator tableCreator(sql); char buf[] = "abcdefghijklmnopqrstuvwxyz"; sql << "insert into soci_test(id, img) values(7, '')"; { blob b(sql); sql << "select img from soci_test where id = 7", into(b); assert(b.get_len() == 0); b.write(0, buf, sizeof(buf)); assert(b.get_len() == sizeof(buf)); sql << "update soci_test set img=? where id = 7", use(b); b.append(buf, sizeof(buf)); assert(b.get_len() == 2 * sizeof(buf)); sql << "insert into soci_test(id, img) values(8, ?)", use(b); } { blob b(sql); sql << "select img from soci_test where id = 8", into(b); assert(b.get_len() == 2 * sizeof(buf)); char buf2[100]; b.read(0, buf2, 10); assert(std::strncmp(buf2, "abcdefghij", 10) == 0); sql << "select img from soci_test where id = 7", into(b); assert(b.get_len() == sizeof(buf)); } } std::cout << "test 2 passed" << std::endl; } // This test was put in to fix a problem that occurs when there are both // into and use elements in the same query and one of them (into) binds // to a vector object. struct test3_table_creator : table_creator_base { test3_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test( id integer, name varchar, subname varchar);"; } }; void test3() { { session sql(backEnd, connectString); test3_table_creator tableCreator(sql); sql << "insert into soci_test(id,name,subname) values( 1,'john','smith')"; sql << "insert into soci_test(id,name,subname) values( 2,'george','vals')"; sql << "insert into soci_test(id,name,subname) values( 3,'ann','smith')"; sql << "insert into soci_test(id,name,subname) values( 4,'john','grey')"; sql << "insert into soci_test(id,name,subname) values( 5,'anthony','wall')"; { std::vector v(10); statement s(sql.prepare << "Select id from soci_test where name = :name"); std::string name = "john"; s.exchange(use(name, "name")); s.exchange(into(v)); s.define_and_bind(); s.execute(true); assert(v.size() == 2); } } std::cout << "test 3 passed" << std::endl; } // Test case from Amnon David 11/1/2007 // I've noticed that table schemas in SQLite3 can sometimes have typeless // columns. One (and only?) example is the sqlite_sequence that sqlite // creates for autoincrement . Attempting to traverse this table caused // SOCI to crash. I've made the following code change in statement.cpp to // create a workaround: struct test4_table_creator : table_creator_base { test4_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test (col INTEGER PRIMARY KEY AUTOINCREMENT, name char)"; } }; void test4() { { // we need to have an table that uses autoincrement to test this. session sql(backEnd, connectString); test4_table_creator tableCreator(sql); sql << "insert into soci_test(name) values('john')"; sql << "insert into soci_test(name) values('james')"; { int key; std::string name; sql << "select * from soci_test", into(key), into(name); assert(name == "john"); rowset rs = (sql.prepare << "select * from sqlite_sequence"); rowset::const_iterator it = rs.begin(); row const& r1 = (*it); assert(r1.get(0) == "soci_test"); assert(r1.get(1) == "2"); } } std::cout << "test 4 passed" << std::endl; } struct longlong_table_creator : table_creator_base { longlong_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val number(20))"; } }; // long long test void test5() { { session sql(backEnd, connectString); longlong_table_creator tableCreator(sql); long long v1 = 1000000000000LL; assert(v1 / 1000000 == 1000000); sql << "insert into soci_test(val) values(:val)", use(v1); long long v2 = 0LL; sql << "select val from soci_test", into(v2); assert(v2 == v1); } // vector { session sql(backEnd, connectString); longlong_table_creator tableCreator(sql); std::vector v1; v1.push_back(1000000000000LL); v1.push_back(1000000000001LL); v1.push_back(1000000000002LL); v1.push_back(1000000000003LL); v1.push_back(1000000000004LL); sql << "insert into soci_test(val) values(:val)", use(v1); std::vector v2(10); sql << "select val from soci_test order by val desc", into(v2); assert(v2.size() == 5); assert(v2[0] == 1000000000004LL); assert(v2[1] == 1000000000003LL); assert(v2[2] == 1000000000002LL); assert(v2[3] == 1000000000001LL); assert(v2[4] == 1000000000000LL); } std::cout << "test 5 passed" << std::endl; } struct test6_table_creator : table_creator_base { test6_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test (id INTEGER PRIMARY KEY, name char)"; } }; void test6() { { session sql(backEnd, connectString); test6_table_creator tableCreator(sql); sql << "insert into soci_test(id, name) values(1, 'john')"; { try { // using same primary key causes constraint violation error sql << "insert into soci_test(id, name) values(1, 'jack')"; } catch (sqlite3_soci_error const& e) { assert(SQLITE_CONSTRAINT == (0xFF & e.result())); } } } std::cout << "test 6 passed" << std::endl; } // DDL Creation objects for common tests struct table_creator_one : public table_creator_base { table_creator_one(session & sql) : table_creator_base(sql) { sql << "create table soci_test(id integer, val integer, c char, " "str varchar(20), sh smallint, ul numeric(20), d float, " "tm datetime, i1 integer, i2 integer, i3 integer, " "name varchar(20))"; } }; struct table_creator_two : public table_creator_base { table_creator_two(session & sql) : table_creator_base(sql) { sql << "create table soci_test(num_float float, num_int integer," " name varchar(20), sometime datetime, chr char)"; } }; struct table_creator_three : public table_creator_base { table_creator_three(session & sql) : table_creator_base(sql) { sql << "create table soci_test(name varchar(100) not null, " "phone varchar(15))"; } }; // Originally, submitted to SQLite3 backend and later moved to common test. // Test commit b394d039530f124802d06c3b1a969c3117683152 // Author: Mika Fischer // Date: Thu Nov 17 13:28:07 2011 +0100 // Implement get_affected_rows for SQLite3 backend struct table_creator_for_get_affected_rows : table_creator_base { table_creator_for_get_affected_rows(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val integer)"; } }; // // Support for SOCI Common Tests // class test_context : public test_context_base { public: test_context(backend_factory const &backEnd, std::string const &connectString) : test_context_base(backEnd, connectString) {} table_creator_base* table_creator_1(session& s) const { return new table_creator_one(s); } table_creator_base* table_creator_2(session& s) const { return new table_creator_two(s); } table_creator_base* table_creator_3(session& s) const { return new table_creator_three(s); } table_creator_base* table_creator_4(session& s) const { return new table_creator_for_get_affected_rows(s); } std::string to_date_time(std::string const &datdt_string) const { return "datetime(\'" + datdt_string + "\')"; } }; int main(int argc, char** argv) { #ifdef _MSC_VER // Redirect errors, unrecoverable problems, and assert() failures to STDERR, // instead of debug message window. // This hack is required to run asser()-driven tests by Buildbot. // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); #endif //_MSC_VER if (argc == 2) { connectString = argv[1]; } else { // If no file name is specfied then work in-memory connectString = ":memory:"; } try { test_context tc(backEnd, connectString); common_tests tests(tc); tests.run(); std::cout << "\nSOCI sqlite3 Tests:\n\n"; test1(); test2(); test3(); test4(); test5(); test6(); std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; } catch (soci::soci_error const & e) { std::cout << "SOCIERROR: " << e.what() << '\n'; } catch (std::exception const & e) { std::cout << "EXCEPTION: " << e.what() << '\n'; } return EXIT_FAILURE; } soci-3.2.3/backends/sqlite3/test/.gitignore0000644000000000000000000000003512511361676017265 0ustar rootroottest_sqlite3 test_sqlite3.db soci-3.2.3/backends/sqlite3/test/Makefile.basic0000644000000000000000000000126712511361676020025 0ustar rootroot# The following variable is specific to this backend and its correct # values might depend on your environment - feel free to set it accordingly. BOOSTINCLUDEDIR = SQLITE3INCLUDEDIR = SQLITE3LIBDIR = -L/usr/lib SQLITE3LIBS = -lsqlite3 # The rest of the Makefile is independent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long INCLUDEDIRS = -I.. -I../../../core -I../../../core/test ${SQLITE3INCLUDEDIR} ${BOOSTINCLUDEDIR} LIBDIRS = -L.. -L../../../core ${SQLITE3LIBDIR} LIBS = -lsoci_core -lsoci_sqlite3 -ldl ${SQLITE3LIBS} test-sqlite3 : test-sqlite3.cpp ${COMPILER} -o $@ $? ${CXXFLAGS} ${INCLUDEDIRS} ${LIBDIRS} ${LIBS} clean : rm -f test-sqlite3 soci-3.2.3/backends/sqlite3/test/CMakeLists.txt0000644000000000000000000000101512511361676020034 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend_test( BACKEND SQLite3 SOURCE test-sqlite3.cpp CONNSTR "soci_test.db")soci-3.2.3/backends/sqlite3/common.cpp0000644000000000000000000000264412511361676016322 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include "common.h" #include "soci-backend.h" // std #include #include namespace // anonymous { // helper function for parsing decimal data (for std::tm) long parse10(char const *&p1, char *&p2, char const* const msg) { long v = std::strtol(p1, &p2, 10); if (p2 != p1) { p1 = p2 + 1; return v; } else { throw soci::soci_error(msg); } } } // namespace anonymous void soci::details::sqlite3::parse_std_tm(char const *buf, std::tm &t) { char const *p1 = buf; char *p2 = 0; char const* const errMsg = "Cannot convert data to std::tm."; long year = parse10(p1, p2, errMsg); long month = parse10(p1, p2, errMsg); long day = parse10(p1, p2, errMsg); long hour = 0, minute = 0, second = 0; if (*p2 != '\0') { // there is also the time of day available hour = parse10(p1, p2, errMsg); minute = parse10(p1, p2, errMsg); second = parse10(p1, p2, errMsg); } t.tm_isdst = -1; t.tm_year = year - 1900; t.tm_mon = month - 1; t.tm_mday = day; t.tm_hour = hour; t.tm_min = minute; t.tm_sec = second; std::mktime(&t); } soci-3.2.3/backends/sqlite3/vector-into-type.cpp0000644000000000000000000001250312511361676020255 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include "soci-sqlite3.h" #include "common.h" // std #include #include #include #include #include #include using namespace soci; using namespace soci::details; using namespace soci::details::sqlite3; void sqlite3_vector_into_type_backend::define_by_pos( int& position, void* data, exchange_type type) { data_ = data; type_ = type; position_ = position++; } void sqlite3_vector_into_type_backend::pre_fetch() { // ... } namespace // anonymous { template void set_in_vector(void* p, int indx, T const& val) { assert(NULL != p); std::vector* dest = static_cast*>(p); std::vector& v = *dest; v[indx] = val; } } // namespace anonymous void sqlite3_vector_into_type_backend::post_fetch(bool gotData, indicator * ind) { if (!gotData) { // no data retrieved return; } int const endRow = static_cast(statement_.dataCache_.size()); for (int i = 0; i < endRow; ++i) { sqlite3_column const& curCol = statement_.dataCache_[i][position_-1]; if (curCol.isNull_) { if (ind == NULL) { throw soci_error( "Null value fetched and no indicator defined."); } ind[i] = i_null; // no need to convert data if it is null, go to next row continue; } else { if (ind != NULL) { ind[i] = i_ok; } } const char * buf = curCol.data_.c_str(); // set buf to a null string if a null pointer is returned if (buf == NULL) { buf = ""; } switch (type_) { case x_char: set_in_vector(data_, i, *buf); break; case x_stdstring: set_in_vector(data_, i, buf); break; case x_short: { short const val = string_to_integer(buf); set_in_vector(data_, i, val); } break; case x_integer: { int const val = string_to_integer(buf); set_in_vector(data_, i, val); } break; case x_long_long: { long long const val = string_to_integer(buf); set_in_vector(data_, i, val); } break; case x_unsigned_long_long: { unsigned long long const val = string_to_unsigned_integer(buf); set_in_vector(data_, i, val); } break; case x_double: { double const val = strtod(buf, NULL); set_in_vector(data_, i, val); } break; case x_stdtm: { // attempt to parse the string and convert to std::tm std::tm t; parse_std_tm(buf, t); set_in_vector(data_, i, t); } break; default: throw soci_error("Into element used with non-supported type."); } } } void sqlite3_vector_into_type_backend::resize(std::size_t sz) { switch (type_) { // simple cases case x_char: resize_vector(data_, sz); break; case x_short: resize_vector(data_, sz); break; case x_integer: resize_vector(data_, sz); break; case x_long_long: resize_vector(data_, sz); break; case x_unsigned_long_long: resize_vector(data_, sz); break; case x_double: resize_vector(data_, sz); break; case x_stdstring: resize_vector(data_, sz); break; case x_stdtm: resize_vector(data_, sz); break; default: throw soci_error("Into vector element used with non-supported type."); } } std::size_t sqlite3_vector_into_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type_) { // simple cases case x_char: sz = get_vector_size(data_); break; case x_short: sz = get_vector_size(data_); break; case x_integer: sz = get_vector_size(data_); break; case x_long_long: sz = get_vector_size(data_); break; case x_unsigned_long_long: sz = get_vector_size(data_); break; case x_double: sz = get_vector_size(data_); break; case x_stdstring: sz = get_vector_size(data_); break; case x_stdtm: sz = get_vector_size(data_); break; default: throw soci_error("Into vector element used with non-supported type."); } return sz; } void sqlite3_vector_into_type_backend::clean_up() { // ... } soci-3.2.3/backends/sqlite3/CMakeLists.txt0000644000000000000000000000127312511362240017047 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend(SQLite3 DEPENDS SQLite3 HEADERS soci-sqlite3.h common.h DESCRIPTION "SOCI backend for SQLite 3 database engine" AUTHORS "Maciej Sobczak, Stephen Hutton, David Courtney" MAINTAINERS "Maciej Sobczak, Mateusz Loskot") add_subdirectory(test) soci-3.2.3/backends/empty/0000755000000000000000000000000012511362240014056 5ustar rootrootsoci-3.2.3/backends/empty/blob.cpp0000644000000000000000000000213212511361676015512 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_EMPTY_SOURCE #include "soci-empty.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; empty_blob_backend::empty_blob_backend(empty_session_backend &session) : session_(session) { // ... } empty_blob_backend::~empty_blob_backend() { // ... } std::size_t empty_blob_backend::get_len() { // ... return 0; } std::size_t empty_blob_backend::read( std::size_t /* offset */, char * /* buf */, std::size_t /* toRead */) { // ... return 0; } std::size_t empty_blob_backend::write( std::size_t /* offset */, char const * /* buf */, std::size_t /* toWrite */) { // ... return 0; } std::size_t empty_blob_backend::append( char const * /* buf */, std::size_t /* toWrite */) { // ... return 0; } void empty_blob_backend::trim(std::size_t /* newLen */) { // ... } soci-3.2.3/backends/empty/statement.cpp0000644000000000000000000000401612511361676016603 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_EMPTY_SOURCE #include "soci-empty.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; empty_statement_backend::empty_statement_backend(empty_session_backend &session) : session_(session) { } void empty_statement_backend::alloc() { // ... } void empty_statement_backend::clean_up() { // ... } void empty_statement_backend::prepare(std::string const & /* query */, statement_type /* eType */) { // ... } statement_backend::exec_fetch_result empty_statement_backend::execute(int /* number */) { // ... return ef_success; } statement_backend::exec_fetch_result empty_statement_backend::fetch(int /* number */) { // ... return ef_success; } long long empty_statement_backend::get_affected_rows() { // ... return -1; } int empty_statement_backend::get_number_of_rows() { // ... return 1; } std::string empty_statement_backend::rewrite_for_procedure_call( std::string const &query) { return query; } int empty_statement_backend::prepare_for_describe() { // ... return 0; } void empty_statement_backend::describe_column(int /* colNum */, data_type & /* type */, std::string & /* columnName */) { // ... } empty_standard_into_type_backend * empty_statement_backend::make_into_type_backend() { return new empty_standard_into_type_backend(*this); } empty_standard_use_type_backend * empty_statement_backend::make_use_type_backend() { return new empty_standard_use_type_backend(*this); } empty_vector_into_type_backend * empty_statement_backend::make_vector_into_type_backend() { return new empty_vector_into_type_backend(*this); } empty_vector_use_type_backend * empty_statement_backend::make_vector_use_type_backend() { return new empty_vector_use_type_backend(*this); } soci-3.2.3/backends/empty/vector-use-type.cpp0000644000000000000000000000160612511361676017654 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_EMPTY_SOURCE #include "soci-empty.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; void empty_vector_use_type_backend::bind_by_pos(int & /* position */, void * /* data */, exchange_type /* type */) { // ... } void empty_vector_use_type_backend::bind_by_name( std::string const & /* name */, void * /* data */, exchange_type /* type */) { // ... } void empty_vector_use_type_backend::pre_use(indicator const * /* ind */) { // ... } std::size_t empty_vector_use_type_backend::size() { // ... return 1; } void empty_vector_use_type_backend::clean_up() { // ... } soci-3.2.3/backends/empty/standard-use-type.cpp0000644000000000000000000000173012511361676020150 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_EMPTY_SOURCE #include "soci-empty.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; void empty_standard_use_type_backend::bind_by_pos( int & /* position */, void * /* data */, exchange_type /* type */, bool /* readOnly */) { // ... } void empty_standard_use_type_backend::bind_by_name( std::string const & /* name */, void * /* data */, exchange_type /* type */, bool /* readOnly */) { // ... } void empty_standard_use_type_backend::pre_use(indicator const * /* ind */) { // ... } void empty_standard_use_type_backend::post_use( bool /* gotData */, indicator * /* ind */) { // ... } void empty_standard_use_type_backend::clean_up() { // ... } soci-3.2.3/backends/empty/session.cpp0000644000000000000000000000215112511361676016260 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_EMPTY_SOURCE #include "soci-empty.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; empty_session_backend::empty_session_backend( connection_parameters const & /* parameters */) { // ... } empty_session_backend::~empty_session_backend() { clean_up(); } void empty_session_backend::begin() { // ... } void empty_session_backend::commit() { // ... } void empty_session_backend::rollback() { // ... } void empty_session_backend::clean_up() { // ... } empty_statement_backend * empty_session_backend::make_statement_backend() { return new empty_statement_backend(*this); } empty_rowid_backend * empty_session_backend::make_rowid_backend() { return new empty_rowid_backend(*this); } empty_blob_backend * empty_session_backend::make_blob_backend() { return new empty_blob_backend(*this); } soci-3.2.3/backends/empty/Makefile.basic0000644000000000000000000000450712505151606016611 0ustar rootroot# The following variable is specific to this backend and its correct # values might depend on your environment - feel free to set it accordingly. EMPTYINCLUDEDIR = # The rest of the Makefile is indepentent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long CXXFLAGSSO = ${CXXFLAGS} -fPIC INCLUDEDIRS = -I../../core ${EMPTYINCLUDEDIR} OBJECTS = blob.o factory.o row-id.o session.o standard-into-type.o \ standard-use-type.o statement.o vector-into-type.o vector-use-type.o OBJECTSSO = blob-s.o factory-s.o row-id-s.o session-s.o \ standard-into-type-s.o standard-use-type-s.o statement-s.o \ vector-into-type-s.o vector-use-type-s.o libsoci_empty.a : ${OBJECTS} ar rv $@ $? rm *.o blob.o : blob.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} factory.o : factory.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} row-id.o : row-id.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} session.o : session.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-into-type.o : standard-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-use-type.o : standard-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} statement.o : statement.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-into-type.o : vector-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-use-type.o : vector-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} shared : ${OBJECTSSO} ${COMPILER} -shared -o libsoci_empty.so ${OBJECTSSO} rm *.o blob-s.o : blob.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} factory-s.o : factory.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} row-id-s.o : row-id.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} session-s.o : session.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} standard-into-type-s.o : standard-into-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} standard-use-type-s.o : standard-use-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} statement-s.o : statement.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} vector-into-type-s.o : vector-into-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} vector-use-type-s.o : vector-use-type.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGSSO} ${INCLUDEDIRS} clean : rm -f libsoci_empty.a libsoci_empty.so soci-3.2.3/backends/empty/factory.cpp0000644000000000000000000000164512511361676016253 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_EMPTY_SOURCE #include "soci-empty.h" #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; // concrete factory for Empty concrete strategies empty_session_backend* empty_backend_factory::make_session( connection_parameters const& parameters) const { return new empty_session_backend(parameters); } empty_backend_factory const soci::empty; extern "C" { // for dynamic backend loading SOCI_EMPTY_DECL backend_factory const* factory_empty() { return &soci::empty; } SOCI_EMPTY_DECL void register_factory_empty() { soci::dynamic_backends::register_backend("empty", soci::empty); } } // extern "C" soci-3.2.3/backends/empty/row-id.cpp0000644000000000000000000000103012511361676015771 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_EMPTY_SOURCE #include "soci-empty.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; empty_rowid_backend::empty_rowid_backend(empty_session_backend & /* session */) { // ... } empty_rowid_backend::~empty_rowid_backend() { // ... } soci-3.2.3/backends/empty/standard-into-type.cpp0000644000000000000000000000143412511361676020326 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_EMPTY_SOURCE #include "soci-empty.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; void empty_standard_into_type_backend::define_by_pos( int & /* position */, void * /* data */, exchange_type /* type */) { // ... } void empty_standard_into_type_backend::pre_fetch() { // ... } void empty_standard_into_type_backend::post_fetch( bool /* gotData */, bool /* calledFromFetch */, indicator * /* ind */) { // ... } void empty_standard_into_type_backend::clean_up() { // ... } soci-3.2.3/backends/empty/test/0000755000000000000000000000000012511362240015035 5ustar rootrootsoci-3.2.3/backends/empty/test/test-empty.cpp0000644000000000000000000001043212511362240017654 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci.h" #include "soci-empty.h" #include #include #include #include #include using namespace soci; std::string connectString; backend_factory const &backEnd = *soci::factory_empty(); // NOTE: // This file is supposed to serve two purposes: // 1. To be a starting point for implementing new tests (for new backends). // 2. To exercise (at least some of) the syntax and try the SOCI library // against different compilers, even in those environments where there // is no database. SOCI uses advanced template techniques which are known // to cause problems on different versions of popular compilers, and this // test is handy to verify that the code is accepted by as many compilers // as possible. // // Both of these purposes mean that the actual code here is meaningless // from the database-development point of view. For new tests, you may wish // to remove this code and keep only the general structure of this file. struct Person { int id; std::string firstName; std::string lastName; }; namespace soci { template<> struct type_conversion { typedef values base_type; static void from_base(values & /* r */, indicator /* ind */, Person & /* p */) { } }; } void test1() { { session sql(backEnd, connectString); sql << "Do what I want."; sql << "Do what I want " << 123 << " times."; std::string query = "some query"; sql << query; int i = 7; sql << "insert", use(i); sql << "select", into(i); #if defined (__LP64__) || ( __WORDSIZE == 64 ) long int li = 9; sql << "insert", use(li); sql << "select", into(li); #endif long long ll = 11; sql << "insert", use(ll); sql << "select", into(ll); indicator ind = i_ok; sql << "insert", use(i, ind); sql << "select", into(i, ind); std::vector numbers(100); sql << "insert", use(numbers); sql << "select", into(numbers); std::vector inds(100); sql << "insert", use(numbers, inds); sql << "select", into(numbers, inds); { statement st = (sql.prepare << "select", into(i)); st.execute(); st.fetch(); } { statement st = (sql.prepare << "select", into(i, ind)); } { statement st = (sql.prepare << "select", into(numbers)); } { statement st = (sql.prepare << "select", into(numbers, inds)); } { statement st = (sql.prepare << "insert", use(i)); } { statement st = (sql.prepare << "insert", use(i, ind)); } { statement st = (sql.prepare << "insert", use(numbers)); } { statement st = (sql.prepare << "insert", use(numbers, inds)); } { Person p; sql << "select person", into(p); } } std::cout << "test 1 passed" << std::endl; } int main(int argc, char** argv) { #ifdef _MSC_VER // Redirect errors, unrecoverable problems, and assert() failures to STDERR, // instead of debug message window. // This hack is required to run asser()-driven tests by Buildbot. // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); #endif //_MSC_VER if (argc == 2) { connectString = argv[1]; } else { std::cout << "usage: " << argv[0] << " connectstring\n" << "example: " << argv[0] << " \'connect_string_for_empty_backend\'\n"; std::exit(1); } try { test1(); // test2(); // ... std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; } catch (std::exception const & e) { std::cout << e.what() << '\n'; } return EXIT_FAILURE; } soci-3.2.3/backends/empty/test/.gitignore0000644000000000000000000000001312511361676017033 0ustar rootroottest_empty soci-3.2.3/backends/empty/test/Makefile.basic0000644000000000000000000000043612511361676017574 0ustar rootrootCOMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long INCLUDEDIRS = -I.. -I../../../core LIBDIRS = -L.. -L../../../core LIBS = -lsoci_core -lsoci_empty -ldl test-empty : test-empty.cpp ${COMPILER} -o $@ $? ${CXXFLAGS} ${INCLUDEDIRS} ${LIBDIRS} ${LIBS} clean : rm -f test-empty soci-3.2.3/backends/empty/test/CMakeLists.txt0000644000000000000000000000075412511361676017617 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend_test( BACKEND Empty SOURCE test-empty.cpp CONNSTR "dummy")soci-3.2.3/backends/empty/vector-into-type.cpp0000644000000000000000000000163312511361676020031 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_EMPTY_SOURCE #include "soci-empty.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; void empty_vector_into_type_backend::define_by_pos( int & /* position */, void * /* data */, exchange_type /* type */) { // ... } void empty_vector_into_type_backend::pre_fetch() { // ... } void empty_vector_into_type_backend::post_fetch( bool /* gotData */, indicator * /* ind */) { // ... } void empty_vector_into_type_backend::resize(std::size_t /* sz */) { // ... } std::size_t empty_vector_into_type_backend::size() { // ... return 1; } void empty_vector_into_type_backend::clean_up() { // ... } soci-3.2.3/backends/empty/CMakeLists.txt0000644000000000000000000000116212511362240016616 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend(Empty HEADERS soci-empty.h DESCRIPTION "SOCI backend skeleton for development of new backends" AUTHORS "Maciej Sobczak, Stephen Hutton" MAINTAINERS "Maciej Sobczak") add_subdirectory(test) soci-3.2.3/backends/empty/soci-empty.h0000644000000000000000000001200512511362240016316 0ustar rootroot// // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_EMPTY_H_INCLUDED #define SOCI_EMPTY_H_INCLUDED #ifdef _WIN32 # ifdef SOCI_DLL # ifdef SOCI_EMPTY_SOURCE # define SOCI_EMPTY_DECL __declspec(dllexport) # else # define SOCI_EMPTY_DECL __declspec(dllimport) # endif // SOCI_EMPTY_SOURCE # endif // SOCI_DLL #endif // _WIN32 // // If SOCI_EMPTY_DECL isn't defined yet define it now #ifndef SOCI_EMPTY_DECL # define SOCI_EMPTY_DECL #endif #include "soci-backend.h" #include #include namespace soci { struct empty_statement_backend; struct SOCI_EMPTY_DECL empty_standard_into_type_backend : details::standard_into_type_backend { empty_standard_into_type_backend(empty_statement_backend &st) : statement_(st) {} void define_by_pos(int& position, void* data, details::exchange_type type); void pre_fetch(); void post_fetch(bool gotData, bool calledFromFetch, indicator* ind); void clean_up(); empty_statement_backend& statement_; }; struct SOCI_EMPTY_DECL empty_vector_into_type_backend : details::vector_into_type_backend { empty_vector_into_type_backend(empty_statement_backend &st) : statement_(st) {} void define_by_pos(int& position, void* data, details::exchange_type type); void pre_fetch(); void post_fetch(bool gotData, indicator* ind); void resize(std::size_t sz); std::size_t size(); void clean_up(); empty_statement_backend& statement_; }; struct SOCI_EMPTY_DECL empty_standard_use_type_backend : details::standard_use_type_backend { empty_standard_use_type_backend(empty_statement_backend &st) : statement_(st) {} void bind_by_pos(int& position, void* data, details::exchange_type type, bool readOnly); void bind_by_name(std::string const& name, void* data, details::exchange_type type, bool readOnly); void pre_use(indicator const* ind); void post_use(bool gotData, indicator* ind); void clean_up(); empty_statement_backend& statement_; }; struct SOCI_EMPTY_DECL empty_vector_use_type_backend : details::vector_use_type_backend { empty_vector_use_type_backend(empty_statement_backend &st) : statement_(st) {} void bind_by_pos(int& position, void* data, details::exchange_type type); void bind_by_name(std::string const& name, void* data, details::exchange_type type); void pre_use(indicator const* ind); std::size_t size(); void clean_up(); empty_statement_backend& statement_; }; struct empty_session_backend; struct SOCI_EMPTY_DECL empty_statement_backend : details::statement_backend { empty_statement_backend(empty_session_backend &session); void alloc(); void clean_up(); void prepare(std::string const& query, details::statement_type eType); exec_fetch_result execute(int number); exec_fetch_result fetch(int number); long long get_affected_rows(); int get_number_of_rows(); std::string rewrite_for_procedure_call(std::string const& query); int prepare_for_describe(); void describe_column(int colNum, data_type& dtype, std::string& columnName); empty_standard_into_type_backend* make_into_type_backend(); empty_standard_use_type_backend* make_use_type_backend(); empty_vector_into_type_backend* make_vector_into_type_backend(); empty_vector_use_type_backend* make_vector_use_type_backend(); empty_session_backend& session_; }; struct empty_rowid_backend : details::rowid_backend { empty_rowid_backend(empty_session_backend &session); ~empty_rowid_backend(); }; struct empty_blob_backend : details::blob_backend { empty_blob_backend(empty_session_backend& session); ~empty_blob_backend(); std::size_t get_len(); std::size_t read(std::size_t offset, char* buf, std::size_t toRead); std::size_t write(std::size_t offset, char const* buf, std::size_t toWrite); std::size_t append(char const* buf, std::size_t toWrite); void trim(std::size_t newLen); empty_session_backend& session_; }; struct empty_session_backend : details::session_backend { empty_session_backend(connection_parameters const& parameters); ~empty_session_backend(); void begin(); void commit(); void rollback(); std::string get_backend_name() const { return "empty"; } void clean_up(); empty_statement_backend* make_statement_backend(); empty_rowid_backend* make_rowid_backend(); empty_blob_backend* make_blob_backend(); }; struct SOCI_EMPTY_DECL empty_backend_factory : backend_factory { empty_backend_factory() {} empty_session_backend* make_session(connection_parameters const& parameters) const; }; extern SOCI_EMPTY_DECL empty_backend_factory const empty; extern "C" { // for dynamic backend loading SOCI_EMPTY_DECL backend_factory const* factory_empty(); SOCI_EMPTY_DECL void register_factory_empty(); } // extern "C" } // namespace soci #endif // SOCI_EMPTY_H_INCLUDED soci-3.2.3/backends/postgresql/0000755000000000000000000000000012511401144015120 5ustar rootrootsoci-3.2.3/backends/postgresql/common.h0000644000000000000000000000645012511361676016605 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_POSTGRESQL_COMMON_H_INCLUDED #define SOCI_POSTGRESQL_COMMON_H_INCLUDED #include "soci-postgresql.h" #include #include #include #include #include namespace soci { namespace details { namespace postgresql { // helper function for parsing integers template T string_to_integer(char const * buf) { long long t(0); int n(0); int const converted = std::sscanf(buf, "%" LL_FMT_FLAGS "d%n", &t, &n); if (converted == 1 && static_cast(n) == std::strlen(buf)) { // successfully converted to long long // and no other characters were found in the buffer const T max = (std::numeric_limits::max)(); const T min = (std::numeric_limits::min)(); if (t <= static_cast(max) && t >= static_cast(min)) { return static_cast(t); } else { // value out of target range throw soci_error("Cannot convert data."); } } else { // try additional conversion from boolean // (PostgreSQL gives 't' or 'f' for boolean results) if (buf[0] == 't' && buf[1] == '\0') { return static_cast(1); } else if (buf[0] == 'f' && buf[1] == '\0') { return static_cast(0); } else { throw soci_error("Cannot convert data."); } } } // helper function for parsing unsigned integers template T string_to_unsigned_integer(char const * buf) { unsigned long long t(0); int n(0); int const converted = std::sscanf(buf, "%" LL_FMT_FLAGS "u%n", &t, &n); if (converted == 1 && static_cast(n) == std::strlen(buf)) { // successfully converted to unsigned long long // and no other characters were found in the buffer const T max = (std::numeric_limits::max)(); if (t <= static_cast(max)) { return static_cast(t); } else { // value out of target range throw soci_error("Cannot convert data."); } } else { // try additional conversion from boolean // (PostgreSQL gives 't' or 'f' for boolean results) if (buf[0] == 't' && buf[1] == '\0') { return static_cast(1); } else if (buf[0] == 'f' && buf[1] == '\0') { return static_cast(0); } else { throw soci_error("Cannot convert data."); } } } // helper function for parsing doubles double string_to_double(char const * buf); // helper function for parsing datetime values void parse_std_tm(char const * buf, std::tm & t); // helper for vector operations template std::size_t get_vector_size(void * p) { std::vector * v = static_cast *>(p); return v->size(); } } // namespace postgresql } // namespace details } // namespace soci #endif // SOCI_POSTGRESQL_COMMON_H_INCLUDED soci-3.2.3/backends/postgresql/blob.cpp0000644000000000000000000000544412511361676016570 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_POSTGRESQL_SOURCE #include "soci-postgresql.h" #include // libpq #include #include #include #include #include #ifdef SOCI_POSTGRESQL_NOPARAMS #ifndef SOCI_POSTGRESQL_NOBINDBYNAME #define SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOPARAMS #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; postgresql_blob_backend::postgresql_blob_backend( postgresql_session_backend & session) : session_(session), fd_(-1) { // nothing to do here, the descriptor is open in the postFetch // method of the Into element } postgresql_blob_backend::~postgresql_blob_backend() { lo_close(session_.conn_, fd_); } std::size_t postgresql_blob_backend::get_len() { int const pos = lo_lseek(session_.conn_, fd_, 0, SEEK_END); if (pos == -1) { throw soci_error("Cannot retrieve the size of BLOB."); } return static_cast(pos); } std::size_t postgresql_blob_backend::read( std::size_t offset, char * buf, std::size_t toRead) { int const pos = lo_lseek(session_.conn_, fd_, static_cast(offset), SEEK_SET); if (pos == -1) { throw soci_error("Cannot seek in BLOB."); } int const readn = lo_read(session_.conn_, fd_, buf, toRead); if (readn < 0) { throw soci_error("Cannot read from BLOB."); } return static_cast(readn); } std::size_t postgresql_blob_backend::write( std::size_t offset, char const * buf, std::size_t toWrite) { int const pos = lo_lseek(session_.conn_, fd_, static_cast(offset), SEEK_SET); if (pos == -1) { throw soci_error("Cannot seek in BLOB."); } int const writen = lo_write(session_.conn_, fd_, const_cast(buf), toWrite); if (writen < 0) { throw soci_error("Cannot write to BLOB."); } return static_cast(writen); } std::size_t postgresql_blob_backend::append( char const * buf, std::size_t toWrite) { int const pos = lo_lseek(session_.conn_, fd_, 0, SEEK_END); if (pos == -1) { throw soci_error("Cannot seek in BLOB."); } int const writen = lo_write(session_.conn_, fd_, const_cast(buf), toWrite); if (writen < 0) { throw soci_error("Cannot append to BLOB."); } return static_cast(writen); } void postgresql_blob_backend::trim(std::size_t /* newLen */) { throw soci_error("Trimming BLOBs is not supported."); } soci-3.2.3/backends/postgresql/statement.cpp0000644000000000000000000004213512511401144017635 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_POSTGRESQL_SOURCE #include "soci-postgresql.h" #include #include // libpq #include #include #include #include #include #include #include #ifdef SOCI_POSTGRESQL_NOPARAMS #ifndef SOCI_POSTGRESQL_NOBINDBYNAME #define SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOPARAMS #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; postgresql_statement_backend::postgresql_statement_backend( postgresql_session_backend &session) : session_(session) , rowsAffectedBulk_(-1LL), justDescribed_(false) , hasIntoElements_(false), hasVectorIntoElements_(false) , hasUseElements_(false), hasVectorUseElements_(false) { } postgresql_statement_backend::~postgresql_statement_backend() { if (statementName_.empty() == false) { try { session_.deallocate_prepared_statement(statementName_); } catch (...) { // Don't allow exceptions to escape from dtor. Suppressing them is // not ideal, but terminating the program, as would happen if we're // already unwinding the stack because of a previous exception, // would be even worse. } } } void postgresql_statement_backend::alloc() { // nothing to do here } void postgresql_statement_backend::clean_up() { // 'reset' the value for a // potential new execution. rowsAffectedBulk_ = -1; // nothing to do here } void postgresql_statement_backend::prepare(std::string const & query, statement_type stType) { #ifdef SOCI_POSTGRESQL_NOBINDBYNAME query_ = query; #else // rewrite the query by transforming all named parameters into // the postgresql_ numbers ones (:abc -> $1, etc.) enum { normal, in_quotes, in_name } state = normal; std::string name; int position = 1; for (std::string::const_iterator it = query.begin(), end = query.end(); it != end; ++it) { switch (state) { case normal: if (*it == '\'') { query_ += *it; state = in_quotes; } else if (*it == ':') { // Check whether this is a cast operator (e.g. 23::float) // and treat it as a special case, not as a named binding const std::string::const_iterator next_it = it + 1; if ((next_it != end) && (*next_it == ':')) { query_ += "::"; ++it; } // Check whether this is an assignment(e.g. x:=y) // and treat it as a special case, not as a named binding else if ((next_it != end) && (*next_it == '=')) { query_ += ":="; ++it; } else { state = in_name; } } else // regular character, stay in the same state { query_ += *it; } break; case in_quotes: if (*it == '\'') { query_ += *it; state = normal; } else // regular quoted character { query_ += *it; } break; case in_name: if (std::isalnum(*it) || *it == '_') { name += *it; } else // end of name { names_.push_back(name); name.clear(); std::ostringstream ss; ss << '$' << position++; query_ += ss.str(); query_ += *it; state = normal; // Check whether the named parameter is immediatelly // followed by a cast operator (e.g. :name::float) // and handle the additional colon immediately to avoid // its misinterpretation later on. if (*it == ':') { const std::string::const_iterator next_it = it + 1; if ((next_it != end) && (*next_it == ':')) { query_ += ':'; ++it; } } } break; } } if (state == in_name) { names_.push_back(name); std::ostringstream ss; ss << '$' << position++; query_ += ss.str(); } #endif // SOCI_POSTGRESQL_NOBINDBYNAME #ifndef SOCI_POSTGRESQL_NOPREPARE if (stType == st_repeatable_query) { assert(statementName_.empty()); // Holding the name temporarily in this var because // if it fails to prepare it we can't DEALLOCATE it. std::string statementName = session_.get_next_statement_name(); postgresql_result result( PQprepare(session_.conn_, statementName.c_str(), query_.c_str(), static_cast(names_.size()), NULL)); result.check_for_errors("Cannot prepare statement."); // Now it's safe to save this info. statementName_ = statementName; } stType_ = stType; #endif // SOCI_POSTGRESQL_NOPREPARE } statement_backend::exec_fetch_result postgresql_statement_backend::execute(int number) { // If the statement was "just described", then we know that // it was actually executed with all the use elements // already bound and pre-used. This means that the result of the // query is already on the client side, so there is no need // to re-execute it. if (justDescribed_ == false) { // This object could have been already filled with data before. clean_up(); if (number > 1 && hasIntoElements_) { throw soci_error( "Bulk use with single into elements is not supported."); } // Since the bulk operations are not natively supported by postgresql_, // we have to explicitly loop to achieve the bulk operations. // On the other hand, looping is not needed if there are single // use elements, even if there is a bulk fetch. // We know that single use and bulk use elements in the same query are // not supported anyway, so in the effect the 'number' parameter here // specifies the size of vectors (into/use), but 'numberOfExecutions' // specifies the number of loops that need to be performed. int numberOfExecutions = 1; if (number > 0) { numberOfExecutions = hasUseElements_ ? 1 : number; } if ((useByPosBuffers_.empty() == false) || (useByNameBuffers_.empty() == false)) { if ((useByPosBuffers_.empty() == false) && (useByNameBuffers_.empty() == false)) { throw soci_error( "Binding for use elements must be either by position " "or by name."); } long long rowsAffectedBulkTemp = 0; for (int i = 0; i != numberOfExecutions; ++i) { std::vector paramValues; if (useByPosBuffers_.empty() == false) { // use elements bind by position // the map of use buffers can be traversed // in its natural order for (UseByPosBuffersMap::iterator it = useByPosBuffers_.begin(), end = useByPosBuffers_.end(); it != end; ++it) { char ** buffers = it->second; paramValues.push_back(buffers[i]); } } else { // use elements bind by name for (std::vector::iterator it = names_.begin(), end = names_.end(); it != end; ++it) { UseByNameBuffersMap::iterator b = useByNameBuffers_.find(*it); if (b == useByNameBuffers_.end()) { std::string msg( "Missing use element for bind by name ("); msg += *it; msg += ")."; throw soci_error(msg); } char ** buffers = b->second; paramValues.push_back(buffers[i]); } } #ifdef SOCI_POSTGRESQL_NOPARAMS throw soci_error("Queries with parameters are not supported."); #else #ifdef SOCI_POSTGRESQL_NOPREPARE result_.reset(PQexecParams(session_.conn_, query_.c_str(), static_cast(paramValues.size()), NULL, ¶mValues[0], NULL, NULL, 0)); #else if (stType_ == st_repeatable_query) { // this query was separately prepared result_.reset(PQexecPrepared(session_.conn_, statementName_.c_str(), static_cast(paramValues.size()), ¶mValues[0], NULL, NULL, 0)); } else // stType_ == st_one_time_query { // this query was not separately prepared and should // be executed as a one-time query result_.reset(PQexecParams(session_.conn_, query_.c_str(), static_cast(paramValues.size()), NULL, ¶mValues[0], NULL, NULL, 0)); } #endif // SOCI_POSTGRESQL_NOPREPARE #endif // SOCI_POSTGRESQL_NOPARAMS if (numberOfExecutions > 1) { // there are only bulk use elements (no intos) // preserve the number of rows affected so far. rowsAffectedBulk_ = rowsAffectedBulkTemp; result_.check_for_errors("Cannot execute query."); rowsAffectedBulkTemp += get_affected_rows(); } } rowsAffectedBulk_ = rowsAffectedBulkTemp; if (numberOfExecutions > 1) { // it was a bulk operation result_.reset(); return ef_no_data; } // otherwise (no bulk), follow the code below } else { // there are no use elements // - execute the query without parameter information #ifdef SOCI_POSTGRESQL_NOPREPARE result_.reset(PQexec(session_.conn_, query_.c_str())); #else if (stType_ == st_repeatable_query) { // this query was separately prepared result_.reset(PQexecPrepared(session_.conn_, statementName_.c_str(), 0, NULL, NULL, NULL, 0)); } else // stType_ == st_one_time_query { result_.reset(PQexec(session_.conn_, query_.c_str())); } #endif // SOCI_POSTGRESQL_NOPREPARE } } else { // The optimization based on the existing results // from the row description can be performed only once. // If the same statement is re-executed, // it will be *really* re-executed, without reusing existing data. justDescribed_ = false; } if (result_.check_for_data("Cannot execute query.")) { currentRow_ = 0; rowsToConsume_ = 0; numberOfRows_ = PQntuples(result_); if (numberOfRows_ == 0) { return ef_no_data; } else { if (number > 0) { // prepare for the subsequent data consumption return fetch(number); } else { // execute(0) was meant to only perform the query return ef_success; } } } else { return ef_no_data; } } statement_backend::exec_fetch_result postgresql_statement_backend::fetch(int number) { // Note: This function does not actually fetch anything from anywhere // - the data was already retrieved from the server in the execute() // function, and the actual consumption of this data will take place // in the postFetch functions, called for each into element. // Here, we only prepare for this to happen (to emulate "the Oracle way"). // forward the "cursor" from the last fetch currentRow_ += rowsToConsume_; if (currentRow_ >= numberOfRows_) { // all rows were already consumed return ef_no_data; } else { if (currentRow_ + number > numberOfRows_) { rowsToConsume_ = numberOfRows_ - currentRow_; // this simulates the behaviour of Oracle // - when EOF is hit, we return ef_no_data even when there are // actually some rows fetched return ef_no_data; } else { rowsToConsume_ = number; return ef_success; } } } long long postgresql_statement_backend::get_affected_rows() { // PQcmdTuples() doesn't really modify the result but it takes a non-const // pointer to it, so we can't rely on implicit conversion here. const char * const resultStr = PQcmdTuples(result_.get_result()); char * end; long long result = std::strtoll(resultStr, &end, 0); if (end != resultStr) { return result; } else if (rowsAffectedBulk_ >= 0) { return rowsAffectedBulk_; } else { return -1; } } int postgresql_statement_backend::get_number_of_rows() { return numberOfRows_ - currentRow_; } std::string postgresql_statement_backend::rewrite_for_procedure_call( std::string const & query) { std::string newQuery("select "); newQuery += query; return newQuery; } int postgresql_statement_backend::prepare_for_describe() { execute(1); justDescribed_ = true; int columns = PQnfields(result_); return columns; } void postgresql_statement_backend::describe_column(int colNum, data_type & type, std::string & columnName) { // In postgresql_ column numbers start from 0 int const pos = colNum - 1; unsigned long const typeOid = PQftype(result_, pos); switch (typeOid) { // Note: the following list of OIDs was taken from the pg_type table // we do not claim that this list is exchaustive or even correct. // from pg_type: case 25: // text case 1043: // varchar case 2275: // cstring case 18: // char case 1042: // bpchar case 142: // xml case 114: // json case 17: // bytea case 2950: // uuid type = dt_string; break; case 702: // abstime case 703: // reltime case 1082: // date case 1083: // time case 1114: // timestamp case 1184: // timestamptz case 1266: // timetz type = dt_date; break; case 700: // float4 case 701: // float8 case 1700: // numeric type = dt_double; break; case 16: // bool case 21: // int2 case 23: // int4 case 26: // oid type = dt_integer; break; case 20: // int8 type = dt_long_long; break; default: { int form = PQfformat(result_, pos); int size = PQfsize(result_, pos); if (form == 0 && size == -1) { type = dt_string; } else { std::stringstream message; message << "unknown data type with typelem: " << typeOid << " for colNum: " << colNum << " with name: " << PQfname(result_, pos); throw soci_error(message.str()); } } } columnName = PQfname(result_, pos); } postgresql_standard_into_type_backend * postgresql_statement_backend::make_into_type_backend() { hasIntoElements_ = true; return new postgresql_standard_into_type_backend(*this); } postgresql_standard_use_type_backend * postgresql_statement_backend::make_use_type_backend() { hasUseElements_ = true; return new postgresql_standard_use_type_backend(*this); } postgresql_vector_into_type_backend * postgresql_statement_backend::make_vector_into_type_backend() { hasVectorIntoElements_ = true; return new postgresql_vector_into_type_backend(*this); } postgresql_vector_use_type_backend * postgresql_statement_backend::make_vector_use_type_backend() { hasVectorUseElements_ = true; return new postgresql_vector_use_type_backend(*this); } soci-3.2.3/backends/postgresql/vector-use-type.cpp0000644000000000000000000001551012511361676020720 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_POSTGRESQL_SOURCE #include #include "soci-postgresql.h" #include "common.h" #include // libpq #include #include #include #include #include #include #ifdef SOCI_POSTGRESQL_NOPARAMS #ifndef SOCI_POSTGRESQL_NOBINDBYNAME #define SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOPARAMS #ifdef _MSC_VER #pragma warning(disable:4355 4996) #define snprintf _snprintf #endif using namespace soci; using namespace soci::details; using namespace soci::details::postgresql; void postgresql_vector_use_type_backend::bind_by_pos(int & position, void * data, exchange_type type) { data_ = data; type_ = type; position_ = position++; } void postgresql_vector_use_type_backend::bind_by_name( std::string const & name, void * data, exchange_type type) { data_ = data; type_ = type; name_ = name; } void postgresql_vector_use_type_backend::pre_use(indicator const * ind) { std::size_t const vsize = size(); for (size_t i = 0; i != vsize; ++i) { char * buf; // the data in vector can be either i_ok or i_null if (ind != NULL && ind[i] == i_null) { buf = NULL; } else { // allocate and fill the buffer with text-formatted client data switch (type_) { case x_char: { std::vector * pv = static_cast *>(data_); std::vector & v = *pv; buf = new char[2]; buf[0] = v[i]; buf[1] = '\0'; } break; case x_stdstring: { std::vector * pv = static_cast *>(data_); std::vector & v = *pv; buf = new char[v[i].size() + 1]; std::strcpy(buf, v[i].c_str()); } break; case x_short: { std::vector * pv = static_cast *>(data_); std::vector & v = *pv; std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf = new char[bufSize]; snprintf(buf, bufSize, "%d", static_cast(v[i])); } break; case x_integer: { std::vector * pv = static_cast *>(data_); std::vector & v = *pv; std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf = new char[bufSize]; snprintf(buf, bufSize, "%d", v[i]); } break; case x_long_long: { std::vector* pv = static_cast*>(data_); std::vector& v = *pv; std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf = new char[bufSize]; snprintf(buf, bufSize, "%" LL_FMT_FLAGS "d", v[i]); } break; case x_unsigned_long_long: { std::vector* pv = static_cast*>(data_); std::vector& v = *pv; std::size_t const bufSize = std::numeric_limits::digits10 + 2; buf = new char[bufSize]; snprintf(buf, bufSize, "%" LL_FMT_FLAGS "u", v[i]); } break; case x_double: { // no need to overengineer it (KISS)... std::vector * pv = static_cast *>(data_); std::vector & v = *pv; std::size_t const bufSize = 100; buf = new char[bufSize]; snprintf(buf, bufSize, "%.20g", v[i]); } break; case x_stdtm: { std::vector * pv = static_cast *>(data_); std::vector & v = *pv; std::size_t const bufSize = 20; buf = new char[bufSize]; snprintf(buf, bufSize, "%d-%02d-%02d %02d:%02d:%02d", v[i].tm_year + 1900, v[i].tm_mon + 1, v[i].tm_mday, v[i].tm_hour, v[i].tm_min, v[i].tm_sec); } break; default: throw soci_error( "Use vector element used with non-supported type."); } } buffers_.push_back(buf); } if (position_ > 0) { // binding by position statement_.useByPosBuffers_[position_] = &buffers_[0]; } else { // binding by name statement_.useByNameBuffers_[name_] = &buffers_[0]; } } std::size_t postgresql_vector_use_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type_) { // simple cases case x_char: sz = get_vector_size(data_); break; case x_short: sz = get_vector_size(data_); break; case x_integer: sz = get_vector_size(data_); break; case x_long_long: sz = get_vector_size(data_); break; case x_unsigned_long_long: sz = get_vector_size(data_); break; case x_double: sz = get_vector_size(data_); break; case x_stdstring: sz = get_vector_size(data_); break; case x_stdtm: sz = get_vector_size(data_); break; default: throw soci_error("Use vector element used with non-supported type."); } return sz; } void postgresql_vector_use_type_backend::clean_up() { std::size_t const bsize = buffers_.size(); for (std::size_t i = 0; i != bsize; ++i) { delete [] buffers_[i]; } } soci-3.2.3/backends/postgresql/standard-use-type.cpp0000644000000000000000000001412612511361676021220 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_POSTGRESQL_SOURCE #include "soci-postgresql.h" #include "blob.h" #include "rowid.h" #include #include // libpq #include #include #include #include #include #include #ifdef SOCI_POSTGRESQL_NOPARAMS #ifndef SOCI_POSTGRESQL_NOBINDBYNAME #define SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOPARAMS #ifdef _MSC_VER #pragma warning(disable:4355 4996) #define snprintf _snprintf #endif using namespace soci; using namespace soci::details; void postgresql_standard_use_type_backend::bind_by_pos( int & position, void * data, exchange_type type, bool /* readOnly */) { // readOnly is ignored, because PostgreSQL does not support // any data to be written back to used (bound) objects. data_ = data; type_ = type; position_ = position++; } void postgresql_standard_use_type_backend::bind_by_name( std::string const & name, void * data, exchange_type type, bool /* readOnly */) { // readOnly is ignored, because PostgreSQL does not support // any data to be written back to used (bound) objects. data_ = data; type_ = type; name_ = name; } void postgresql_standard_use_type_backend::pre_use(indicator const * ind) { if (ind != NULL && *ind == i_null) { // leave the working buffer as NULL } else { // allocate and fill the buffer with text-formatted client data switch (type_) { case x_char: { buf_ = new char[2]; buf_[0] = *static_cast(data_); buf_[1] = '\0'; } break; case x_stdstring: { std::string * s = static_cast(data_); buf_ = new char[s->size() + 1]; std::strcpy(buf_, s->c_str()); } break; case x_short: { std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%d", static_cast(*static_cast(data_))); } break; case x_integer: { std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%d", *static_cast(data_)); } break; case x_long_long: { std::size_t const bufSize = std::numeric_limits::digits10 + 3; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%" LL_FMT_FLAGS "d", *static_cast(data_)); } break; case x_unsigned_long_long: { std::size_t const bufSize = std::numeric_limits::digits10 + 2; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%" LL_FMT_FLAGS "u", *static_cast(data_)); } break; case x_double: { // no need to overengineer it (KISS)... std::size_t const bufSize = 100; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%.20g", *static_cast(data_)); } break; case x_stdtm: { std::size_t const bufSize = 20; buf_ = new char[bufSize]; std::tm * t = static_cast(data_); snprintf(buf_, bufSize, "%d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); } break; case x_rowid: { // RowID is internally identical to unsigned long rowid * rid = static_cast(data_); postgresql_rowid_backend * rbe = static_cast( rid->get_backend()); std::size_t const bufSize = std::numeric_limits::digits10 + 2; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%lu", rbe->value_); } break; case x_blob: { blob * b = static_cast(data_); postgresql_blob_backend * bbe = static_cast(b->get_backend()); std::size_t const bufSize = std::numeric_limits::digits10 + 2; buf_ = new char[bufSize]; snprintf(buf_, bufSize, "%lu", bbe->oid_); } break; default: throw soci_error("Use element used with non-supported type."); } } if (position_ > 0) { // binding by position statement_.useByPosBuffers_[position_] = &buf_; } else { // binding by name statement_.useByNameBuffers_[name_] = &buf_; } } void postgresql_standard_use_type_backend::post_use( bool /* gotData */, indicator * /* ind */) { // PostgreSQL does not support any data moving back the same channel, // so there is nothing to do here. // In particular, there is nothing to protect, because both const and non-const // objects will never be modified. // clean up the working buffer, it might be allocated anew in // the next run of preUse clean_up(); } void postgresql_standard_use_type_backend::clean_up() { if (buf_ != NULL) { delete [] buf_; buf_ = NULL; } } soci-3.2.3/backends/postgresql/session.cpp0000644000000000000000000000604212511361676017330 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_POSTGRESQL_SOURCE #include "soci-postgresql.h" #include "session.h" #include #include // libpq #include #include #include #include #include #ifdef SOCI_POSTGRESQL_NOPARAMS #ifndef SOCI_POSTGRESQL_NOBINDBYNAME #define SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOPARAMS #ifdef _MSC_VER #pragma warning(disable:4355 4996) #endif using namespace soci; using namespace soci::details; postgresql_session_backend::postgresql_session_backend( connection_parameters const& parameters) : statementCount_(0) { PGconn* conn = PQconnectdb(parameters.get_connect_string().c_str()); if (0 == conn || CONNECTION_OK != PQstatus(conn)) { std::string msg = "Cannot establish connection to the database."; if (0 != conn) { msg += '\n'; msg += PQerrorMessage(conn); PQfinish(conn); } throw soci_error(msg); } conn_ = conn; } postgresql_session_backend::~postgresql_session_backend() { clean_up(); } namespace // unnamed { // helper function for hardcoded queries void hard_exec(PGconn * conn, char const * query, char const * errMsg) { postgresql_result(PQexec(conn, query)).check_for_errors(errMsg); } } // namespace unnamed void postgresql_session_backend::begin() { hard_exec(conn_, "BEGIN", "Cannot begin transaction."); } void postgresql_session_backend::commit() { hard_exec(conn_, "COMMIT", "Cannot commit transaction."); } void postgresql_session_backend::rollback() { hard_exec(conn_, "ROLLBACK", "Cannot rollback transaction."); } void postgresql_session_backend::deallocate_prepared_statement( const std::string & statementName) { const std::string & query = "DEALLOCATE " + statementName; hard_exec(conn_, query.c_str(), "Cannot deallocate prepared statement."); } bool postgresql_session_backend::get_next_sequence_value( session & s, std::string const & sequence, long & value) { s << "select nextval('" + sequence + "')", into(value); return true; } void postgresql_session_backend::clean_up() { if (0 != conn_) { PQfinish(conn_); conn_ = 0; } } std::string postgresql_session_backend::get_next_statement_name() { char nameBuf[20] = { 0 }; // arbitrary length sprintf(nameBuf, "st_%d", ++statementCount_); return nameBuf; } postgresql_statement_backend * postgresql_session_backend::make_statement_backend() { return new postgresql_statement_backend(*this); } postgresql_rowid_backend * postgresql_session_backend::make_rowid_backend() { return new postgresql_rowid_backend(*this); } postgresql_blob_backend * postgresql_session_backend::make_blob_backend() { return new postgresql_blob_backend(*this); } soci-3.2.3/backends/postgresql/Makefile.basic0000644000000000000000000000611112505151606017647 0ustar rootroot# The following variable is specific to this backend and its correct # values might depend on your environment - feel free to set it accordingly. PGSQLINCLUDEDIR = -I/usr/include PGSQLLIBDIR = -L/usr/lib PGSQLLIBS = -lpq # The rest of the Makefile is indepentent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long SHARED_CXXFLAGS = ${CXXFLAGS} -fPIC INCLUDEDIRS = -I../../core ${PGSQLINCLUDEDIR} SHARED_LIBDIRS = ${PGSQLLIBDIR} SHARED_LIBS = ${PGSQLLIBS} ../../core/libsoci_core.a UNAME = $(shell uname) ifeq ($(UNAME),Darwin) SHARED_LINK_FLAGS = -dynamiclib -flat_namespace -undefined suppress else SHARED_LINK_FLAGS = -shared endif OBJECTS = blob.o error.o factory.o row-id.o session.o standard-into-type.o \ standard-use-type.o statement.o vector-into-type.o vector-use-type.o \ common.o SHARED_OBJECTS = blob-s.o error-s.o factory-s.o row-id-s.o session-s.o \ standard-into-type-s.o standard-use-type-s.o statement-s.o \ vector-into-type-s.o vector-use-type-s.o common-s.o libsoci_postgresql.a : ${OBJECTS} ar rv $@ $? rm *.o blob.o : blob.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} error.o : error.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} common.o : common.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} factory.o : factory.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} row-id.o : row-id.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} session.o : session.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-into-type.o : standard-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} standard-use-type.o : standard-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} statement.o : statement.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-into-type.o : vector-into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} vector-use-type.o : vector-use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} shared : ${SHARED_OBJECTS} ${COMPILER} ${SHARED_LINK_FLAGS} -o libsoci_postgresql.so \ ${SHARED_OBJECTS} ${SHARED_LIBDIRS} ${SHARED_LIBS} rm *.o blob-s.o : blob.cpp ${COMPILER} -c -o $@ $? ${SHARED_CXXFLAGS} ${INCLUDEDIRS} error-s.o : error.cpp ${COMPILER} -c -o $@ $? ${CXXFLAGS} ${INCLUDEDIRS} common-s.o : common.cpp ${COMPILER} -c -o $@ $? ${SHARED_CXXFLAGS} ${INCLUDEDIRS} factory-s.o : factory.cpp ${COMPILER} -c -o $@ $? ${SHARED_CXXFLAGS} ${INCLUDEDIRS} row-id-s.o : row-id.cpp ${COMPILER} -c -o $@ $? ${SHARED_CXXFLAGS} ${INCLUDEDIRS} session-s.o : session.cpp ${COMPILER} -c -o $@ $? ${SHARED_CXXFLAGS} ${INCLUDEDIRS} standard-into-type-s.o : standard-into-type.cpp ${COMPILER} -c -o $@ $? ${SHARED_CXXFLAGS} ${INCLUDEDIRS} standard-use-type-s.o : standard-use-type.cpp ${COMPILER} -c -o $@ $? ${SHARED_CXXFLAGS} ${INCLUDEDIRS} statement-s.o : statement.cpp ${COMPILER} -c -o $@ $? ${SHARED_CXXFLAGS} ${INCLUDEDIRS} vector-into-type-s.o : vector-into-type.cpp ${COMPILER} -c -o $@ $? ${SHARED_CXXFLAGS} ${INCLUDEDIRS} vector-use-type-s.o : vector-use-type.cpp ${COMPILER} -c -o $@ $? ${SHARED_CXXFLAGS} ${INCLUDEDIRS} clean : rm -f libsoci_postgresql.a libsoci_postgresql.so soci-3.2.3/backends/postgresql/error.cpp0000644000000000000000000000341612511361676017000 0ustar rootroot// // Copyright (C) 2011 Gevorg Voskanyan // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_POSTGRESQL_SOURCE #include "soci-postgresql.h" #include "error.h" #include #include using namespace soci; using namespace soci::details; postgresql_soci_error::postgresql_soci_error( std::string const & msg, char const *sqlst) : soci_error(msg) { assert(std::strlen(sqlst) == 5); std::memcpy(sqlstate_, sqlst, 5); } std::string postgresql_soci_error::sqlstate() const { return std::string(sqlstate_, 5); } void details::postgresql_result::check_for_errors(char const* errMsg) const { static_cast(check_for_data(errMsg)); } bool details::postgresql_result::check_for_data(char const* errMsg) const { ExecStatusType const status = PQresultStatus(result_); switch (status) { case PGRES_EMPTY_QUERY: case PGRES_COMMAND_OK: // No data but don't throw neither. return false; case PGRES_TUPLES_OK: return true; default: // Some of the other status codes are not really errors but we're // not prepared to handle them right now and shouldn't ever receive // them so throw nevertheless break; } std::string msg(errMsg); const char* const pqError = PQresultErrorMessage(result_); if (pqError && *pqError) { msg += " "; msg += pqError; } const char* sqlstate = PQresultErrorField(result_, PG_DIAG_SQLSTATE); const char* const blank_sql_state = " "; if (!sqlstate) { sqlstate = blank_sql_state; } throw postgresql_soci_error(msg, sqlstate); } soci-3.2.3/backends/postgresql/factory.cpp0000644000000000000000000000231012511361676017306 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_POSTGRESQL_SOURCE #include "soci-postgresql.h" #include #include // libpq #ifdef SOCI_POSTGRESQL_NOPARAMS #ifndef SOCI_POSTGRESQL_NOBINDBYNAME #define SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOPARAMS #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; // concrete factory for Empty concrete strategies postgresql_session_backend * postgresql_backend_factory::make_session( connection_parameters const & parameters) const { return new postgresql_session_backend(parameters); } postgresql_backend_factory const soci::postgresql; extern "C" { // for dynamic backend loading SOCI_POSTGRESQL_DECL backend_factory const * factory_postgresql() { return &soci::postgresql; } SOCI_POSTGRESQL_DECL void register_factory_postgresql() { soci::dynamic_backends::register_backend("postgresql", soci::postgresql); } } // extern "C" soci-3.2.3/backends/postgresql/row-id.cpp0000644000000000000000000000162312511361676017046 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_POSTGRESQL_SOURCE #include "soci-postgresql.h" #include // libpq #include #include #include #include #include #ifdef SOCI_POSTGRESQL_NOPARAMS #ifndef SOCI_POSTGRESQL_NOBINDBYNAME #define SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOPARAMS #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; postgresql_rowid_backend::postgresql_rowid_backend( postgresql_session_backend & /* session */) { // nothing to do here } postgresql_rowid_backend::~postgresql_rowid_backend() { // nothing to do here } soci-3.2.3/backends/postgresql/standard-into-type.cpp0000644000000000000000000001206212511361676021372 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_POSTGRESQL_SOURCE #include #include "soci-postgresql.h" #include "common.h" #include "rowid.h" #include "blob.h" #include // libpq #include #include #include #include #include #include #ifdef SOCI_POSTGRESQL_NOPARAMS #ifndef SOCI_POSTGRESQL_NOBINDBYNAME #define SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOPARAMS using namespace soci; using namespace soci::details; using namespace soci::details::postgresql; void postgresql_standard_into_type_backend::define_by_pos( int & position, void * data, exchange_type type) { data_ = data; type_ = type; position_ = position++; } void postgresql_standard_into_type_backend::pre_fetch() { // nothing to do here } void postgresql_standard_into_type_backend::post_fetch( bool gotData, bool calledFromFetch, indicator * ind) { if (calledFromFetch == true && gotData == false) { // this is a normal end-of-rowset condition, // no need to do anything (fetch() will return false) return; } if (gotData) { // postgresql_ positions start at 0 int const pos = position_ - 1; // first, deal with indicators if (PQgetisnull(statement_.result_, statement_.currentRow_, pos) != 0) { if (ind == NULL) { throw soci_error( "Null value fetched and no indicator defined."); } *ind = i_null; // no need to convert data if it is null return; } else { if (ind != NULL) { *ind = i_ok; } } // raw data, in text format char const * buf = PQgetvalue(statement_.result_, statement_.currentRow_, pos); switch (type_) { case x_char: { char * dest = static_cast(data_); *dest = *buf; } break; case x_stdstring: { std::string * dest = static_cast(data_); dest->assign(buf); } break; case x_short: { short * dest = static_cast(data_); *dest = string_to_integer(buf); } break; case x_integer: { int * dest = static_cast(data_); *dest = string_to_integer(buf); } break; case x_long_long: { long long * dest = static_cast(data_); *dest = string_to_integer(buf); } break; case x_unsigned_long_long: { unsigned long long * dest = static_cast(data_); *dest = string_to_unsigned_integer(buf); } break; case x_double: { double * dest = static_cast(data_); *dest = string_to_double(buf); } break; case x_stdtm: { // attempt to parse the string and convert to std::tm std::tm * dest = static_cast(data_); parse_std_tm(buf, *dest); } break; case x_rowid: { // RowID is internally identical to unsigned long rowid * rid = static_cast(data_); postgresql_rowid_backend * rbe = static_cast( rid->get_backend()); rbe->value_ = string_to_unsigned_integer(buf); } break; case x_blob: { unsigned long oid = string_to_unsigned_integer(buf); int fd = lo_open(statement_.session_.conn_, oid, INV_READ | INV_WRITE); if (fd == -1) { throw soci_error("Cannot open the blob object."); } blob * b = static_cast(data_); postgresql_blob_backend * bbe = static_cast(b->get_backend()); if (bbe->fd_ != -1) { lo_close(statement_.session_.conn_, bbe->fd_); } bbe->fd_ = fd; bbe->oid_ = oid; } break; default: throw soci_error("Into element used with non-supported type."); } } } void postgresql_standard_into_type_backend::clean_up() { // nothing to do here } soci-3.2.3/backends/postgresql/test/0000755000000000000000000000000012511401144016077 5ustar rootrootsoci-3.2.3/backends/postgresql/test/test-postgresql.cpp0000644000000000000000000005510212511401144021766 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include "soci.h" #include "soci-postgresql.h" #include "common-tests.h" #include #include #include #include #include #include #include #include using namespace soci; using namespace soci::tests; std::string connectString; backend_factory const &backEnd = *soci::factory_postgresql(); // Postgres-specific tests struct oid_table_creator : public table_creator_base { oid_table_creator(session& sql) : table_creator_base(sql) { sql << "create table soci_test (" " id integer," " name varchar(100)" ") with oids"; } }; // ROWID test // Note: in PostgreSQL, there is no ROWID, there is OID. // It is still provided as a separate type for "portability", // whatever that means. void test1() { try { session sql(backEnd, connectString); oid_table_creator tableCreator(sql); sql << "insert into soci_test(id, name) values(7, \'John\')"; rowid rid(sql); sql << "select oid from soci_test where id = 7", into(rid); int id; std::string name; #ifndef SOCI_POSTGRESQL_NOPARAMS sql << "select id, name from soci_test where oid = :rid", into(id), into(name), use(rid); #else // Older PostgreSQL does not support use elements. postgresql_rowid_backend *rbe = static_cast(rid.get_backend()); unsigned long oid = rbe->value_; sql << "select id, name from soci_test where oid = " << oid, into(id), into(name); #endif // SOCI_POSTGRESQL_NOPARAMS assert(id == 7); assert(name == "John"); // Must not cause the application to crash. statement st(sql); st.prepare(""); // Throws an exception in some versions. } catch(...) { } std::cout << "test 1 passed" << std::endl; } // function call test class function_creator : function_creator_base { public: function_creator(session & sql) : function_creator_base(sql) { // before a language can be used it must be defined // if it has already been defined then an error will occur try { sql << "create language plpgsql"; } catch (soci_error const &) {} // ignore if error #ifndef SOCI_POSTGRESQL_NOPARAMS sql << "create or replace function soci_test(msg varchar) " "returns varchar as $$ " "declare x int := 1;" "begin " " return msg; " "end $$ language plpgsql"; #else sql << "create or replace function soci_test(varchar) " "returns varchar as \' " "declare x int := 1;" "begin " " return $1; " "end \' language plpgsql"; #endif } protected: std::string drop_statement() { return "drop function soci_test(varchar)"; } }; void test2() { { session sql(backEnd, connectString); function_creator functionCreator(sql); std::string in("my message"); std::string out; #ifndef SOCI_POSTGRESQL_NOPARAMS statement st = (sql.prepare << "select soci_test(:input)", into(out), use(in, "input")); #else // Older PostgreSQL does not support use elements. statement st = (sql.prepare << "select soci_test(\'" << in << "\')", into(out)); #endif // SOCI_POSTGRESQL_NOPARAMS st.execute(true); assert(out == in); // explicit procedure syntax { std::string in("my message2"); std::string out; #ifndef SOCI_POSTGRESQL_NOPARAMS procedure proc = (sql.prepare << "soci_test(:input)", into(out), use(in, "input")); #else // Older PostgreSQL does not support use elements. procedure proc = (sql.prepare << "soci_test(\'" << in << "\')", into(out)); #endif // SOCI_POSTGRESQL_NOPARAMS proc.execute(true); assert(out == in); } } std::cout << "test 2 passed" << std::endl; } // BLOB test struct blob_table_creator : public table_creator_base { blob_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test (" " id integer," " img oid" ")"; } }; void test3() { { session sql(backEnd, connectString); blob_table_creator tableCreator(sql); char buf[] = "abcdefghijklmnopqrstuvwxyz"; sql << "insert into soci_test(id, img) values(7, lo_creat(-1))"; // in PostgreSQL, BLOB operations must be within transaction block transaction tr(sql); { blob b(sql); sql << "select img from soci_test where id = 7", into(b); assert(b.get_len() == 0); b.write(0, buf, sizeof(buf)); assert(b.get_len() == sizeof(buf)); b.append(buf, sizeof(buf)); assert(b.get_len() == 2 * sizeof(buf)); } { blob b(sql); sql << "select img from soci_test where id = 7", into(b); assert(b.get_len() == 2 * sizeof(buf)); char buf2[100]; b.read(0, buf2, 10); assert(std::strncmp(buf2, "abcdefghij", 10) == 0); } unsigned long oid; sql << "select img from soci_test where id = 7", into(oid); sql << "select lo_unlink(" << oid << ")"; } std::cout << "test 3 passed" << std::endl; } struct longlong_table_creator : table_creator_base { longlong_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val int8)"; } }; // long long test void test4() { { session sql(backEnd, connectString); longlong_table_creator tableCreator(sql); long long v1 = 1000000000000LL; assert(v1 / 1000000 == 1000000); sql << "insert into soci_test(val) values(:val)", use(v1); long long v2 = 0LL; sql << "select val from soci_test", into(v2); assert(v2 == v1); } // vector { session sql(backEnd, connectString); longlong_table_creator tableCreator(sql); std::vector v1; v1.push_back(1000000000000LL); v1.push_back(1000000000001LL); v1.push_back(1000000000002LL); v1.push_back(1000000000003LL); v1.push_back(1000000000004LL); sql << "insert into soci_test(val) values(:val)", use(v1); std::vector v2(10); sql << "select val from soci_test order by val desc", into(v2); assert(v2.size() == 5); assert(v2[0] == 1000000000004LL); assert(v2[1] == 1000000000003LL); assert(v2[2] == 1000000000002LL); assert(v2[3] == 1000000000001LL); assert(v2[4] == 1000000000000LL); } std::cout << "test 4 passed" << std::endl; } // unsigned long long test void test4ul() { { session sql(backEnd, connectString); longlong_table_creator tableCreator(sql); unsigned long long v1 = 1000000000000ULL; assert(v1 / 1000000 == 1000000); sql << "insert into soci_test(val) values(:val)", use(v1); unsigned long long v2 = 0ULL; sql << "select val from soci_test", into(v2); assert(v2 == v1); } } struct boolean_table_creator : table_creator_base { boolean_table_creator(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val boolean)"; } }; void test5() { { session sql(backEnd, connectString); boolean_table_creator tableCreator(sql); int i1 = 0; sql << "insert into soci_test(val) values(:val)", use(i1); int i2 = 7; sql << "select val from soci_test", into(i2); assert(i2 == i1); sql << "update soci_test set val = true"; sql << "select val from soci_test", into(i2); assert(i2 == 1); } std::cout << "test 5 passed" << std::endl; } // dynamic backend test void test6() { try { session sql("nosuchbackend://" + connectString); assert(false); } catch (soci_error const & e) { assert(e.what() == std::string("Failed to open: libsoci_nosuchbackend.so")); } { dynamic_backends::register_backend("pgsql", backEnd); std::vector backends = dynamic_backends::list_all(); assert(backends.size() == 1); assert(backends[0] == "pgsql"); { session sql("pgsql://" + connectString); } dynamic_backends::unload("pgsql"); backends = dynamic_backends::list_all(); assert(backends.empty()); } { session sql("postgresql://" + connectString); } std::cout << "test 6 passed" << std::endl; } void test7() { { session sql(backEnd, connectString); int i; sql << "select 123", into(i); assert(i == 123); try { sql << "select 'ABC'", into (i); assert(false); } catch (soci_error const & e) { assert(e.what() == std::string("Cannot convert data.")); } } std::cout << "test 7 passed" << std::endl; } void test8() { { session sql(backEnd, connectString); assert(sql.get_backend_name() == "postgresql"); } std::cout << "test 8 passed" << std::endl; } // test for double-colon cast in SQL expressions void test9() { { session sql(backEnd, connectString); int a = 123; int b = 0; sql << "select :a::integer", use(a), into(b); assert(b == a); } std::cout << "test 9 passed" << std::endl; } // test for date, time and timestamp parsing void test10() { { session sql(backEnd, connectString); std::string someDate = "2009-06-17 22:51:03.123"; std::tm t1, t2, t3; sql << "select :sd::date, :sd::time, :sd::timestamp", use(someDate, "sd"), into(t1), into(t2), into(t3); // t1 should contain only the date part assert(t1.tm_year == 2009 - 1900); assert(t1.tm_mon == 6 - 1); assert(t1.tm_mday == 17); assert(t1.tm_hour == 0); assert(t1.tm_min == 0); assert(t1.tm_sec == 0); // t2 should contain only the time of day part assert(t2.tm_year == 0); assert(t2.tm_mon == 0); assert(t2.tm_mday == 1); assert(t2.tm_hour == 22); assert(t2.tm_min == 51); assert(t2.tm_sec == 3); // t3 should contain all information assert(t3.tm_year == 2009 - 1900); assert(t3.tm_mon == 6 - 1); assert(t3.tm_mday == 17); assert(t3.tm_hour == 22); assert(t3.tm_min == 51); assert(t3.tm_sec == 3); } std::cout << "test 10 passed" << std::endl; } // test for number of affected rows struct table_creator_for_test11 : table_creator_base { table_creator_for_test11(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val integer)"; } }; void test11() { { session sql(backEnd, connectString); table_creator_for_test11 tableCreator(sql); for (int i = 0; i != 10; i++) { sql << "insert into soci_test(val) values(:val)", use(i); } statement st1 = (sql.prepare << "update soci_test set val = val + 1"); st1.execute(false); assert(st1.get_affected_rows() == 10); statement st2 = (sql.prepare << "delete from soci_test where val <= 5"); st2.execute(false); assert(st2.get_affected_rows() == 5); } std::cout << "test 11 passed" << std::endl; } // test INSERT INTO ... RETURNING syntax struct table_creator_for_test12 : table_creator_base { table_creator_for_test12(session & sql) : table_creator_base(sql) { sql << "create table soci_test(sid serial, txt text)"; } }; void test12() { { session sql(backEnd, connectString); table_creator_for_test12 tableCreator(sql); std::vector ids(10); for (std::size_t i = 0; i != ids.size(); i++) { long sid(0); std::string txt("abc"); sql << "insert into soci_test(txt) values(:txt) returning sid", use(txt, "txt"), into(sid); ids[i] = sid; } std::vector ids2(ids.size()); sql << "select sid from soci_test order by sid", into(ids2); assert(std::equal(ids.begin(), ids.end(), ids2.begin())); } std::cout << "test 12 passed" << std::endl; } struct bytea_table_creator : public table_creator_base { bytea_table_creator(session& sql) : table_creator_base(sql) { sql << "drop table if exists soci_test;"; sql << "create table soci_test ( val bytea null )"; } }; void test_bytea() { { session sql(backEnd, connectString); bytea_table_creator tableCreator(sql); int v = 0x0A0B0C0D; unsigned char* b = reinterpret_cast(&v); std::string data; std::copy(b, b + sizeof(v), std::back_inserter(data)); { sql << "insert into soci_test(val) values(:val)", use(data); // 1) into string, no Oid mapping std::string bin1; sql << "select val from soci_test", into(bin1); assert(bin1 == "\\x0d0c0b0a"); // 2) Oid-to-dt_string mapped row r; sql << "select * from soci_test", into(r); assert(r.size() == 1); column_properties const& props = r.get_properties(0); assert(props.get_data_type() == soci::dt_string); std::string bin2 = r.get(0); assert(bin2 == "\\x0d0c0b0a"); } } std::cout << "test bytea passed" << std::endl; } // json struct table_creator_json : public table_creator_base { table_creator_json(session& sql) : table_creator_base(sql) { sql << "drop table if exists soci_json_test;"; sql << "create table soci_json_test(data json)"; } }; // Return 9,2 for 9.2.3 typedef std::pair server_version; server_version get_postgresql_version(session& sql) { std::string version; std::pair result; sql << "select version()",into(version); if (sscanf(version.c_str(),"PostgreSQL %i.%i", &result.first, &result.second) < 2) { throw std::runtime_error("Failed to retrieve PostgreSQL version number"); } return result; } // Test JSON. Only valid for PostgreSQL Server 9.2++ void test_json() { session sql(backEnd, connectString); server_version version = get_postgresql_version(sql); if ( version >= server_version(9,2)) { bool exception = false; std::string result; std::string valid_input = "{\"tool\":\"soci\",\"result\":42}"; std::string invalid_input = "{\"tool\":\"other\",\"result\":invalid}"; table_creator_json tableCreator(sql); sql << "insert into soci_json_test (data) values(:data)",use(valid_input); sql << "select data from soci_json_test",into(result); assert(result == valid_input); try { sql << "insert into soci_json_test (data) values(:data)",use(invalid_input); } catch(soci_error& e) { (void)e; exception = true; } assert(exception); std::cout << "test json passed" << std::endl; } else { std::cout << "test json skipped (PostgreSQL >= 9.2 required, found " << version.first << "." << version.second << ")" << std::endl; } } struct table_creator_text : public table_creator_base { table_creator_text(session& sql) : table_creator_base(sql) { sql << "drop table if exists soci_test;"; sql << "create table soci_test(name varchar(20))"; } }; // Test deallocate_prepared_statement called for non-existing statement // which creation failed due to invalid SQL syntax. // https://github.com/SOCI/soci/issues/116 void test_statement_prepare_failure() { { session sql(backEnd, connectString); table_creator_text tableCreator(sql); try { // types mismatch should lead to PQprepare failure statement get_trades = (sql.prepare << "select * from soci_test where name=9999"); assert(false); } catch(soci_error const& e) { std::string const msg(e.what()); // poor-man heuristics assert(msg.find("prepared statement") == std::string::npos); assert(msg.find("operator does not exist") != std::string::npos); } } std::cout << "test_statement_prepare_failure passed" << std::endl; } // Test the support of PostgreSQL-style casts with ORM void test_orm_cast() { session sql(backEnd, connectString); values v; v.set("a", 1); sql << "select :a::int", use(v); // Must not throw an exception! } struct table_creator_for_uuid_column_type_support : table_creator_base { table_creator_for_uuid_column_type_support(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val uuid)"; } }; void try_one_uuid_format(session& sql, const std::string& uuid, const std::string& uuidExpected) { sql << "insert into soci_test(val) values(:val)", use(uuid); // 1) into string, no Oid mapping std::string uuid1; sql << "select val from soci_test", into(uuid1); assert(uuid1 == uuidExpected); // 2) Oid-to-dt_string mapped row r; sql << "select * from soci_test", into(r); assert(r.size() == 1); column_properties const& props = r.get_properties(0); assert(props.get_data_type() == soci::dt_string); std::string uuid2 = r.get(0); assert(uuid2 == uuidExpected); } void test_uuid_column_type_support() { { session sql(backEnd, connectString); table_creator_for_uuid_column_type_support tableCreator(sql); static const std::string standardUuid("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"); std::vector uuidFormats; uuidFormats.push_back(standardUuid); uuidFormats.push_back("A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11"); uuidFormats.push_back("{a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}"); uuidFormats.push_back("a0eebc999c0b4ef8bb6d6bb9bd380a11"); uuidFormats.push_back("a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11"); uuidFormats.push_back("{a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}"); std::vector::const_iterator it = uuidFormats.begin(); while (it != uuidFormats.end()) { std::string uuid = *it++; try_one_uuid_format(sql, uuid, standardUuid); } } std::cout << "test uuid passed" << std::endl; } // // Support for soci Common Tests // // DDL Creation objects for common tests struct table_creator_one : public table_creator_base { table_creator_one(session & sql) : table_creator_base(sql) { sql << "create table soci_test(id integer, val integer, c char, " "str varchar(20), sh int2, ul numeric(20), d float8, " "tm timestamp, i1 integer, i2 integer, i3 integer, " "name varchar(20))"; } }; struct table_creator_two : public table_creator_base { table_creator_two(session & sql) : table_creator_base(sql) { sql << "create table soci_test(num_float float8, num_int integer," " name varchar(20), sometime timestamp, chr char)"; } }; struct table_creator_three : public table_creator_base { table_creator_three(session & sql) : table_creator_base(sql) { sql << "create table soci_test(name varchar(100) not null, " "phone varchar(15))"; } }; struct table_creator_for_get_affected_rows : table_creator_base { table_creator_for_get_affected_rows(session & sql) : table_creator_base(sql) { sql << "create table soci_test(val integer)"; } }; // Common tests context class test_context : public test_context_base { public: test_context(backend_factory const &backEnd, std::string const &connectString) : test_context_base(backEnd, connectString) {} table_creator_base* table_creator_1(session& s) const { return new table_creator_one(s); } table_creator_base* table_creator_2(session& s) const { return new table_creator_two(s); } table_creator_base* table_creator_3(session& s) const { return new table_creator_three(s); } table_creator_base* table_creator_4(session& s) const { return new table_creator_for_get_affected_rows(s); } std::string to_date_time(std::string const &datdt_string) const { return "timestamptz(\'" + datdt_string + "\')"; } }; int main(int argc, char** argv) { #ifdef _MSC_VER // Redirect errors, unrecoverable problems, and assert() failures to STDERR, // instead of debug message window. // This hack is required to run asser()-driven tests by Buildbot. // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); #endif //_MSC_VER if (argc == 2) { connectString = argv[1]; } else { std::cout << "usage: " << argv[0] << " connectstring\n" << "example: " << argv[0] << " \'connect_string_for_PostgreSQL\'\n"; return EXIT_FAILURE; } try { test_context tc(backEnd, connectString); common_tests tests(tc); tests.run(); std::cout << "\nSOCI PostgreSQL Tests:\n\n"; test1(); test2(); test3(); test4(); test4ul(); test5(); //test6(); std::cout << "test 6 skipped (dynamic backend)\n"; test7(); test8(); test9(); test10(); test11(); test12(); test_bytea(); test_json(); test_statement_prepare_failure(); test_orm_cast(); test_uuid_column_type_support(); std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; } catch (std::exception const & e) { std::cout << e.what() << '\n'; } return EXIT_FAILURE; } soci-3.2.3/backends/postgresql/test/.gitignore0000644000000000000000000000002012511361676020076 0ustar rootroottest_postgresql soci-3.2.3/backends/postgresql/test/Makefile.basic0000644000000000000000000000123312511361676020635 0ustar rootroot# The following variable is specific to this backend and its correct # values might depend on your environment - feel free to set it accordingly. PGSQLINCLUDEDIR = -I/usr/include PGSQLLIBDIR = -L/usr/lib PGSQLLIBS = -lpq # The rest of the Makefile is indepentent of the target environment. COMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long INCLUDEDIRS = -I.. -I../../../core/test -I../../../core ${PGSQLINCLUDEDIR} LIBDIRS = -L.. -L../../../core ${PGSQLLIBDIR} LIBS = -lsoci_core -lsoci_postgresql -ldl ${PGSQLLIBS} test-postgresql : test-postgresql.cpp ${COMPILER} -o $@ $? ${CXXFLAGS} ${INCLUDEDIRS} ${LIBDIRS} ${LIBS} clean : rm -f test-postgresql soci-3.2.3/backends/postgresql/test/CMakeLists.txt0000644000000000000000000000101412511361676020652 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### soci_backend_test( BACKEND PostgreSQL SOURCE test-postgresql.cpp CONNSTR "dummy")soci-3.2.3/backends/postgresql/common.cpp0000644000000000000000000000504412511361676017136 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #include #include "common.h" namespace // anonymous { // helper function for parsing decimal data (for std::tm) long parse10(char const * & p1, char * & p2, char const * msg) { long v = std::strtol(p1, &p2, 10); if (p2 != p1) { p1 = p2 + 1; return v; } else { throw soci::soci_error(msg); } } } // namespace anonymous void soci::details::postgresql::parse_std_tm(char const * buf, std::tm & t) { char const * p1 = buf; char * p2; char separator; long a, b, c; long year = 1900, month = 1, day = 1; long hour = 0, minute = 0, second = 0; char const * errMsg = "Cannot convert data to std::tm."; a = parse10(p1, p2, errMsg); separator = *p2; b = parse10(p1, p2, errMsg); c = parse10(p1, p2, errMsg); if (*p2 == ' ') { // there are more elements to parse // - assume that what was already parsed is a date part // and that the remaining elements describe the time of day year = a; month = b; day = c; hour = parse10(p1, p2, errMsg); minute = parse10(p1, p2, errMsg); second = parse10(p1, p2, errMsg); } else { // only three values have been parsed if (separator == '-') { // assume the date value was read // (leave the time of day as 00:00:00) year = a; month = b; day = c; } else { // assume the time of day was read // (leave the date part as 1900-01-01) hour = a; minute = b; second = c; } } t.tm_isdst = -1; t.tm_year = year - 1900; t.tm_mon = month - 1; t.tm_mday = day; t.tm_hour = hour; t.tm_min = minute; t.tm_sec = second; std::mktime(&t); } double soci::details::postgresql::string_to_double(char const * buf) { double t; int n; int const converted = sscanf(buf, "%lf%n", &t, &n); if (converted == 1 && static_cast(n) == strlen(buf)) { // successfully converted to double // and no other characters were found in the buffer return t; } else { throw soci_error("Cannot convert data."); } } soci-3.2.3/backends/postgresql/vector-into-type.cpp0000644000000000000000000001477512511361676021111 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_POSTGRESQL_SOURCE #include #include "soci-postgresql.h" #include "common.h" #include // libpq #include #include #include #include #include #include #ifdef SOCI_POSTGRESQL_NOPARAMS #ifndef SOCI_POSTGRESQL_NOBINDBYNAME #define SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOBINDBYNAME #endif // SOCI_POSTGRESQL_NOPARAMS using namespace soci; using namespace soci::details; using namespace soci::details::postgresql; void postgresql_vector_into_type_backend::define_by_pos( int & position, void * data, exchange_type type) { data_ = data; type_ = type; position_ = position++; } void postgresql_vector_into_type_backend::pre_fetch() { // nothing to do here } namespace // anonymous { template void set_invector_(void * p, int indx, T const & val) { std::vector * dest = static_cast *>(p); std::vector & v = *dest; v[indx] = val; } } // namespace anonymous void postgresql_vector_into_type_backend::post_fetch(bool gotData, indicator * ind) { if (gotData) { // Here, rowsToConsume_ in the Statement object designates // the number of rows that need to be put in the user's buffers. // postgresql_ column positions start at 0 int const pos = position_ - 1; int const endRow = statement_.currentRow_ + statement_.rowsToConsume_; for (int curRow = statement_.currentRow_, i = 0; curRow != endRow; ++curRow, ++i) { // first, deal with indicators if (PQgetisnull(statement_.result_, curRow, pos) != 0) { if (ind == NULL) { throw soci_error( "Null value fetched and no indicator defined."); } ind[i] = i_null; // no need to convert data if it is null, go to next row continue; } else { if (ind != NULL) { ind[i] = i_ok; } } // buffer with data retrieved from server, in text format char * buf = PQgetvalue(statement_.result_, curRow, pos); switch (type_) { case x_char: set_invector_(data_, i, *buf); break; case x_stdstring: set_invector_(data_, i, buf); break; case x_short: { short const val = string_to_integer(buf); set_invector_(data_, i, val); } break; case x_integer: { int const val = string_to_integer(buf); set_invector_(data_, i, val); } break; case x_long_long: { long long const val = string_to_integer(buf); set_invector_(data_, i, val); } break; case x_unsigned_long_long: { unsigned long long const val = string_to_unsigned_integer(buf); set_invector_(data_, i, val); } break; case x_double: { double const val = string_to_double(buf); set_invector_(data_, i, val); } break; case x_stdtm: { // attempt to parse the string and convert to std::tm std::tm t; parse_std_tm(buf, t); set_invector_(data_, i, t); } break; default: throw soci_error("Into element used with non-supported type."); } } } else // no data retrieved { // nothing to do, into vectors are already truncated } } namespace // anonymous { template void resizevector_(void * p, std::size_t sz) { std::vector * v = static_cast *>(p); v->resize(sz); } } // namespace anonymous void postgresql_vector_into_type_backend::resize(std::size_t sz) { assert(sz < 10u*std::numeric_limits::max()); // Not a strong constraint, for debugging only. Notice my fix is even worse switch (type_) { // simple cases case x_char: resizevector_(data_, sz); break; case x_short: resizevector_(data_, sz); break; case x_integer: resizevector_(data_, sz); break; case x_long_long: resizevector_(data_, sz); break; case x_unsigned_long_long: resizevector_(data_, sz); break; case x_double: resizevector_(data_, sz); break; case x_stdstring: resizevector_(data_, sz); break; case x_stdtm: resizevector_(data_, sz); break; default: throw soci_error("Into vector element used with non-supported type."); } } std::size_t postgresql_vector_into_type_backend::size() { std::size_t sz = 0; // dummy initialization to please the compiler switch (type_) { // simple cases case x_char: sz = get_vector_size(data_); break; case x_short: sz = get_vector_size(data_); break; case x_integer: sz = get_vector_size(data_); break; case x_long_long: sz = get_vector_size(data_); break; case x_unsigned_long_long: sz = get_vector_size(data_); break; case x_double: sz = get_vector_size(data_); break; case x_stdstring: sz = get_vector_size(data_); break; case x_stdtm: sz = get_vector_size(data_); break; default: throw soci_error("Into vector element used with non-supported type."); } return sz; } void postgresql_vector_into_type_backend::clean_up() { // nothing to do here } soci-3.2.3/backends/postgresql/soci-postgresql.h0000644000000000000000000002503412511362240020436 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Copyright (C) 2011 Gevorg Voskanyan // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_POSTGRESQL_H_INCLUDED #define SOCI_POSTGRESQL_H_INCLUDED #ifdef _WIN32 # ifdef SOCI_DLL # ifdef SOCI_POSTGRESQL_SOURCE # define SOCI_POSTGRESQL_DECL __declspec(dllexport) # else # define SOCI_POSTGRESQL_DECL __declspec(dllimport) # endif // SOCI_POSTGRESQL_SOURCE # endif // SOCI_DLL #endif // _WIN32 // // If SOCI_POSTGRESQL_DECL isn't defined yet define it now #ifndef SOCI_POSTGRESQL_DECL # define SOCI_POSTGRESQL_DECL #endif #include #include #include #ifdef _MSC_VER #pragma warning(disable:4512 4511) #endif namespace soci { class postgresql_soci_error : public soci_error { public: postgresql_soci_error(std::string const & msg, char const * sqlst); std::string sqlstate() const; private: char sqlstate_[ 5 ]; // not std::string to keep copy-constructor no-throw }; namespace details { // A class thinly encapsulating PGresult. Its main purpose is to ensure that // PQclear() is always called, avoiding result memory leaks. class postgresql_result { public: // Creates a wrapper for the given, possibly NULL, result. The wrapper // object takes ownership of the object and will call PQclear() on it. explicit postgresql_result(PGresult* result = NULL) { init(result); } // Frees any currently stored result pointer and takes ownership of the // given one. void reset(PGresult* result = NULL) { free(); init(result); } // Check whether the status is PGRES_COMMAND_OK and throw an exception if // it is different. Notice that if the query can return any results, // check_for_data() below should be used instead to verify whether anything // was returned or not. // // The provided error message is used only for the exception being thrown // and should describe the operation which yielded this result. void check_for_errors(char const* errMsg) const; // Check whether the status indicates successful query completion, either // with the return results (in which case true is returned) or without them // (then false is returned). If the status corresponds to an error, throws // an exception, just as check_for_errors(). bool check_for_data(char const* errMsg) const; // Implicit conversion to const PGresult: this is somewhat dangerous but // allows us to avoid changing the existing code that uses PGresult and // avoids the really bad problem with calling PQclear() twice accidentally // as this would require a conversion to non-const pointer that we do not // provide. operator const PGresult*() const { return result_; } // Get the associated result (which may be NULL). Unlike the implicit // conversion above, this one returns a non-const pointer, so you should be // careful to avoid really modifying it. PGresult* get_result() const { return result_; } // Dtor frees the result. ~postgresql_result() { free(); } private: void init(PGresult* result) { result_ = result; } void free() { // Notice that it is safe to call PQclear() with NULL pointer, it // simply does nothing in this case. PQclear(result_); } PGresult* result_; // This class can't be copied as it owns result_ which can't be duplicated. postgresql_result(postgresql_result const &); postgresql_result& operator=(postgresql_result const &); }; } // namespace details struct postgresql_statement_backend; struct postgresql_standard_into_type_backend : details::standard_into_type_backend { postgresql_standard_into_type_backend(postgresql_statement_backend & st) : statement_(st) {} virtual void define_by_pos(int & position, void * data, details::exchange_type type); virtual void pre_fetch(); virtual void post_fetch(bool gotData, bool calledFromFetch, indicator * ind); virtual void clean_up(); postgresql_statement_backend & statement_; void * data_; details::exchange_type type_; int position_; }; struct postgresql_vector_into_type_backend : details::vector_into_type_backend { postgresql_vector_into_type_backend(postgresql_statement_backend & st) : statement_(st) {} virtual void define_by_pos(int & position, void * data, details::exchange_type type); virtual void pre_fetch(); virtual void post_fetch(bool gotData, indicator * ind); virtual void resize(std::size_t sz); virtual std::size_t size(); virtual void clean_up(); postgresql_statement_backend & statement_; void * data_; details::exchange_type type_; int position_; }; struct postgresql_standard_use_type_backend : details::standard_use_type_backend { postgresql_standard_use_type_backend(postgresql_statement_backend & st) : statement_(st), position_(0), buf_(NULL) {} virtual void bind_by_pos(int & position, void * data, details::exchange_type type, bool readOnly); virtual void bind_by_name(std::string const & name, void * data, details::exchange_type type, bool readOnly); virtual void pre_use(indicator const * ind); virtual void post_use(bool gotData, indicator * ind); virtual void clean_up(); postgresql_statement_backend & statement_; void * data_; details::exchange_type type_; int position_; std::string name_; char * buf_; }; struct postgresql_vector_use_type_backend : details::vector_use_type_backend { postgresql_vector_use_type_backend(postgresql_statement_backend & st) : statement_(st), position_(0) {} virtual void bind_by_pos(int & position, void * data, details::exchange_type type); virtual void bind_by_name(std::string const & name, void * data, details::exchange_type type); virtual void pre_use(indicator const * ind); virtual std::size_t size(); virtual void clean_up(); postgresql_statement_backend & statement_; void * data_; details::exchange_type type_; int position_; std::string name_; std::vector buffers_; }; struct postgresql_session_backend; struct postgresql_statement_backend : details::statement_backend { postgresql_statement_backend(postgresql_session_backend & session); ~postgresql_statement_backend(); virtual void alloc(); virtual void clean_up(); virtual void prepare(std::string const & query, details::statement_type stType); virtual exec_fetch_result execute(int number); virtual exec_fetch_result fetch(int number); virtual long long get_affected_rows(); virtual int get_number_of_rows(); virtual std::string rewrite_for_procedure_call(std::string const & query); virtual int prepare_for_describe(); virtual void describe_column(int colNum, data_type & dtype, std::string & columnName); virtual postgresql_standard_into_type_backend * make_into_type_backend(); virtual postgresql_standard_use_type_backend * make_use_type_backend(); virtual postgresql_vector_into_type_backend * make_vector_into_type_backend(); virtual postgresql_vector_use_type_backend * make_vector_use_type_backend(); postgresql_session_backend & session_; details::postgresql_result result_; std::string query_; details::statement_type stType_; std::string statementName_; std::vector names_; // list of names for named binds long long rowsAffectedBulk_; // number of rows affected by the last bulk operation int numberOfRows_; // number of rows retrieved from the server int currentRow_; // "current" row number to consume in postFetch int rowsToConsume_; // number of rows to be consumed in postFetch bool justDescribed_; // to optimize row description with immediately // following actual statement execution bool hasIntoElements_; bool hasVectorIntoElements_; bool hasUseElements_; bool hasVectorUseElements_; // the following maps are used for finding data buffers according to // use elements specified by the user typedef std::map UseByPosBuffersMap; UseByPosBuffersMap useByPosBuffers_; typedef std::map UseByNameBuffersMap; UseByNameBuffersMap useByNameBuffers_; }; struct postgresql_rowid_backend : details::rowid_backend { postgresql_rowid_backend(postgresql_session_backend & session); ~postgresql_rowid_backend(); unsigned long value_; }; struct postgresql_blob_backend : details::blob_backend { postgresql_blob_backend(postgresql_session_backend & session); ~postgresql_blob_backend(); virtual std::size_t get_len(); virtual std::size_t read(std::size_t offset, char * buf, std::size_t toRead); virtual std::size_t write(std::size_t offset, char const * buf, std::size_t toWrite); virtual std::size_t append(char const * buf, std::size_t toWrite); virtual void trim(std::size_t newLen); postgresql_session_backend & session_; unsigned long oid_; // oid of the large object int fd_; // descriptor of the large object }; struct postgresql_session_backend : details::session_backend { postgresql_session_backend(connection_parameters const & parameters); ~postgresql_session_backend(); virtual void begin(); virtual void commit(); virtual void rollback(); void deallocate_prepared_statement(const std::string & statementName); virtual bool get_next_sequence_value(session & s, std::string const & sequence, long & value); virtual std::string get_backend_name() const { return "postgresql"; } void clean_up(); virtual postgresql_statement_backend * make_statement_backend(); virtual postgresql_rowid_backend * make_rowid_backend(); virtual postgresql_blob_backend * make_blob_backend(); std::string get_next_statement_name(); int statementCount_; PGconn * conn_; }; struct postgresql_backend_factory : backend_factory { postgresql_backend_factory() {} virtual postgresql_session_backend * make_session( connection_parameters const & parameters) const; }; extern SOCI_POSTGRESQL_DECL postgresql_backend_factory const postgresql; extern "C" { // for dynamic backend loading SOCI_POSTGRESQL_DECL backend_factory const * factory_postgresql(); SOCI_POSTGRESQL_DECL void register_factory_postgresql(); } // extern "C" } // namespace soci #endif // SOCI_POSTGRESQL_H_INCLUDED soci-3.2.3/backends/postgresql/CMakeLists.txt0000644000000000000000000000302512511362240017663 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### include(CMakeDependentOption) option(SOCI_POSTGRESQL_NOPARAMS "Do not use input parameters. PostgreSQL 7.x portability." OFF) option(SOCI_POSTGRESQL_NOBINDBYNAME "Disable query rewriting to native form. PostgreSQL 7.0 portability." OFF) cmake_dependent_option(SOCI_POSTGRESQL_NOPREPARE "Disable prepared statements. Set ON if SOCI_POSTGRESQL_NOBINDBYNAME is ON. PostgreSQL 7.0 portability." ON SOCI_POSTGRESQL_NOBINDBYNAME OFF) if(SOCI_POSTGRESQL_NOPARAMS) add_definitions(-DSOCI_POSTGRESQL_NOPARAMS=1) endif() if(SOCI_POSTGRESQL_NOBINDBYNAME) message("X") add_definitions(-DSOCI_POSTGRESQL_NOBINDBYNAME=1) endif() if(SOCI_POSTGRESQL_NOPREPARE) message("Y") add_definitions(-DSOCI_POSTGRESQL_NOPREPARE=1) endif() soci_backend(PostgreSQL DEPENDS PostgreSQL HEADERS soci-postgresql.h common.h DESCRIPTION "SOCI backend for PostgreSQL database engine" AUTHORS "Maciej Sobczak, Stephen Hutton" MAINTAINERS "Mateusz Loskot") boost_report_value(SOCI_POSTGRESQL_NOPARAMS) boost_report_value(SOCI_POSTGRESQL_NOBINDBYNAME) boost_report_value(SOCI_POSTGRESQL_NOPREPARE) add_subdirectory(test) soci-3.2.3/backends/CMakeLists.txt0000644000000000000000000000252212511362240015461 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### colormsg(_HIBLUE_ "Configuring SOCI database backends:") # First, we'll investigate what can be found from database engines foreach(dep ${SOCI_BACKENDS_DB_DEPENDENCIES}) string(TOUPPER ${dep} depUP) if (WITH_${depUP}) find_package(${dep}) endif() if(${dep}_FOUND OR ${depUP}_FOUND) set(${depUP}_FOUND ON) else() set(${depUP}_FOUND OFF) endif() endforeach() # get all files in backends file(GLOB backend_dirs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *) # empty backend always on by default option(SOCI_EMPTY "Build empty backend" ON) if(SOCI_EMPTY) set(WITH_EMPTY ON) set(EMPTY_FOUND ON) endif() # enable only found backends foreach(dir ${backend_dirs}) if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${dir}) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/CMakeLists.txt) string(TOUPPER ${dir} dirUP) if(${dirUP}_FOUND AND WITH_${dirUP}) add_subdirectory(${dir}) endif() endif() endif() endforeach() message(STATUS "") soci-3.2.3/doc/0000755000000000000000000000000012511401144011710 5ustar rootrootsoci-3.2.3/doc/backends/0000755000000000000000000000000012511401144013462 5ustar rootrootsoci-3.2.3/doc/backends/postgresql.html0000644000000000000000000002305212511401144016555 0ustar rootroot SOCI - PostgreSQL Backend Reference

PostgreSQL Backend Reference

Prerequisites

Supported Versions

The SOCI PostgreSQL backend is supported for use with PostgreSQL >= 7.3, although versions older than 8.0 will suffer from limited feature support. See below for details.

Tested Platforms

PostgreSQL versionOperating SystemCompiler
9.0Mac OS X 10.6.6g++ 4.2
8.4FreeBSD 8.2g++ 4.1
8.4Debian 6g++ 4.3
8.4RedHat 5g++ 4.3

Required Client Libraries

The SOCI PostgreSQL backend requires PostgreSQL's libpq client library.

Note that the SOCI library itself depends also on libdl, so the minimum set of libraries needed to compile a basic client program is:

-lsoci_core -lsoci_postgresql -ldl -lpq

Connecting to the Database

To establish a connection to the PostgreSQL database, create a session object using the postgresql backend factory together with a connection string:

session sql(postgresql, "dbname=mydatabase");

// or:
session sql("postgresql", "dbname=mydatabase");

// or:
session sql("postgresql://dbname=mydatabase");

The set of parameters used in the connection string for PostgreSQL is the same as accepted by the PQconnectdb function from the libpq library.

Once you have created a session object as shown above, you can use it to access the database, for example:

int count;
sql << "select count(*) from invoices", into(count);

(See the SOCI basics and exchanging data documentation for general information on using the session class.)

SOCI Feature Support

Dynamic Binding

The PostgreSQL backend supports the use of the SOCI row class, which facilitates retrieval of data whose type is not known at compile time.

When calling row::get<T>(), the type you should pass as T depends upon the underlying database type.
For the PostgreSQL backend, this type mapping is:

PostgreSQL Data Type SOCI Data Type row::get<T> specializations
numeric, real, double dt_double double
boolean, smallint, integer dt_integer int
int8 dt_long_long long long
oid dt_integer unsigned long
char, varchar, text, cstring, bpchar dt_string std::string
abstime, reltime, date, time, timestamp, timestamptz, timetz dt_date std::tm

(See the dynamic resultset binding documentation for general information on using the row class.)

Binding by Name

In addition to binding by position, the PostgreSQL backend supports binding by name, via an overload of the use() function:

int id = 7;
sql << "select name from person where id = :id", use(id, "id")

Apart from the portable "colon-name" syntax above, which is achieved by rewriting the query string, the backend also supports the PostgreSQL native numbered syntax:

int i = 7;
int j = 8;
sql << "insert into t(x, y) values($1, $2)", use(i), use(j);

The use of native syntax is not recommended, but can be nevertheless imposed by switching off the query rewriting. This can be achieved by defining the macro SOCI_POSTGRESQL_NOBINDBYNAME and it is actually necessary for PostgreSQL 7.3, in which case binding of use elements is not supported at all. See the Configuration options section for details.

Bulk Operations

The PostgreSQL backend has full support for SOCI's bulk operations interface.

Transactions

Transactions are also fully supported by the PostgreSQL backend.

blob Data Type

The PostgreSQL backend supports working with data stored in columns of type Blob, via SOCI's blob class with the exception that trimming is not supported.

rowid Data Type

The concept of row identifier (OID in PostgreSQL) is supported via SOCI's rowid class.

Nested Statements

Nested statements are not supported by PostgreSQL backend.

Stored Procedures

PostgreSQL stored procedures can be executed by using SOCI's procedure class.

Acessing the native database API

SOCI provides access to underlying datbabase APIs via several get_backend() functions, as described in the beyond SOCI documentation.

The PostgreSQL backend provides the following concrete classes for navite API access:

Accessor Function Concrete Class
session_backend * session::get_backend() postgresql_session_backend
statement_backend * statement::get_backend() postgresql_statement_backend
blob_backend * blob::get_backend() postgresql_blob_backend
rowid_backend * rowid::get_backend() postgresql_rowid_backend

Backend-specific extensions

uuid Data Type

The PostgreSQL backend supports working with data stored in columns of type UUID via simple string operations. All string representations of UUID supported by PostgreSQL are accepted on input, the backend will return the standard format of UUID on output. See the test test_uuid_column_type_support for usage examples.

Configuration options

To support older PostgreSQL versions, the following configuration macros are recognized:

  • SOCI_POSTGRESQL_NOBINDBYNAME - switches off the query rewriting.
  • SOCI_POSTGRESQL_NOPARAMS - disables support for parameterized queries (binding of use elements), automatically imposes also the SOCI_POSTGRESQL_NOBINDBYNAME macro. It is necessary for PostgreSQL 7.3.
  • SOCI_POSTGRESQL_NOPREPARE - disables support for separate query preparation, which in this backend is significant only in terms of optimization. It is necessary for PostgreSQL 7.3 and 7.4.
soci-3.2.3/doc/backends/firebird.html0000644000000000000000000002210512511362240016141 0ustar rootroot SOCI - Firebird Backend Reference

Firebird Backend Reference

Prerequisites

Supported Versions

The SOCI Firebird backend is currently supported for use with Firebird 1.5.
Other versions of Firebird may work as well, but they have not been tested by the SOCI team.

Tested Platforms

Firebird versionOperating SystemCompiler
1.5.2.4731SunOS 5.10g++ 3.4.3
1.5.2.4731Windows XPVisual C++ 8.0
1.5.3.4870Windows XPVisual C++ 8.0 Professional

Required Client Libraries

The Firebird backend requires Firebird's libfbclient client library.

Connecting to the Database

To establish a connection to a Firebird database, create a Session object using the firebird backend factory together with a connection string:

BackEndFactory const &backEnd = firebird;
Session sql(backEnd, 
        "service=/usr/local/firbird/db/test.fdb user=SYSDBA password=masterkey");

or simply:

Session sql(firebird, 
        "service=/usr/local/firbird/db/test.fdb user=SYSDBA password=masterkey");

The set of parameters used in the connection string for Firebird is:

  • service
  • user
  • password
  • role
  • charset

The following parameters have to be provided as part of the connection string : service, user, password. Role and charset parameters are optional.

Once you have created a Session object as shown above, you can use it to access the database, for example:

int count;
sql << "select count(*) from user_tables", into(count);

(See the SOCI basics and exchanging data documentation for general information on using the Session class.)

SOCI Feature Support

Dynamic Binding

The Firebird backend supports the use of the SOCI Row class, which facilitates retrieval of data whose type is not known at compile time.

When calling Row::get<T>(), the type you should pass as T depends upon the underlying database type. For the Firebird backend, this type mapping is:

Firebird Data Type SOCI Data Type Row::get<T> specializations
numeric, decimal
(where scale > 0)
eDouble double
numeric, decimal [1]
(where scale = 0)
eInteger, eDouble int, double
double precision, float eDouble double
smallint, integer eInteger int
char, varchar eString std::string
date, time, timestamp eDate std::tm

 [1]  There is also 64bit integer type for larger values which is currently not supported.

(See the dynamic resultset binding documentation for general information on using the Row class.)

Binding by Name

In addition to binding by position, the Firebird backend supports binding by name, via an overload of the use() function:

int id = 7;
sql << "select name from person where id = :id", use(id, "id")

It should be noted that parameter binding by name is supported only by means of emulation, since the underlying API used by the backend doesn't provide this feature.

Bulk Operations

The Firebird backend has full support for SOCI's bulk operations interface. This feature is also supported by emulation.

Transactions

Transactions are also fully supported by the Firebird backend. In fact, there is always a transaction which is automatically commited in Session's destructor.
See the Configuration options section for more details.

BLOB Data Type

The Firebird backend supports working with data stored in columns of type Blob, via SOCI's BLOB class.

It should by noted, that entire Blob data is fetched from database to allow random read and write access. This is because Firebird itself allows only writing to a new Blob or reading from existing one - modifications of existing Blob means creating a new one. Firebird backend hides those details from user.

RowID Data Type

This feature is not supported by Firebird backend.

Nested Statements

This feature is not supported by Firebird backend.

Stored Procedures

Firebird stored procedures can be executed by using SOCI's Procedure class.

Acessing the native database API

SOCI provides access to underlying datbabase APIs via several getBackEnd() functions, as described in the beyond SOCI documentation.

The Firebird backend provides the following concrete classes for navite API access:

Accessor Function Concrete Class
SessionBackEnd* Session::getBackEnd() FirebirdSessionBackEnd
StatementBackEnd* Statement::getBackEnd() FirebirdStatementBackEnd
BLOBBackEnd* BLOB::getBackEnd() FirebirdBLOBBackEnd
RowIDBackEnd* RowID::getBackEnd() FirebirdRowIDBackEnd

Backend-specific extensions

FirebirdSOCIError

The Firebird backend can throw instances of class FirebirdSOCIError, which is publicly derived from SOCIError and has an additional public status_ member containing the Firebird status vector.

Configuration options

The Firebird backend recognize the following configuration macros :

  • SOCI_FIREBIRD_NORESTARTTRANSACTION - Transactions will not be restarted automatically after commit() or rollback(). The default is to restart transactions.
soci-3.2.3/doc/backends/oracle.html0000644000000000000000000002221712511362240015624 0ustar rootroot SOCI - Oracle Backend Reference

Oracle Backend Reference

Prerequisites

Supported Versions

The SOCI Oracle backend is currently supported for use with Oracle 10 or later.
Older versions of Oracle may work as well, but they have not been tested by the SOCI team.

Tested Platforms

Oracle versionOperating SystemCompiler
10.2.0 (XE)RedHat 5g++ 4.3

Required Client Libraries

The SOCI Oracle backend requires Oracle's libclntsh client library. Depending on the particular system, the libnnz10 library might be needed as well.

Note that the SOCI library itself depends also on libdl, so the minimum set of libraries needed to compile a basic client program is:

-lsoci_core -lsoci_oracle -ldl -lclntsh -lnnz10

Connecting to the Database

To establish a connection to an Oracle database, create a session object using the oracle backend factory together with a connection string:

session sql(oracle, "service=orcl user=scott password=tiger");

// or:
session sql("oracle", "service=orcl user=scott password=tiger");

// or:
session sql("oracle://service=orcl user=scott password=tiger");

The set of parameters used in the connection string for Oracle is:

  • service
  • user
  • password
  • mode (optional)

The first 3 of these parameters have to be provided as part of the connection string.

The mode parameter allows to specify the connection mode and can be any of:

  • default (which is assumed if omitted)
  • sysdba
  • sysoper

Once you have created a session object as shown above, you can use it to access the database, for example:

int count;
sql << "select count(*) from user_tables", into(count);

(See the SOCI basics and exchanging data documentation for general information on using the session class.)

SOCI Feature Support

Dynamic Binding

The Oracle backend supports the use of the SOCI row class, which facilitates retrieval of data which type is not known at compile time.

When calling row::get<T>(), the type you should pass as T depends upon the underlying database type.
For the Oracle backend, this type mapping is:

Oracle Data Type SOCI Data Type row::get<T> specializations
number (where scale > 0) dt_double double
number
(where scale = 0 and precision ≤ std::numeric_limits<int>::digits10)
dt_integer int
number dt_long_long long long
char, varchar, varchar2 dt_string std::string
date dt_date std::tm

(See the dynamic resultset binding documentation for general information on using the row class.)

Binding by Name

In addition to binding by position, the Oracle backend supports binding by name, via an overload of the use() function:

int id = 7;
sql << "select name from person where id = :id", use(id, "id")

SOCI's use of ':' to indicate a value to be bound within a SQL string is consistant with the underlying Oracle client library syntax.

Bulk Operations

The Oracle backend has full support for SOCI's bulk operations interface.

Transactions

Transactions are also fully supported by the Oracle backend, although transactions with non-default isolation levels have to be managed by explicit SQL statements.

blob Data Type

The Oracle backend supports working with data stored in columns of type Blob, via SOCI's blob class.

rowid Data Type

Oracle rowid's are accessible via SOCI's rowid class.

Nested Statements

The Oracle backend supports selecting into objects of type statement, so that you may work with nested sql statements and PL/SQL cursors:

statement stInner(sql);
statement stOuter = (sql.prepare <<
    "select cursor(select name from person order by id)"
    " from person where id = 1",
    into(stInner));
stInner.exchange(into(name));
stOuter.execute();
stOuter.fetch();

while (stInner.fetch())
{
    std::cout << name << '\n';
}

Stored Procedures

Oracle stored procedures can be executed by using SOCI's procedure class.

Acessing the native database API

SOCI provides access to underlying datbabase APIs via several get_backend() functions, as described in the Beyond SOCI documentation.

The Oracle backend provides the following concrete classes for navite API access:

Accessor Function Concrete Class
session_backend * session::get_backend() oracle_session_backend
statement_backend * statement::get_backend() oracle_statement_backend
blob_backend * blob::get_backend() oracle_blob_backend
rowid_backend * rowid::get_backend() oracle_rowid_backend

Backend-specific extensions

eracle=soci_error

The Oracle backend can throw instances of class oracle_soci_error, which is publicly derived from soci_error and has an additional public err_num_ member containing the Oracle error code:

int main()
{
    try
    {
        // regular code
    }
    catch (oracle_soci_error const & e)
    {
        cerr << "Oracle error: " << e.err_num_
            << " " << e.what() << endl;
    }
    catch (exception const &e)
    {
        cerr << "Some other error: " << e.what() << endl;
    }
}
soci-3.2.3/doc/backends/db2.html0000644000000000000000000000704112511362240015024 0ustar rootroot SOCI - DB2 Backend Reference

DB2 Backend Reference

Prerequisites

Supported Versions

The SOCI DB2 backend .

Tested Platforms

DB2 versionOperating SystemCompiler
-Linux PPC64GCC
9.1LinuxGCC
9.5LinuxGCC
9.7LinuxGCC
10.1LinuxGCC
10.1Windows 8Visual Studio 2012

Required Client Libraries

The SOCI DB2 backend requires IBM DB2 Call Level Interface (CLI) library.

Connecting to the Database

On Unix, before using the DB2 backend please make sure, that you have sourced DB2 profile into your environment:

. ~/db2inst1/sqllib/db2profile

To establish a connection to the DB2 database, create a session object using the DB2 backend factory together with the database file name:

soci::session sql(soci::db2, "your DB2 connection string here");

SOCI Feature Support

Dynamic Binding

TODO

Binding by Name

TODO

Bulk Operations

Supported, but with caution as it hasn't been extensively tested.

Transactions

Currently, not supported.

BLOB Data Type

Currently, not supported.

Nested Statements

Nesting statements are not processed by SOCI in any special way and they work as implemented by the DB2 database.

Stored Procedures

Stored procedures are supported, with CALL statement.

Acessing the native database API

TODO

Backend-specific extensions

None.

Configuration options

None

soci-3.2.3/doc/backends/mysql.html0000644000000000000000000002202312511362240015517 0ustar rootroot SOCI - MySQL Backend Reference

MySQL Backend Reference

Prerequisites

Supported Versions

The SOCI MySQL backend should in principle work with every version of MySQL 5.x. Some of the features (transactions, stored functions) are not available when MySQL server doesn't support them.

Tested Platforms

MySQL versionOperating SystemCompiler
5.5.28OS X 10.8.2Apple LLVM version 4.2 (clang-425.0.24)
5.0.96Ubuntu 8.04.4 LTS (Hardy Heron) g++ (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu4)

Required Client Libraries

The SOCI MySQL backend requires MySQL's libmysqlclient client library.

Note that the SOCI library itself depends also on libdl, so the minimum set of libraries needed to compile a basic client program is:

-lsoci_core -lsoci_mysql -ldl -lmysqlclient

Connecting to the Database

To establish a connection to a MySQL server, create a session object using the mysql backend factory together with a connection string:

session sql(mysql, "db=test user=root password='Ala ma kota'");

// or:
session sql("mysql", "db=test user=root password='Ala ma kota'");

// or:
session sql("mysql://db=test user=root password='Ala ma kota'");

The set of parameters used in the connection string for MySQL is:

  • dbname or db or service (required)
  • user
  • password or pass
  • host
  • port
  • unix_socket
  • sslca
  • sslcert
  • local_infile - should be 0 or 1, 1 means MYSQL_OPT_LOCAL_INFILE will be set.
  • charset

Once you have created a session object as shown above, you can use it to access the database, for example:

int count;
sql << "select count(*) from invoices", into(count);

(See the SOCI basics and exchanging data documentation for general information on using the session class.)

SOCI Feature Support

Dynamic Binding

The MySQL backend supports the use of the SOCI row class, which facilitates retrieval of data which type is not known at compile time.

When calling row::get<T>(), the type you should pass as T depends upon the underlying database type.
For the MySQL backend, this type mapping is:

MySQL Data Type SOCI Data Type row::get<T> specializations
FLOAT, DOUBLE, DECIMAL and synonyms dt_double double
TINYINT, TINYINT UNSIGNED, SMALLINT, SMALLINT UNSIGNED, INT dt_integer int
INT UNSIGNED dt_long_long long long or unsigned
BIGINT dt_long_long long long
BIGINT UNSIGNED dt_unsigned_long_long unsigned long long
CHAR, VARCHAR, BINARY, VARBINARY, TINYBLOB, MEDIUMBLOB, BLOB, LONGBLOB, TINYTEXT, MEDIUMTEXT, TEXT, LONGTEXT, ENUM dt_string std::string
TIMESTAMP (works only with MySQL >= 5.0), DATE, TIME, DATETIME dt_date std::tm

(See the dynamic resultset binding documentation for general information on using the Row class.)

Binding by Name

In addition to binding by position, the MySQL backend supports binding by name, via an overload of the use() function:

int id = 7;
sql << "select name from person where id = :id", use(id, "id")

It should be noted that parameter binding of any kind is supported only by means of emulation, since the underlying API used by the backend doesn't provide this feature.

Bulk Operations

The MySQL backend has full support for SOCI's bulk operations interface. This feature is also supported by emulation.

Transactions

Transactions are also supported by the MySQL backend. Please note, however, that transactions can only be used when the MySQL server supports them (it depends on options used during the compilation of the server; typically, but not always, servers >=4.0 support transactions and earlier versions do not) and only with appropriate table types.

BLOB Data Type

SOCI blob interface is not supported by the MySQL backend.

Note that this does not mean you cannot use MySQL's BLOB types. They can be selected using the usual SQL syntax and read into std::string on the C++ side, so no special interface is required.

RowID Data Type

The rowid functionality is not supported by the MySQL backend.

Nested Statements

Nested statements are not supported by the MySQL backend.

Stored Procedures

MySQL version 5.0 and later supports two kinds of stored routines: stored procedures and stored functions (for details, please consult the MySQL documentation). Stored functions can be executed by using SOCI's procedure class. There is currently no support for stored procedures.

Accessing the native database API

SOCI provides access to underlying datbabase APIs via several get_backend() functions, as described in the Beyond SOCI documentation.

The MySQL backend provides the following concrete classes for native API access:

Accessor Function Concrete Class
session_backend * session::get_backend() mysql_session_backend
statement_backend * statement::get_backend() mysql_statement_backend

Backend-specific extensions

None.

Configuration options

None.

soci-3.2.3/doc/backends/odbc.html0000644000000000000000000002402212511362240015262 0ustar rootroot SOCI - ODBC Backend Reference

ODBC Backend Reference

Prerequisites

Supported Versions

The SOCI ODBC backend is supported for use with ODBC 3.

Tested Platforms

ODBC versionOperating SystemCompiler
3Linux (Ubuntu 12.04)g++ 4.6.3
3Linux (Ubuntu 12.04)clang 3.2
3.8Windows 8Visual Studio 2012
3Windows 7Visual Studio 2010
3Windows XPVisual Studio 2005 (express)
3Windows XPVisual C++ 8.0 Professional
3Windows XPg++ 3.3.4 (Cygwin)

Required Client Libraries

The SOCI ODBC backend requires the ODBC client library.

Connecting to the Database

To establish a connection to the ODBC database, create a Session object using the ODBC backend factory together with a connection string:

backend_factory const& backEnd = odbc;
session sql(backEnd, "filedsn=c:\\my.dsn");

or simply:

session sql(odbc, "filedsn=c:\\my.dsn");

The set of parameters used in the connection string for ODBC is the same as accepted by the SQLDriverConnect function from the ODBC library.

Once you have created a session object as shown above, you can use it to access the database, for example:

int count;
sql << "select count(*) from invoices", into(count);

(See the SOCI basics and exchanging data documentation for general information on using the session class.)

SOCI Feature Support

Dynamic Binding

The ODBC backend supports the use of the SOCI row class, which facilitates retrieval of data whose type is not known at compile time.

When calling row::get<T>(), the type you should pass as T depends upon the underlying database type.
For the ODBC backend, this type mapping is:

ODBC Data Type SOCI Data Type row::get<T> specializations
SQL_DOUBLE , SQL_DECIMAL , SQL_REAL , SQL_FLOAT , SQL_NUMERIC dt_double double
SQL_TINYINT , SQL_SMALLINT , SQL_INTEGER , SQL_BIGINT dt_integer int
SQL_CHAR, SQL_VARCHAR dt_string std::string
SQL_TYPE_DATE , SQL_TYPE_TIME , SQL_TYPE_TIMESTAMP dt_date std::tm

Not all ODBC drivers support all datatypes

(See the dynamic resultset binding documentation for general information on using the row class.)

Binding by Name

In addition to binding by position, the ODBC backend supports binding by name, via an overload of the use() function:

int id = 7;
sql << "select name from person where id = :id", use(id, "id")

Apart from the portable "colon-name" syntax above, which is achieved by rewriting the query string, the backend also supports the ODBC ? syntax:

int i = 7;
int j = 8;
sql << "insert into t(x, y) values(?, ?)", use(i), use(j);

Bulk Operations

The ODBC backend has support for SOCI's bulk operations interface. Not all ODBC drivers support bulk operations, the following is a list of some tested backends:

ODBC Driver Bulk Read Bulk Insert
MS SQL Server 2005 YES YES
MS Access 2003 YES NO
PostgresQL 8.1 YES YES
MySQL 4.1 NO NO

Transactions

Transactions are also fully supported by the ODBC backend, provided that they are supported by the underlying database.

BLOB Data Type

Not currently supported

RowID Data Type

Not currently supported

Nested Statements

Not currently supported

Stored Procedures

Not currently supported

Acessing the native database API

SOCI provides access to underlying datbabase APIs via several getBackEnd() functions, as described in the beyond SOCI documentation.

The ODBC backend provides the following concrete classes for navite API access:

Accessor Function Concrete Class
session_backend* session::get_backend() odbc_statement_backend
statement_backend* statement::get_backend() odbc_statement_backend
rowid_backend* rowid::get_backend() odbc_rowid_backend

Backend-specific extensions

odbc_soci_error

The ODBC backend can throw instances of class odbc_soci_error, which is publicly derived from soci_error and has additional public members containing the ODBC error code, the Native database error code, and the message returned from ODBC:

int main()
{
    try
    {
        // regular code
    }
    catch (soci::odbc_soci_error const& e)
    {
        cerr << "ODBC Error Code: " << e.odbc_error_code() << endl
             << "Native Error Code: " << e.native_error_code() << endl
             << "SOCI Message: " << e.what() << std::endl
             << "ODBC Message: " << e.odbc_error_message() << endl;
    }
   catch (exception const &e)
    {
        cerr << "Some other error: " << e.what() << endl;
    }
}

get_connection_string()

The odbc_session_backend class provides std::string get_connection_string() const method that returns fully expanded connection string as returned by the SQLDriverConnect function.

Configuration options

This backend supports odbc_option_driver_complete option which can be passed to it via connection_parameters class. The value of this option is passed to SQLDriverConnect() function as "driver completion" parameter and so must be one of SQL_DRIVER_XXX values, in the string form. The default value of this option is SQL_DRIVER_PROMPT meaning that the driver will query the user for the user name and/or the password if they are not stored together with the connection. If this is undesirable for some reason, you can use SQL_DRIVER_NOPROMPT value for this option to suppress showing the message box:

connection_parameters parameters("odbc", "DSN=mydb");
parameters.set_option(odbc_option_driver_complete, "0" /* SQL_DRIVER_NOPROMPT */);
session sql(parameters);
soci-3.2.3/doc/backends/sqlite3.html0000644000000000000000000002130112511401144015731 0ustar rootroot SOCI - SQLite3 Backend Reference

SQLite3 Backend Reference

Prerequisites

Supported Versions

The SOCI SQLite3 backend is supported for use with SQLite3 >= 3.1

Tested Platforms

SQLite3 versionOperating SystemCompiler
3.5.2Mac OS X 10.5g++ 4.0.1
3.1.3Mac OS X 10.4g++ 4.0.1
3.2.1Linux i686 2.6.10-gentoo-r6g++ 3.4.5
3.3.4Ubuntu 5.1g++ 4.0.2
3.3.4Windows XP(cygwin) g++ 3.3.4
3.3.4Windows XPVisual C++ 2005 Express Edition
3.3.8Windows XPVisual C++ 2005 Professional
3.4.0Windows XP(cygwin) g++ 3.4.4
3.4.0Windows XPVisual C++ 2005 Express Edition

Required Client Libraries

The SOCI SQLite3 backend requires SQLite3's libsqlite3 client library.

Connecting to the Database

To establish a connection to the SQLite3 database, create a Session object using the SQLite3 backend factory together with the database file name:

session sql(sqlite3, "database_filename");

The only option for the connection string is the name of the file to use as a database.

Once you have created a session object as shown above, you can use it to access the database, for example:

int count;
sql << "select count(*) from invoices", into(count);

(See the SOCI basics and exchanging data documentation for general information on using the session class.)

SOCI Feature Support

Dynamic Binding

The SQLite3 backend supports the use of the SOCI row class, which facilitates retrieval of data whose type is not known at compile time.

When calling row::get<T>(), the type you should pass as T depends upon the underlying database type.

For the SQLite3 backend, this type mapping is complicated by the fact the SQLite3 does not enforce types *, and makes no attempt to validate the type names used in table creation or alteration statements. SQLite3 will return the type as a string, SOCI will recognize the following strings and match them the corresponding SOCI types:

SQLite3 Data Type SOCI Data Type row::get<T> specializations
*float* dt_ouble double
*int* dt_integer int
*char* dt_string std::string
*date*, *time* dt_date std::tm

* There is one case where SQLite3 enforces type. If a column is declared as "integer primary key", then SQLite3 uses that as an alias to the internal ROWID column that exists for every table. Only integers are allowed in this column.

(See the dynamic resultset binding documentation for general information on using the row class.)

Binding by Name

In addition to binding by position, the SQLite3 backend supports binding by name, via an overload of the use() function:

int id = 7;
sql << "select name from person where id = :id", use(id, "id")

The backend also supports the SQLite3 native numbered syntax, "one or more literals can be replace by a parameter "?" or ":AAA" or "@AAA" or "$VVV" where AAA is an alphanumeric identifier and VVV is a variable name according to the syntax rules of the TCL programming language." [1]:

int i = 7;
int j = 8;
sql << "insert into t(x, y) values(?, ?)", use(i), use(j);

Bulk Operations

The SQLite3 backend has full support for SOCI's bulk operations interface. However, this support is emulated and is not native.

Transactions

Transactions are also fully supported by the SQLite3 backend.

BLOB Data Type

The SQLite3 backend supports working with data stored in columns of type Blob, via SOCI's blob class. Because of SQLite3 general typelessness the column does not have to be declared any particular type.

RowID Data Type

In SQLite3 RowID is an integer. "Each entry in an SQLite table has a unique integer key called the "rowid". The rowid is always available as an undeclared column named ROWID, OID, or _ROWID_. If the table has a column of type INTEGER PRIMARY KEY then that column is another an alias for the rowid."[2]

Nested Statements

Nested statements are not supported by SQLite3 backend.

Stored Procedures

Stored procedures are not supported by SQLite3 backend

Acessing the native database API

SOCI provides access to underlying datbabase APIs via several get_backend() functions, as described in the beyond SOCI documentation.

The SQLite3 backend provides the following concrete classes for navite API access:

Accessor Function Concrete Class
session_backend* session::get_backend() sqlie3_session_backend
statement_backend* statement::get_backend() sqlite3_statement_backend
rowid_backend* rowid::get_backend() sqlite3_rowid_backend

Backend-specific extensions

SQLite3 result code support

SQLite3 result code is provided via the backend specific sqlite3_soci_error class. Catching the backend specific error yields the value of SQLite3 result code via the result() method.

Configuration options

None

soci-3.2.3/doc/backends/index.html0000644000000000000000000000655512511362240015475 0ustar rootroot SOCI - Existing Backends

Existing backends and supported platforms

Supported Features

(Follow the links to learn more about each backend.)

Oracle PostgreSQL MySQL SQLite3 Firebird ODBC DB2
Binding by Name YES YES (>=8.0) YES YES YES YES YES
Dynamic Binding YES YES YES YES YES YES
Bulk Operations YES YES YES YES YES YES YES
Transactions YES YES YES (with servers that support them, usually >= 4.0) YES YES YES YES
BLOB Data Type YES YES MySQL's BLOB type is mapped to std::string YES YES NO NO
RowID Data Type YES YES NO NO NO NO NO
Nested Statements YES NO NO NO NO NO YES
Stored Procedures YES YES NO (but stored functions, YES) NO YES NO YES
soci-3.2.3/doc/exchange.html0000644000000000000000000006301712511362240014372 0ustar rootroot SOCI - exchanging data

Exchanging data

Binding local data

Note: The Oracle documentation uses two terms: defining (for instructing the library where the output data should go) and binding (for the input data and input/output PL/SQL parameters). For the sake of simplicity, SOCI uses the term binding for both of these.

Binding output data

The into expression is used to add binding information to the statement:

int count;
sql << "select count(*) from person", into(count);

string name;
sql << "select name from person where id = 7", into(name);

In the above examples, some data is retrieved from the database and transmitted into the given local variable.

There should be as many into elements as there are expected columns in the result (see dynamic resultset binding for the exception to this rule).

Binding input data

The use expression associates the SQL placeholder (written with colon) with the local data:

int val = 7;
sql << "insert into numbers(val) values(:val)", use(val);

In the above statement, the first "val" is a column name (assuming that there is appropriate table numbers with this column), the second "val" (with colon) is a placeholder and its name is ignored here, and the third "val" is a name of local variable.

To better understand the meaning of each "val" above, consider also:

int number = 7;
sql << "insert into numbers(val) values(:blabla)", use(number);

Both examples above will insert the value of some local variable into the table numbers - we say that the local variable is used in the SQL statement.

There should be as many use elements as there are parameters used in the SQL query.

Portability note:

Older versions of the PostgreSQL client API do not allow to use input parameters at all. In order to compile SOCI with those old client libraries, define the SOCI_POSTGRESQL_NOPARAMS preprocessor name passing -DSOCI_POSTGRESQL_NOPARAMS=ON variable to CMake.

Binding by position

If there is more output or input "holes" in the single statement, it is possible to use many into and use expressions, separated by commas, where each expression will be responsible for the consecutive "hole" in the statement:

string firstName = "John", lastName = "Smith";
int personId = 7;

sql << "insert into person(id, firstname, lastname) values(:id, :fn, :ln)",
    use(personId), use(firstName), use(lastName);

sql << "select firstname, lastname from person where id = :id",
    into(firstName), into(lastName), use(personId);

In the code above, the order of "holes" in the SQL statement and the order of into and use expression should match.

Binding by name

The SQL placeholders that have their names (with colon) can be bound by name to clearly associate the local variable with the given placeholder.

This explicit naming allows to use different order of elements:

string firstName = "John", lastName = "Smith";
int personId = 7;
sql << "insert into person(id, firstname, lastname) values(:id, :fn, :ln)",
    use(firstName, "fn"), use(lastName, "ln"), use(personId, "id");

or bind the same local data to many "holes" at the same time:

string addr = "...";
sql << "update person"
       " set mainaddress = :addr, contactaddress = :addr"
       " where id = 7",
       use(addr, "addr");

Object lifetime and immutability:

SOCI assumes that local variables provided as use elements live at least as long at it takes to execute the whole statement. In short statement forms like above, the statement is executed sometime at the end of the full expression and the whole process is driven by the invisible temporary object handled by the library. If the data provided by user comes from another temporary variable, it might be possible for the compiler to arrange them in a way that the user data will be destroyed before the statement will have its chance to execute, referencing objects that no longer exist:

// dangerous code:

string getNameFromSomewhere();

sql << "insert into person(name) values(:n)",
    use(getNameFromSomewhere());

In the above example, the data passed to the database comes from the temporary variable that is a result of call to getNameFromSomewhere - this should be avoided and named variables should be used to ensure safe lifetime relations:

// safe code:

string getNameFromSomewhere();

string name = getNameFromSomewhere();
sql << "insert into person(name) values(:n)",
    use(name);

It is still possible to provide const data for use elements. Note that some database servers, like Oracle, allow PL/SQL procedures to modify their in/out parameters - this is detected by the SOCI library and an error is reported if the database attempts to modify the use element that holds const data.

The above example can be ultimately written in the following way:

// safe and efficient code:

string getNameFromSomewhere();

const string & name = getNameFromSomewhere();
sql << "insert into person(name) values(:n)",
    use(name);

Portability notes:

The PostgreSQL backend allows to use the "native" PostgreSQL way of naming parameters in the query, which is by numbers like $1, $2, $3, etc. In fact, the backend rewrites the given query to the native form - and this is also one of the very few places where SOCI intrudes into the SQL query. For portability reasons, it is recommended to use named parameters, as shown in the examples above.
The query rewriting can be switched off by compiling the backend with the SOCI_POSTGRESQL_NOBINDBYNAME name defined (pass -DSOCI_POSTGRESQL_NOBINDBYNAME=ON variable to CMake). Note that in this case it is also necessary to define SOCI_POSTGRESQL_NOPREPARE (controlled by CMake variable -DSOCI_POSTGRESQL_NOPREPARE=ON), because statement preparation relies on successful query rewriting. In practice, both macros will be needed for PostgreSQL server older than 8.0.

Handling nulls and other conditions

Indicators

In order to support null values and other conditions which are not real errors, the concept of indicator is provided.

For example, when the following SQL query is executed:

select name from person where id = 7

there are three possible outcomes:

  1. there is a person with id = 7 and his name is returned
  2. there is a person with id = 7, but he has no name (his name is null in the database table)
  3. there is no such person

Whereas the first alternative is easy to handle, the other two are more complex. Moreover, they are not necessarily errors from the application's point of view and what's more interesting, they are different and the application may wish to detect which is the case.
The following example does this:

string name;
indicator ind;

sql << "select name from person where id = 7", into(name, ind);

if (sql.got_data())
{
    switch (ind)
    {
    case i_ok:
        // the data was returned without problems
        break;
    case i_null:
        // there is a person, but he has no name (his name is null)
        break;
    case i_truncated:
        // the name was returned only in part,
        // because the provided buffer was too short
        // (not possible with std::string, but possible with char* and char[])
        break;
    }
}
else
{
    // no such person in the database
}

The use of indicator variable is optional, but if it is not used and the result would be i_null, then the exception is thrown. This means that you should use indicator variables everywhere where the application logic (and database schema) allow the "attribute not set" condition.

Indicator variables can be also used when binding input data, to control whether the data is to be used as provided, or explicitly overrided to be null:

int id = 7;
string name;
indicator ind = i_null;
sql << "insert into person(id, name) values(:id, :name)",
    use(id), use(name, ind);

In the above example, the row is inserted with name attribute set to null.

Indicator variables can also be used in conjunction with vector based insert, update, and select statements:

vector<string> names(100);
vector<indicator> inds;
sql << "select name from person where id = 7", into(names, inds);

The above example retrieves first 100 rows of data (or less). The initial size of names vector provides the (maximum) number of rows that should be read. Both vectors will be automatically resized according to the number of rows that were actually read.

The following example inserts null for each value of name:

vector<int> ids;
vector<string> names;
vector<indicator> nameIndicators;

for (int i = 0; i != 10; ++i)
{
    ids.push_back(i);
    names.push_back("");
    nameIndicators.push_back(i_null);
}

sql << "insert into person(id, name) values(:id, :name)",
    use(ids), use(name, nameIndicators);

See also Integration with Boost to learn how the Boost.Optional library can be used to handle null data conditions in a more natural way.

Types

Static type binding

The static binding for types is most useful when the types used in the database are known at compile time - this was already presented above with the help of into and use functions.

The following types are currently supported for use with into and use expressions:

  • char (for character values)
  • short, int, unsigned long, long long, double (for numeric values)
  • char*, char[], std::string (for string values)
  • std::tm (for datetime values)
  • soci::statement (for nested statements and PL/SQL cursors)
  • soci::blob (for Binary Large OBjects)
  • soci::row_id (for row identifiers)

See the test code that accompanies the library to see how each of these types is used.

Static type binding for bulk operations

Bulk inserts, updates, and selects are supported through the following std::vector based into and use types:

  • std::vector<char>
  • std::vector<short>
  • std::vector<int>
  • std::vector<unsigned long>
  • std::vector<long long>
  • std::vector<double>
  • std::vector<std::string>
  • std::vector<std::tm>

Use of the vector based types mirrors that of the standard types, with the size of the vector used to specify the number of records to process at a time. See below for examples.

Note that bulk operations are supported only for std::vectors of the types listed above.

Dynamic resultset binding

For certain applications it is desirable to be able to select data from arbitrarily structured tables (e.g. via "select * from ...") and format the resulting data based upon its type. SOCI supports this through the soci::row and soci::column_properties classes.

Data is selected into a row object, which holds column_properties objects describing the attributes of data contained in each column. Once the data type for each column is known, the data can be formatted appropriately.

For example, the code below creates an XML document from a selected row of data from an arbitrary table:

row r;
sql << "select * from some_table", into(r);

std::ostringstream doc;
doc << "<row>" << std::endl;
for(std::size_t i = 0; i != r.size(); ++i)
{
    const column_properties & props = r.get_properties(i);

    doc << '<' << props.get_name() << '>';

    switch(props.get_data_type())
    {
    case dt_string:
        doc << r.get<std::string>(i);
        break;
    case dt_double:
        doc << r.get<double>(i);
        break;
    case dt_integer:
        doc << r.get<int>(i);
        break;
    case dt_long_long:
        doc << r.get<long long>(i);
        break;
    case dt_unsigned_long_long:
        doc << r.get<unsigned long long>(i);
        break;
    case dt_date:
        std::tm when = r.get<std::tm>(i);
        doc << asctime(&when);
        break;
    }

    doc << "</" << props.get_name() << '>' << std::endl;
}
doc << "</row>";

The type T parameter that should be passed to row::get<T>() depends on the SOCI data type that is returned from column_properties::get_data_type().

row::get<T>() throws an exception of type std::bad_cast if an incorrect type T is requested.

SOCI Data Type row::get<T> specialization
dt_double double
dt_integer int
dt_long_long long long
dt_unsigned_long_long unsigned long long
dt_string std::string
dt_date std::tm

The mapping of underlying database column types to SOCI datatypes is database specific. See the backend documentation for details.

The row also provides access to indicators for each column:

row r;
sql << "select name from some_table where id = 1", into(r);
if (r.get_indicator(0) != soci::i_null)
{
   std::cout << r.get<std::string>(0);
}

It is also possible to extract data from the row object using its stream-like interface, where each extracted variable should have matching type respective to its position in the chain:

row r;
sql << "select name, address, age from persons where id = 123", into(r);

string name, address;
int age;

r >> name >> address >> age;

Note, however, that this interface is not compatible with the standard std::istream class and that it is only possible to extract a single row at a time - for "safety" reasons the row boundary is preserved and it is necessary to perform the fetch operation explicitly for each consecutive row (see next page).

Extending SOCI to support custom (user-defined) C++ types

SOCI can be easily extended with support for user-defined datatypes.

The extension mechanism relies on appropriate specialization of the type_conversion struct that converts to and from one of the following SOCI base types:

  • double
  • int
  • long long
  • unsigned long long
  • std::string
  • char
  • std::tm

There are three required class members for a valid type_conversion specialization:

  • the base_type type definition, aliasing either one of the base types or another ser-defined type
  • the from_base() static member function, converting from the base type
  • the to_base() static member function, converting to the base type

Note that no database-specific code is required to define user conversion.

The following example shows how the user can extend SOCI to support his own type MyInt, which here is some wrapper for the fundamental int type:

class MyInt
{
public:
    MyInt() {}
    MyInt(int i) : i_(i) {}

    void set(int i) { i_ = i; }
    int get() const { return i_; }

private:
    int i_;
};

namespace soci
{
    template <>
    struct type_conversion<MyInt>
    {
        typedef int base_type;

        static void from_base(int i, indicator ind, MyInt & mi)
        {
            if (ind == i_null)
            {
                throw soci_error("Null value not allowed for this type");
            }

            mi.set(i);
        }

        static void to_base(const MyInt & mi, int & i, indicator & ind)
        {
            i = mi.get();
            ind = i_ok;
        }
    };
}

The above specialization for soci::type_conversion<MyInt> is enough to enable the following:

MyInt i;

sql << "select count(*) from person", into(i);

cout << "We have " << i.get() << " persons in the database.\n";

Note that there is a number of types from the Boost library integrated with SOCI out of the box, see Integration with Boost for complete description. Use these as examples of conversions for more complext data types.

Note also that user-defined datatypes are not supported with bulk data transfer.

Another possibility to extend SOCI with custom data types is to use the into_type<T> and use_type<T> class templates, which specializations can be user-provided. These specializations need to implement the interface defined by, respectively, the into_type_base and use_type_base classes.

Note that when specializing these template classes the only convention is that when the indicator variable is used (see below), it should appear in the second position. Please refer to the library source code to see how this is done for the standard types.

Object-relational mapping

SOCI provides a class called values specifically to enable object-relational mapping via type_conversion specializations.

For example, the following code maps a Person object to and from a database table containing columns "ID", "FIRST_NAME", "LAST_NAME", and "GENDER".

Note that the mapping is non-invasive - the Person object itself does not contain any SOCI-specific code:

struct Person
{
    int id;
    std::string firstName;
    std::string lastName;
    std::string gender;
};

namespace soci
{
    template<>
    struct type_conversion<Person>
    {
        typedef values base_type;

        static void from_base(values const & v, indicator /* ind */, Person & p)
        {
            p.id = v.get<int>("ID");
            p.firstName = v.get<std::string>("FIRST_NAME");
            p.lastName = v.get<std::string>("LAST_NAME");

            // p.gender will be set to the default value "unknown"
            // when the column is null:
            p.gender = v.get<std::string>("GENDER", "unknown");

            // alternatively, the indicator can be tested directly:
            // if (v.indicator("GENDER") == i_null)
            // {
            //     p.gender = "unknown";
            // }
            // else
            // {
            //     p.gender = v.get<std::string>("GENDER");
            // }
        }
    
        static void to_base(const Person & p, values & v, indicator & ind)
        {
            v.set("ID", p.id);
            v.set("FIRST_NAME", p.firstName);
            v.set("LAST_NAME", p.lastName);
            v.set("GENDER", p.gender, p.gender.empty() ? i_null : i_ok);
            ind = i_ok;
        }
    };
}

With the above type_conversion specialization in place, it is possible to use Person directly with SOCI:

session sql(oracle, "service=db1 user=scott password=tiger");

Person p;
p.id = 1;
p.lastName = "Smith";
p.firstName = "Pat";
sql << "insert into person(id, first_name, last_name) "
       "values(:ID, :FIRST_NAME, :LAST_NAME)", use(p);

Person p1;
sql << "select * from person", into(p1);
assert(p1.id == 1);
assert(p1.firstName + p.lastName == "PatSmith");
assert(p1.gender == "unknown");

p.firstName = "Patricia";
sql << "update person set first_name = :FIRST_NAME "
       "where id = :ID", use(p);

Note: The values class is currently not suited for use outside of type_conversion specializations. It is specially designed to facilitate object-relational mapping when used as shown above.

Large objects (BLOBs)

The SOCI library provides also an interface for basic operations on large objects (BLOBs - Binary Large OBjects).

blob b(sql); // sql is a session object
sql << "select mp3 from mymusic where id = 123", into(b);

The following functions are provided in the blob interface, mimicking the file-like operations:

  • std::size_t get_len();
  • std::size_t read(std::size_t offset, char *buf, std::size_t toRead);
  • std::size_t write(std::size_t offset, char const *buf, std::size_t toWrite);
  • std::size_t append(char const *buf, std::size_t toWrite);
  • void trim(std::size_t newLen);

The offset parameter is always counted from the beginning of the BLOB's data.

Portability notes:

  1. The way to define BLOB table columns and create or destroy BLOB objects in the database varies between different database engines. Please see the SQL documentation relevant for the given server to learn how this is actually done. The test programs provided with the SOCI library can be also a simple source of full working examples.
  2. The trim function is not currently available for the PostgreSQL backend.
soci-3.2.3/doc/beyond.html0000644000000000000000000001551112511362240014064 0ustar rootroot SOCI - beyond standard SQL

Beyond standard SQL

Sometimes the standard SQL is not enough and database-specific syntax needs to be used. When possible and practical, SOCI provides wrappers hiding the differences between the backends and this section describes these wrappers. And if this is still not enough, you can use the backend-specific methods directly as described below.

Getting the number of rows affected by an operation

It can be useful to know how many rows were affected by the last SQL statement, most often when using INSERT, UPDATE or DELETE. SOCI provides statement::get_affected_rows() method allowing to do this:

statement st = (sql.prepare << "update some_table ...");
st.execute(true);

if ( !st.get_affected_rows() )
{
    ... investigate why no rows were modified ...
}

Portability note:

This method is currently not supported by the Oracle backend. It is however supported when using Oracle database via ODBC backend.

Working with sequences

It is common to have auto-incrementing database fields or fields whose value come from a sequence. In the latter case you need to retrieve the value of the field for a new row before inserting it into the database. In the former case, this is unnecessary but you may still want to know the value generated by the database, e.g. to use it as a foreign key in another table. So it would be useful to have a way to obtain the value of such a field. But, of course, to make life of database programmers more interesting, different products usually support either autoincrement fields or sequences but not both -- and they use different syntaxes for them, too. SOCI tries to help to deal with this unfortunate situation by providing two functions: session::get_next_sequence_value() and session::get_last_insert_id.

If you know which kind of database you use, you may use only one of them: when working with sequences, the first one allows to generate the next value in a sequence and when working with autoincrement fields, the second one retrieves the last value generated for such a field for the given table.

However if you use multiple SOCI backends or even just a single ODBC backend but support connecting to databases of different types, you actually must use both of them in the following way to insert a row:

long id;
statement st;
if ( sql.get_next_sequence_value("table_sequence", id) )
{
    st << "insert into table(id, f1, f2) values(:id, :f1, :f2)",
        use(id), use(f1), use(f2);
}
else
{
    // We're not using sequences, so don't specify the value,
    // it will be automatically generated by the database on insert.
    st << "insert into table(f1, f2) value(:f1, :f2)",
        use(f1), use(f2);

    // If the ID used for the above row is needed later, get it:
    if ( !sql.get_last_insert_id("table", id) )
        ... unexpected error, handle appropriately ...
}

Portability note:

These methods are currently only implemented in Firebird and ODBC backends.

Beyond SOCI API

As the original name of the library (Simple Oracle Call Interface) clearly stated, SOCI is intended to be a simple library, targeting the majority of needs in regular C++ application. We do not claim that everything can be done with SOCI and it was never the intent of the library. What is important, though, is that the simplicity of the library does not prevent the client applications from reaching into the low-level specifics of each database backend in order to achieve special configuration or performance goals.

Most of the SOCI classes have the getBackEnd method, which returns the pointer to the actual backend object that implements the given functionality. The knowledge of the actual backend allows the client application to get access to all low-level details that are involved.

blob b(sql);

oracle_session_back_end * sessionBackEnd = static_cast<oracle_session_back_end *>(sql.get_back_end());
oracle_blob_back_end * blobBackEnd = static_cast<oracle_blob_back_end *>(b.get_back_end());

OCILobDisableBuffering(sessionBackEnd->svchp_, sessionBackEnd->errhp_, blobBackEnd->lobp_);

The above code creates the blob object and uses two calls to the get_back_end function (on both the session and the blob objects) to get access to the actual backend objects. Assuming that it is the "oracle" backend which is in use, the downcasts allow to access all relevant low-level handles and use them in the call to the OCILobDisableBuffering function. This way, the BLOB handle was configured in a way that the SOCI library alone would not allow.

rowid rid(sql); // sql is a session object
sql << "select oid from mytable where id = 7", into(rid);

postgresql_rowid_back_end * rbe = static_cast<postgresql_rowid_back_end *>(rid.get_back_end());

unsigned long oid = rbe->value_;

The above example retrieves the rowid ("something" that identifies the row in the table) from the table and uses the get_back_end function to extract the actual object that implements this functionality. Assuming that it is the "postgresql" backend which is in use, the downcast is performed to use the postgresql_rowid_back_end interface to get the actual OID value that is a physical, low-level implementation of row identifier on PostgreSQL databases.

In order for any of the above to compile, you have to explicitly #include the appropriate backend's header file.

Please see the header file related to the given backend to learn what low-level handles and descriptors are available.

soci-3.2.3/doc/boost.html0000644000000000000000000001001612511362240013725 0ustar rootroot SOCI - integration with Boost

Integration with Boost

The SOCI user code can be easily integrated with the Boost library thanks to the very flexible type conversion facility. There are three important Boost types that are supported out of the box.

boost::optional<T>

boost::optional<T> provides an alternative way to support the null data condition and as such relieves the user from necessity to handle separate indicator values.

The boost::optional<T> objects can be used everywhere where the regular user provided values are expected.

Example:

boost::optional<string> name;
sql << "select name from person where id = 7", into(name);

if (name.is_initialized())
{
    // OK, the name was retrieved and is not-null
    cout << "The name is " << name.get();
}
else
{
    // the name is null
}

The boost::optional<T> objects are fully supported for both into and use elements, in both single and vector forms. They can be also used for user-defined data types.

boost::tuple<T1, ...>

boost::tuple<T1, ...> allows to work with whole rows of information and in some cases can be more convenient to use than the more dynamically-oriented row type.

Example:

boost::tuple<string, string, int> person;

sql << "select name, phone, salary from persons where ...",
    into(person);

Tuples are supported for both into and use elements. They can be used with rowset as well.

Tuples can be also composed with boost::optional<T>:

boost::tuple<string, boost::optional<string>, int> person;

sql << "select name, phone, salary from persons where ...",
    into(person);

if (person.get<1>().is_initialized())
{
    // the given person has a phone number
}
else
{
    // this person does not have a phone number
}

boost::fusion::vector<T1, ...>

The boost::fusion::vector types are supported in the same way as tuples.

boost::gregorian::date

The boost::gregorian::date is provided as a conversion for base type std::tm and can be used as a replacement for it.

Optional integration:

The integration with Boost types is optional and not enabled by default, which means that SOCI can be compiled and used without any dependency on Boost.

In order to enable the support for any of the above types, the user needs to either include one of these headers:

#include <boost-optional.h>
#include <boost-tuple.h>
#include <boost-fusion.h>
#include <boost-gregorian-date.h>

or to define the SOCI_USE_BOOST macro before including the soci.h main header file. Note that in this case the support for boost::fusion::vector is enabled only if the detected Boost version is at least 1.35.

soci-3.2.3/doc/rationale.html0000644000000000000000000003505012511362240014562 0ustar rootroot SOCI - rationale

Rationale FAQ

This part of the documentation is supposed to gather in a single place the usual questions (and answers) about SOCI with regard to the design decisions that have shaped it.

Q: Why "SOCI"?

SOCI was initially developed in the environment where Oracle was the main database technology in use. As a wrapper for the native OCI API (Oracle Call Interface), the name "Simple Oracle Call Interface" was quite obvious - until the 2.0 release, when the internal architecture was largely redesigned to allow the use of backends that support other database servers. We have kept the same name to indicate that Oracle is the main supported technology in the sense that the library includes only those features that were naturally implemented in Oracle. With the 2.1 release of the library, two new backends were added (MySQL and SQLite3) and we decided to drop the original full name so that new users looking for a library supporting any of these simpler libraries are not discouraged by seeing "Oracle" somewhere in the name. The other possible interpretation was "Syntax Oriented Call Interface", which stresses the fact that SOCI was built to support the most natural and easy interface for the user that is similar to the Embedded SQL concept (see below). But on the other hand, SOCI also provides other features (like object-relational mapping) and as a whole it is not just "emulator" of the Embedded SQL. With all these considerations in mind, SOCI is just "SOCI - The C++ Database Access Library".

Still, Oracle is considered to be the main driving server technology in terms of the set of features that are supported by the library. This also means that backends for other servers might need to work around some of the imposed idioms and protocols, but already available and well-working PostgreSQL, MySQL and SQLite3 backends show that it's actually not that bad and the abstractions provided by the library are actually very universal. Of course, some of the features that were provided for Oracle might not be supported for all other servers, but we think that it's better to have one leading technology (where at least one group is fully happy) instead of some "common denominator" for all databases (where nobody is happy).

Q: Where the basic SOCI syntax comes from?

The basic SOCI syntax was inspired by the Embedded SQL, which is part of the SQL standard, supported by the major DB technologies and even available as built-in part of the languages used in some DB-oriented integrated development environments. The term "Embedded SQL" is enough for Google to spit millions of references - one of the typical examples is:

{
    int a;
    /* ... */
    EXEC SQL SELECT salary INTO :a
             FROM Employee
             WHERE SSN=876543210;
    /* ... */
    printf("The salary is %d\n", a);
    /* ... */
}

The above is not a regular C (nor C++) code, of course. It's the mix of C and SQL and there is a separate, specialized preprocessor needed to convert it to something that the actual C (or C++) compiler will be able to understand. This means that the compilation of the program using embedded SQL is two-phase: preprocess the embedded SQL part and compile the result. This two-phase development is quite troublesome, especially when it comes to debugging. Yet, the advantage of it is that the code expresses the programmer's intents in a very straightforward way: read something from the database and put it into the local variable. Just like that.

The SOCI library was born as an anwer to the following question: is it possible to have the same expressive power without the disadvantages of two-phase builds?

The following was chosen to be the basic SOCI syntax that can mirror the above Embedded SQL example:

int a;
sql << "SELECT salary FROM Employee WHERE SSN=876543210", into(a);

(as you see, SOCI changes the order of elements a little bit, so that the SQL query is separate and not mixed with other elements)

Apart from mimicking the Embedded SQL techniques in the regular, fully standard C++ code, the above syntax has the following benefit: it is minimal with respect to what has to be said. Every single piece above is needed and expresses something important, like:

  • which session should be used (the client can be connected to many databases at the same time) - here, the sql object encapsulates the session,
  • what SQL query should be executed - here, it's the string literal, but it could be also a std::string variable,
  • where to put the result - here, the local variable a will receive the result.

Everything else is just a couple of operators that allow to treat the whole as a single expression. It's rather difficult to remove anything from this example.

The fact that the basic SOCI syntax is minimal (but without being obscure at the same time, see below) means that the programmer does not need to bother with unnecessary noise that some other database libraries impose. We hope that after having written one line of code like above by themselves, most programmers will react with something like "how obvious!" instead of "how advanced!".

Q: Why should I use SQL queries as strings in my program? I prefer the query to be generated or composed piece-by-piece by separate functions.

First, you don't need to use SQL queries as string literals. In bigger projects it is a common practice to store SQL queries externally (in a file, or in a... database) and load them before use. This means that they are not necessarily expected to appear in the program code, as they do in our simple code examples and the advantage of separating them from the source code of the main program is, among others, the possibility to optimize and tune the SQL queries without recompilation and relinking of the whole program.

What is the most important, though, is that SOCI does not try to mess with the text of the query (apart from very few cases), which means that the database server will get exactly the same text of the query as is used in the program. The advantage of this is that there is no new SQL-like (or even SQL-unlike) syntax that you would need to learn, and also that it's much easier to convince a typical DBA to help with SQL tuning or other specialized activities, if he is given the material in the form that is not polluted with any foreign abstractions.

Q: Why not some stream-like interface, which is well-known to all C++ programmers?

An example of the stream-like interface might be something like this (this is imaginary syntax, not supported by SOCI):

sql.exec("select a, b, c from some_table");

while (!sql.eof())
{
    int a, b, c;
    sql >> a >> b >> c;
    // ...
}

We think that the data stored in the relational database should be treated as a set of relations - which is exactly what it is. This means that what is read from the database as a result of some SQL query is a set of rows. This set might be ordered, but it is still a set of rows, not a uniformly flat list of values. This distinction might seem to be unnecessarily low-level and that the uniform stream-like presentation of data is more preferable, but it's actually the other way round - the set of rows is something more structured - and that structure was designed into the database - than the flat stream and is therefore less prone to programming errors like miscounting the number of values that is expected in each row.

Consider the following programming error:

sql.exec("select a, b from some_table"); // only TWO columns

while (!sql.eof())
{
    int a, b, c;
    sql >> a >> b >> c; // this causes "row-tearing"
    // ...
}

"How to detect the end of each line in a file" is a common beginner's question that relates to the use of IOStreams - and this common question clearly shows that for the record-oriented data the stream is not an optimal abstraction. Of course, we don't claim that IOStreams is bad - but we do insist that the record-oriented data is better manipulated in a way that is also record-aware.

Having said that, we have provided some form of the stream-like interface, but with the important limitation that the stream is always bound to the single row, so that the row-tearing effect is not possible. In other words, data returned from the database is still structured into rows, but each row can be separately traversed like a stream. We hope that it provides a good balance between convenience and code safety.

Q: Why use indicators instead of some special value to discover that something is null?

Some programmers are used to indicating the null value by using some special (which means: "unlikely" to be ever used) value - for example, to use the smallest integer value to indicate null integer. Or to use empty string to indicate null string. And so on.

We think that it's completely wrong. Null (in the database sense) is an information about the data. It describes the state of the data and if it's null, then there's no data at all. Nothing. Null. It does not make any sense to talk about some special value if in fact there is no value at all - especially if we take into account that, for example, the smallest integer value (or whatever else you choose as the "special" value) might not be that special in the given application or domain.

Thus, SOCI uses a separate indicators to describe the state of exchanged data. It also has an additional benefit of allowing the library to convey more than two states (null and not null). Indeed, the SOCI library uses indicators also to report that the data was read, but truncated (this applies to strings when reading to fixed-length character arrays). Truncation is also an information about the data and as such it's better to have it in addition to the data, not as part of it.

Having said that, it is important to point at the Integration with Boost that allows to use boost::optional<T> to conveniently pack together the data and the information about its state.

Q: Overloaded comma operator is just obfuscation, I don't like it.

Well, consider the following:

"Send the query X to the server Y and put result into variable Z."

Above, the "and" plays a role of the comma. Even if overloading the comma operator is not a very popular practice in C++, some libraries do this, achieving terse and easy to learn syntax. We are pretty sure that in SOCI the comma operator was overloaded with a good effect.

Q: The operator<< provides a bad abstraction for the "input" statements.

Indeed, the operator<< in the basic SOCI syntax shows that something (the query) is sent somewhere (to the server). Some people don't like this, especially when the "select" statements are involved. If the high-level idea is to read data from somewhere, then operator<< seems unintuitive to the die-hard IOStreams users. The fact is, however, that the code containing SQL statement already indicates that there is a client-server relationship with some other software component (very likely remote). In such code it does not make any sense to pretend that the communication is one-way only, because it's clear that even the "select" statements need to be sent somewhere. This approach is also more uniform and allows to cover other statements like "drop table" or alike, where no data is expected to be exchanged at all (and therefore the IOStreams analogies for data exchange have no sense at all). No matter what is the kind of the SQL statement, it is sent to the server and this "sending" justifies the choice of operator<<.

Using different operators (operator>> and operator<<) as a way of distinguishing between different high-level ideas (reading and writing from the data store, respectively) does make sense on much higher level of abstraction, where the SQL statement itself is already hidden - and we do encourage programmers to use SOCI for implementing such high-level abstractions. For this, the object-relational mapping facilities available in SOCI might prove to be a valuable tool as well, as an effective bridge between the low-level world of SQL statements and the high-level world of user-defined abstract data types.

Q: Why the Boost license?

We decided to use the Boost license, because it's well recognized in the C++ community, allows us to keep our minimum copyrights, and at the same time allows SOCI to be safely used in commercial projects, without imposing concerns (or just plain uncertainty) typical to other open source licenses, like GPL. We also hope that by choosing the Boost license we have made the life easier for both us and our users. It saves us from answering law-related questions that were already answered on the Boost license info page and it should also give more confidence to our users - especially to those of them, who already accepted the conditions of the Boost license - the just have one license less to analyze.

Still, if for any reason the conditions of this license are not acceptable, we encourage the users to contact us directly (see links on the relevant SOCI page) to discuss any remaining concerns.

soci-3.2.3/doc/reference.html0000644000000000000000000011146212511362240014544 0ustar rootroot SOCI - reference

Client interface reference

The core client interface is a set of classes and free functions declared in the soci.h header file. All names are dbeclared in the soci namespace.

There are also additional names declared in the soci::details namespace, but they are not supposed to be directly used by the users of the library and are therefore not documented here. When such types are used in the declarations that are part of the "public" interface, they are replaced by "IT", which means "internal type". Types related to the backend interface are named here, but documented on the next page.

commonly used types

The following types are commonly used in the rest of the interface:

// data types, as seen by the user
enum data_type { dt_string, dt_date, dt_double, dt_integer, dt_long_long, dt_unsigned_long_long };

// the enum type for indicator variables
enum indicator { i_ok, i_null, i_truncated };

// the type used for reporting exceptions
class soci_error : public std::runtime_error { /* ... */ };

The data_type type defines the basic SOCI data types. User provided data types need to be associated with one of these basic types.

The indicator type defines the possible states of data.

The soci_error type is used for error reporting.

class session

The session class encapsulates the connection to the database.

class session
{
public:
    session();
    explicit session(connection_parameters const & parameters);
    session(backend_factory const & factory, std::string const & connectString);
    session(std::string const & backendName, std::string const & connectString);
    explicit session(std::string const & connectString);
    explicit session(connection_pool & pool);

    ~session();

    void open(backend_factory const & factory, std::string const & connectString);
    void open(std::string const & backendName, std::string const & connectString);
    void open(std::string const & connectString);
    void close();
    void reconnect();

    void begin();
    void commit();
    void rollback();

    IT once;
    IT prepare;

    template <typename T> IT operator<<(T const & t);

    bool got_data() const;

    bool get_next_sequence_value(std::string const & sequence, long & value);
    bool get_last_insert_id(std::string const & table, long & value);

    std::ostringstream & get_query_stream();

    void set_log_stream(std::ostream * s);
    std::ostream * get_log_stream() const;

    std::string get_last_query() const;

    void uppercase_column_names(bool forceToUpper);

    details::session_backend * get_backend();

    std::string get_backend_name() const;
};

This class contains the following members:

  • Various constructors. The default one creates the session in the disconnected state. The others expect the backend factory object, or the backend name, or the URL-like composed connection string or the special parameters object containing both the backend and the connection string as well as possibly other connection options. The last constructor creates a session proxy associated with the session that is available in the given pool and releases it back to the pool when its lifetime ends. Example:
    session sql(postgresql, "dbname=mydb");
    session sql("postgresql", "dbname=mydb");
    session sql("postgresql://dbname=mydb");
    
    The constructors that take backend name as string load the shared library (if not yet loaded) with name computed as libsoci_ABC.so (or libsoci_ABC.dll on Windows) where ABC is the given backend name.
  • open, close and reconnect functions for reusing the same session object many times; the reconnect function attempts to establish the connection with the same parameters as most recently used with constructor or open. The arguments for open are treated in the same way as for constructors.
  • begin, commit and rollback functions for transaction control.
  • once member, which is used for performing instant queries that do not need to be separately prepared. Example:
    sql.once << "drop table persons";
    
  • prepare member, which is used for statement preparation - the result of the statement preparation must be provided to the constructor of the statement class. Example:
    int i;
    statement st = (sql.prepare <<
                    "insert into numbers(value) values(:val)", use(i));
    
  • operator<< that is a shortcut forwarder to the equivalent operator of the once member. Example:
    sql << "drop table persons";
    
  • got_data returns true if the last executed query had non-empty result.
  • get_next_sequence_value returns true if the next value of the sequence with the specified name was generated and returned in its second argument. Unless you can be sure that your program will use only databases that support sequences, consider using this method in conjunction with get_last_insert_id() as explained in "Working with sequences" section.
  • get_last_insert_id returns true if it could retrieve the last value automatically generated by the database for an auto-incremented field. Notice that although this method takes the table name, for some databases, such as Microsoft SQL Server and SQLite, this value is actually global, so you should attempt to retrieve it immediately after performing an insertion.
  • get_query_stream provides direct access to the stream object that is used to accumulate the query text and exists in particular to allow the user to imbue specific locale to this stream.
  • set_log_stream and get_log_stream functions for setting and getting the current stream object used for basic query logging. By default, it is NULL, which means no logging. The string value that is actually logged into the stream is one-line verbatim copy of the query string provided by the user, without including any data from the use elements. The query is logged exactly once, before the preparation step.
  • get_last_query retrieves the text of the last used query.
  • uppercase_column_names allows to force all column names to uppercase in dynamic row description; this function is particularly useful for portability, since various database servers report column names differently (some preserve case, some change it).
  • get_backend returns the internal pointer to the concrete backend implementation of the session. This is provided for advanced users that need access to the functionality that is not otherwise available.
  • get_backend_name is a convenience forwarder to the same function of the backend object.

See Connections and simple queries for more examples.

class connection_parameters

The connection_parameters class is a simple container for the backend pointer, connection string and any other connection options. It is used together with session constructor and open() method.

class connection_parameters
{
public:
    connection_parameters();
    connection_parameters(backend_factory const & factory, std::string const & connectString);
    connection_parameters(std::string const & backendName, std::string const & connectString);
    explicit connection_parameters(std::string const & fullConnectString);

    void set_option(const char * name, std::string const & value);
    bool get_option(const char * name, std::string & value) const
};

The methods of this class are:

  • Default constructor is rarely used as it creates an uninitialized object and the only way to initialize it later is to assign another, valid, connection_parameters object to this one.
  • The other constructors correspond to the similar constructors of the session class and specify both the backend, either as a pointer to it or by name, and the connection string.
  • set_option can be used to set the value of an option with the given name. Currently all option values are strings, so if you need to set a numeric option you need to convert it to a string first. If an option with the given name had been already set before, its old value is overwritten.

class connection_pool

The connection_pool class encapsulates the thread-safe pool of connections and ensures that only one thread at a time has access to any connection that it manages.

class connection_pool
{
public:
    explicit connection_pool(std::size_t size);
    ~connection_pool();

    session & at(std::size_t pos);

    std::size_t lease();
    bool try_lease(std::size_t & pos, int timeout);
    void give_back(std::size_t pos);
};

The operations of the pool are:

  • Constructor that takes the intended size of the pool. After construction, the pool contains regular session objects in disconnected state.
  • at function that provides direct access to any given entry in the pool. This function is non-synchronized.
  • lease function waits until some entry is available (which means that it is not used) and returns the position of that entry in the pool, marking it as locked.
  • try_lease acts like lease, but allows to set up a time-out (relative, in milliseconds) on waiting. Negative time-out value means no time-out. Returns true if the entry was obtained, in which case its position is written to the pos parametr, and false if no entry was available before the time-out.
  • give_back should be called when the entry on the given position is no longer in use and can be passed to other requesting thread.

Note: calls to lease and give_back are automated by the dedicated constructor of the session class, see above.

class transaction

The class transaction can be used for associating the transaction with some code scope. It is a RAII wrapper for regular transaction operations that automatically rolls back in its destructor if the transaction was not explicitly committed before.

class transaction
{
public:
    explicit transaction(session & sql);

    ~transaction();

    void commit();
    void rollback();

private:
    // ...
};

Note that objects of this class are not notified of other transaction related operations that might be executed by user code explicitly or hidden inside SQL queries. It is not recommended to mix different ways of managing transactions.

function into

The function into is used for binding local output data (in other words, it defines where the results of the query are stored).

template <typename T>
IT into(T & t);

template <typename T, typename T1>
IT into(T & t, T1 p1);

template <typename T>
IT into(T & t, indicator & ind);

template <typename T, typename T1>
IT into(T & t, indicator & ind, T1 p1);

template <typename T>
IT into(T & t, std::vector<indicator> & ind);

Example:

int count;
sql << "select count(*) from person", into(count);

See Binding local data for more examples.

function use

The function use is used for binding local input data (in other words, it defines where the parameters of the query come from).

template <typename T>
IT use(T & t);

template <typename T, typename T1>
IT use(T & t, T1 p1);

template <typename T>
IT use(T & t, indicator & ind);

template <typename T, typename T1>
IT use(T & t, indicator & ind, T1 p1);

template <typename T>
IT use(T & t, std::vector<indicator> const & ind);

template <typename T, typename T1>
IT use(T & t, std::vector<indicator> const & ind, T1 p1);

Example:

int val = 7;
sql << "insert into numbers(val) values(:val)", use(val);

See Binding local data for more examples.

class statement

The statement class encapsulates the prepared statement.

class statement
{
public:
    statement(session & s);
    statement(IT const & prep);
    ~statement();

    statement(statement const & other);
    void operator=(statement const & other);

    void alloc();
    void bind(values & v);
    void exchange(IT const & i);
    void exchange(IT const & u);
    void clean_up();

    void prepare(std::string const & query);
    void define_and_bind();

    bool execute(bool withDataExchange = false);
    long long get_affected_rows();
    bool fetch();

    bool got_data() const;

    void describe();
    void set_row(row * r);
    void exchange_for_rowset(IT const & i);

    details::statement_backend * get_backend();
};

This class contains the following members:

  • Constructor accepting the session object. This can be used for later query preparation. Example:
    statement stmt(sql);
    
  • Constructor accepting the result of using prepare on the session object, see example provided above for the session class.
  • Copy operations.
  • alloc function, which allocates necessary internal resources.
  • bind function, which is used to bind the values object - this is used in the object-relational mapping and normally called automatically.
  • exchange functions for registering the binding of local data - they expect the result of calling the into or use functions and are normally invoked automatically.
  • clean_up function for cleaning up resources, normally called automatically.
  • prepare function for preparing the statement for repeated execution.
  • define_and_bind function for actually executing the registered bindings, normally called automatically.
  • execute function for executing the statement. If its parameter is false then there is no data exchange with locally bound variables (this form should be used if later fetch of multiple rows is foreseen). Returns true if there was at least one row of data returned.
  • get_affected_rows function returns the number of rows affected by the last statement. Returns -1 if it's not implemented by the backend being used.
  • fetch function for retrieving the next portion of the result. Returns true if there was new data.
  • got_data return true if the most recent execution returned any rows.
  • describe function for extracting the type information for the result (note: no data is exchanged). This is normally called automatically and only when dynamic resultset binding is used.
  • set_row function for associating the statement and row objects, normally called automatically.
  • exchange_for_rowset as a special case for binding rowset objects.
  • get_backend function that returns the internal pointer to the concrete backend implementation of the statement object. This is provided for advanced users that need access to the functionality that is not otherwise available.

See Statement preparation and repeated execution for example uses.

Most of the functions from the statement class interface are called automatically, but can be also used explicitly. See Interfaces for the description of various way to use this interface.

class procedure

The procedure class encapsulates the call to the stored procedure and is aimed for higher portability of the client code.

class procedure
{
public:
    procedure(IT const & prep);

    bool execute(bool withDataExchange = false);
    bool fetch();
    bool got_data() const;
};

The constructor expects the result of using prepare on the session object.

See Stored procedures for examples.

class type_conversion

The type_conversion class is a traits class that is supposed to be provided (specialized) by the user for defining conversions to and from one of the basic SOCI types.

template <typename T>
struct type_conversion
{
    typedef T base_type;

    static void from_base(base_type const & in, indicator ind, T & out);

    static void to_base(T const & in, base_type & out, indicator & ind);
};

Users are supposed to properly implement the from_base and to_base functions in their specializations of this template class.

See Extending SOCI to support custom (user-defined) C++ types.

class row

The row class encapsulates the data and type information retrieved for the single row when the dynamic rowset binding is used.

class row
{
public:
    row();
    ~row();

    void uppercase_column_names(bool forceToUpper);

    std::size_t size() const;

    indicator get_indicator(std::size_t pos) const;
    indicator get_indicator(std::string const & name) const;

    column_properties const & get_properties (std::size_t pos) const;
    column_properties const & get_properties (std::string const & name) const;

    template <typename T>
    T get(std::size_t pos) const;

    template <typename T>
    T get(std::size_t pos, T const & nullValue) const;

    template <typename T>
    T get(std::string const & name) const;

    template <typename T>
    T get(std::string const & name, T const & nullValue) const;

    template <typename T>
    row const & operator>>(T & value) const;

    void skip(std::size_t num = 1) const;

    void reset_get_counter() const
};

This class contains the following members:

  • Default constructor that allows to declare a row variable.
  • uppercase_column_names - see the same function in the session class.
  • size function that returns the number of columns in the row.
  • get_indicator function that returns the indicator value for the given column (column is specified by position - starting from 0 - or by name).
  • get_properties function that returns the properties of the column given by position (starting from 0) or by name.
  • get functions that return the value of the column given by position or name. If the column contains null, then these functions either return the provided "default" nullValue or throw an exception.
  • operator>> for convenience stream-like extraction interface. Subsequent calls to this function are equivalent to calling get with increasing position parameter, starting from the beginning.
  • skip and reset_get_counter allow to change the order of data extraction for the above operator.

See Dynamic resultset binding for examples.

class column_properties

The column_properties class provides the type and name information about the particular column in a rowset.

class column_properties
{
public:
    std::string get_name() const;
    data_type get_data_type() const;
};

This class contains the following members:

  • get_name function that returns the name of the column.
  • get_data_type that returns the type of the column.

See Dynamic resultset binding for examples.

class values

The values class encapsulates the data and type information and is used for object-relational mapping.

class values
{
public:
    values();

    void uppercase_column_names(bool forceToUpper);

    indicator get_indicator(std::size_t pos) const;
    indicator get_indicator(std::string const & name) const;

    template <typename T>
    T get(std::size_t pos) const;

    template <typename T>
    T get(std::size_t pos, T const & nullValue) const;

    template <typename T>
    T get(std::string const & name) const;
    
    template <typename T>
    T get(std::string const & name, T const & nullValue) const;

    template <typename T>
    values const & operator>>(T & value) const;

    void skip(std::size_t num = 1) const;
    void reset_get_counter() const;
    
    template <typename T>
    void set(std::string const & name, T const & value, indicator indic = i_ok);

    template <typename T>
    void set(const T & value, indicator indic = i_ok);

    template <typename T>
    values & operator<<(T const & value);
};

This class contains the same members as the row class (with the same meaning) plus:

  • set function for storing values in named columns or in subsequent positions.
  • operator<< for convenience.

See Object-relational mapping for examples.

class blob

The blob class encapsulates the "large object" functionality.

class blob
{
public:
    explicit blob(session & s);
    ~blob();

    std::size_t getLen();
    std::size_t read(std::size_t offset, char * buf, std::size_t toRead);
    std::size_t write(std::size_t offset, char const * buf, std::size_t toWrite);
    std::size_t append(char const * buf, std::size_t toWrite);
    void trim(std::size_t newLen);

    details::blob_backend * get_backend();
};

This class contains the following members:

  • Constructor associating the blob object with the session object.
  • get_len function that returns the size of the BLOB object.
  • read function that reads the BLOB data into provided buffer.
  • write function that writes the BLOB data from provided buffer.
  • append function that appends to the existing BLOB data.
  • trim function that truncates the existing data to the new length.
  • get_backend function that returns the internal pointer to the concrete backend implementation of the BLOB object. This is provided for advanced users that need access to the functionality that is not otherwise available.

See Large objects (BLOBs) for more discussion.

class rowid

The rowid class encapsulates the "row identifier" object.

class rowid
{
public:
    explicit rowid(Session & s);
    ~rowid();

    details::rowid_backend * get_backend();
};

This class contains the following members:

  • Constructor associating the rowid object with the session object.
  • get_backend function that returns the internal pointer to the concrete backend implementation of the rowid object.

class backend_factory

The backend_factory class provides the abstract interface for concrete backend factories.

struct backend_factory
{
    virtual details::session_backend * make_session(
        std::string const & connectString) const = 0;
};

The only member of this class is the make_session function that is supposed to create concrete backend implementation of the session object.

Objects of this type are declared by each backend and should be provided to the constructor of the session class. In simple programs users do not need to use this class directly, but the example use is:

backend_factory & factory = postgresql;
std::string connectionParameters = "dbname=mydb";

session sql(factory, parameters);

Simple client interface

The simple client interface is provided with other languages in mind, to allow easy integration of the SOCI library with script interpreters and those languages that have the ability to link directly with object files using the "C" calling convention.

The functionality of this interface is limited and in particular the dynamic rowset description and type conversions are not supported in this release. On the other hand, the important feature of this interface is that it does not require passing pointers to data managed by the user, because all data is handled at the SOCI side. This should make it easier to integrate SOCI with languages that have constrained ability to understand the C type system.

Users of this interface need to explicitly #include <soci-simple.h>.

typedef void * session_handle;
session_handle soci_create_session(char const * connectionString);
void soci_destroy_session(session_handle s);

void soci_begin(session_handle s);
void soci_commit(session_handle s);
void soci_rollback(session_handle s);

int soci_session_state(session_handle s);
char const * soci_session_error_message(session_handle s);

The functions above provide the session abstraction with the help of opaque handle. The soci_session_state function returns 1 if there was no error during the most recently executed function and 0 otherwise, in which case the soci_session_error_message can be used to obtain a human-readable error description.

Note that the only function that cannot report all errors this way is soci_create_session, which returns NULL if it was not possible to create an internal object representing the session. However, if the proxy object was created, but the connection could not be established for whatever reason, the error message can be obtained in the regular way.

typedef void * statement_handle;
statement_handle soci_create_statement(session_handle s);
void soci_destroy_statement(statement_handle st);

int soci_statement_state(statement_handle s);
char const * soci_statement_error_message(statement_handle s);

The functions above create and destroy the statement object. If the statement cannot be created by the soci_create_statement function, the error condition is set up in the related session object; for all other functions the error condition is set in the statement object itself.

int soci_into_string   (statement_handle st);
int soci_into_int      (statement_handle st);
int soci_into_long_long(statement_handle st);
int soci_into_double   (statement_handle st);
int soci_into_date     (statement_handle st);

int soci_into_string_v   (statement_handle st);
int soci_into_int_v      (statement_handle st);
int soci_into_long_long_v(statement_handle st);
int soci_into_double_v   (statement_handle st);
int soci_into_date_v     (statement_handle st);

These functions create new data items for storing query results (into elements). These elements can be later identified by their position, which is counted from 0. For convenience, these function return the position of the currently added element. In case of error, -1 is returned and the error condition is set in the statement object.

The _v versions create a vector into elements, which can be used to retrieve whole arrays of results.

int soci_get_into_state(statement_handle st, int position);
int soci_get_into_state_v(statement_handle st, int position, int index);

This function returns 1 if the into element at the given position has non-null value and 0 otherwise. The _v version works with vector elements and expects an array index.

int  soci_into_get_size_v(statement_handle st);
void soci_into_resize_v  (statement_handle st, int new_size);

The functions above allow to get and set the size of vector into element.

Note: the soci_into_resize_v always sets all into vectors in the given statement to the same size, which guarantees that all vector into elements have equal size.

char const * soci_get_into_string   (statement_handle st, int position);
int          soci_get_into_int      (statement_handle st, int position);
long long    soci_get_into_long_long(statement_handle st, int position);
double       soci_get_into_double   (statement_handle st, int position);
char const * soci_get_into_date     (statement_handle st, int position);

char const * soci_get_into_string_v   (statement_handle st, int position, int index);
int          soci_get_into_int_v      (statement_handle st, int position, int index);
long long    soci_get_into_long_long_v(statement_handle st, int position, int index);
double       soci_get_into_double_v   (statement_handle st, int position, int index);
char const * soci_get_into_date_v     (statement_handle st, int position, int index);

The functions above allow to retrieve the current value of the given into element.

Note: the date function returns the date value in the "YYYY MM DD HH mm ss" string format.

void soci_use_string   (statement_handle st, char const * name);
void soci_use_int      (statement_handle st, char const * name);
void soci_use_long_long(statement_handle st, char const * name);
void soci_use_double   (statement_handle st, char const * name);
void soci_use_date     (statement_handle st, char const * name);

void soci_use_string_v   (statement_handle st, char const * name);
void soci_use_int_v      (statement_handle st, char const * name);
void soci_use_long_long_v(statement_handle st, char const * name);
void soci_use_double_v   (statement_handle st, char const * name);
void soci_use_date_v     (statement_handle st, char const * name);

The functions above allow to create new data elements that will be used to provide data to the query (use elements). The new elements can be later identified by given name, which must be unique for the given statement.

void soci_set_use_state(statement_handle st, char const * name, int state);

The soci_set_use_state function allows to set the state of the given use element. If the state parameter is set to non-zero the use element is considered non-null (which is also the default state after creating the use element).

int  soci_use_get_size_v(statement_handle st);
void soci_use_resize_v  (statement_handle st, int new_size);

These functions get and set the size of vector use elements (see comments for vector into elements above).

void soci_set_use_string   (statement_handle st, char const * name, char const * val);
void soci_set_use_int      (statement_handle st, char const * name, int val);
void soci_set_use_long_long(statement_handle st, char const * name, long long val);
void soci_set_use_double   (statement_handle st, char const * name, double val);
void soci_set_use_date     (statement_handle st, char const * name, char const * val);

void soci_set_use_state_v    (statement_handle st, char const * name, int index, int state);
void soci_set_use_string_v   (statement_handle st, char const * name, int index, char const * val);
void soci_set_use_int_v      (statement_handle st, char const * name, int index, int val);
void soci_set_use_long_long_v(statement_handle st, char const * name, int index, long long val);
void soci_set_use_double_v   (statement_handle st, char const * name, int index, double val);
void soci_set_use_date_v     (statement_handle st, char const * name, int index, char const * val);

The functions above set the value of the given use element, for both single and vector elements.

Note: the expected format for the data values is "YYYY MM DD HH mm ss".

int          soci_get_use_state    (statement_handle st, char const * name);
char const * soci_get_use_string   (statement_handle st, char const * name);
int          soci_get_use_int      (statement_handle st, char const * name);
long long    soci_get_use_long_long(statement_handle st, char const * name);
double       soci_get_use_double   (statement_handle st, char const * name);
char const * soci_get_use_date     (statement_handle st, char const * name);

These functions allow to inspect the state and value of named use elements.

Note: these functions are provide only for single use elements, not for vectors; the rationale for this is that modifiable use elements are not supported for bulk operations.

void soci_prepare(statement_handle st, char const * query);
int  soci_execute(statement_handle st, int withDataExchange);
int  soci_fetch(statement_handle st);
int  soci_got_data(statement_handle st);

The functions above provide the core execution functionality for the statement object and their meaning is equivalent to the respective functions in the core C++ interface described above.

soci-3.2.3/doc/connections.html0000644000000000000000000001452412511362240015131 0ustar rootroot SOCI - connections

Connections and simple queries

Connecting to the database

The session class encapsulates the database connection and other backend-related details, which are common to all the statements that will be later executed. It has a couple of overloaded constructors.

The most basic one expects two parameters: the requested backend factory object and the generic connection string, which meaning is backend-dependent.

Example:

session sql(oracle, "service=orcl user=scott password=tiger");

Another example might be:

session sql(postgresql, "dbname=mydb");

Above, the sql object is a local (automatic) object that encapsulates the connection.

This session constructor either connects successfully, or throws an exception.

Another constructor allows to name backends at run-time and supports the dynamically loadable backends, which have to be compiled as shared libraries. The usage is similar to the above, but instead of providing the factory object, the backend name is expected:

session sql("postgresql", "dbname=mydb");

For convenience, the URL-like form that combines both the backend name with connection parameters is supported as well:

session sql("postgresql://dbname=mydb");

The last two constructors described above try to locate the shared library with the name libsoci_ABC.so (or libsoci_ABC.dll on Windows), where ABC is the backend name. In the above examples, the expected library name will be libsoci_postgresql.so for Unix-like systems.

The most general form of the constructor takes a single object of connection_parameters type which contains a pointer to the backend to use, the connection string and also any connection options. Using this constructor is the only way to pass any non-default options to the backend. For example, to suppress any interactive prompts when using ODBC backend you could do:

connection_parameters parameters("odbc", "DSN=mydb");
parameters.set_option(odbc_option_driver_complete, "0" /* SQL_DRIVER_NOPROMPT */);
session sql(parameters);
Notice that you need to #include <soci-odbc.h> to obtain the option name declaration. The existing options are described in the backend-specific part of the documentation.

Environment configuration:

The SOCI_BACKENDS_PATH environment variable defines the set of paths where the shared libraries will be searched for. There can be many paths, separated by colons, and they are used from left to right until the library with the appropriate name is found. If this variable is not set or is empty, the current directory is used as a default path for dynamically loaded backends.

The run-time selection of backends is also supported with libraries linked statically. Each backend provides a separate function of the form register_factory_name, where name is a backend name. Thus:

extern "C" void register_factory_postgresql();
// ...
register_factory_postgresql();
session sql("postgresql://dbname=mydb");

The above example registers the backend for PostgreSQL and later creates the session object for that backend. This form is provided for those projects that prefer static linking but still wish to benefit from run-time backend selection.

An alternative way to set up the session is to create it in the disconnected state and connect later:

session sql;

// some time later:
sql.open(postgresql, "dbname=mydb");

// or:
sql.open("postgresql://dbname=mydb");

// or also:
connection_parameters parameters("postgresql", "dbname=mydb");
sql.open(parameters);

The rules for backend naming are the same as with the constructors described above.

The session can be also explicitly closed and reconnected, which can help with basic session error recovery. The reconnect function has no parameters and attempts to use the same values as those provided with earlier constructor or open calls.

See also the page devoted to multithreading for a detailed description of connection pools.

It is possible to have many active sessions at the same time, even using different backends.

Portability note:

The following backend factories are currently (as of 3.1.0 release) available:

  • mysql (requires #include "soci-mysql.h")
  • oracle (requires #include "soci-oracle.h")
  • postgresql (requires #include "soci-postgresql.h")

The following backends are also available, with various levels of completeness:

  • sqlite3 (requires #include "soci-sqlite3.h")
  • odbc (requires #include "soci-odbc.h")
  • firebird (requires #include "soci-firebird.h")
soci-3.2.3/doc/languages/0000755000000000000000000000000012511362240013661 5ustar rootrootsoci-3.2.3/doc/languages/ada/0000755000000000000000000000000012511362240014406 5ustar rootrootsoci-3.2.3/doc/languages/ada/idioms.html0000644000000000000000000002522612511362240016567 0ustar rootroot SOCI-Ada - documentation

SOCI-Ada - manual

Common Idioms

As any other library, SOCI-Ada has its set of idioms that ensure optimal work in terms of performance and resource usage. Still, the optimal use will depend on the concrete usage scenario - the places where programmer choices are needed will be described explicitly.

The idioms below are provided as complete programs with the intent to make them more understandable and to give complete context of use for each idiom. The programs assume that the target database is PostgreSQL, but this can be changed by a different connection string in each place where the sessions are established. The programs use the Ada 2005 interface and some minor changes will be required to adapt them for Ada 95 compilers.

Single query without data transfer

This type of query is useful for DDL commands and can be executed directly on the given session, without explicit statement management.

with SOCI;

procedure My_Program is

   SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");

begin

   SQL.Execute ("drop table some_table");

end My_Program;

Note:

The session object is initialized by a constructor function call. An alternative would be to declare it without initialization and later use the Open operation to establish a physical connection with the database.

Simple query without parameters resulting in one row of data

This type of query requires only single into elements, which together with the statement have to be manipulated explicitly.

with SOCI;
with Ada.Text_IO;

procedure My_Program is

   SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
   St : SOCI.Statement := SOCI.Make_Statement (SQL);
   Pos : SOCI.Into_Position;

   Num_Of_Persons : SOCI.DB_Integer;

begin

   Pos := St.Into_Integer;
   St.Prepare ("select count(*) from persons");
   St.Execute (True);

   Num_Of_Persons := St.Get_Into_Integer (Pos);

   Ada.Text_IO.Put_Line ("Number of persons: " & SOCI.DB_Integer'Image (Num_Of_Persons));

end My_Program;

Note:

The into element is inspected by providing the position value that was obtained at the time if was created. No operations are defined for the position type. There can be many into elements with a single query.

Simple query with parameters and without results

This type of query requires only use elements.

with SOCI;

procedure My_Program is

   SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
   St : SOCI.Statement := SOCI.Make_Statement (SQL);

begin

   St.Use_Integer ("increase");
   St.Set_Use_Integer ("increase", 1000);

   St.Prepare ("update persons set salary = salary + :increase");
   St.Execute (True);

end My_Program;

Note:

The ":increase" in the query is a placeholder variable. There can be many such variables and each of them needs to be filled in by respective use element.

Repeated query with parameters and without results

This type of query requires only use elements, but they can be set differently for each statement execution.

with SOCI;

procedure My_Program is

   SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
   St : SOCI.Statement := SOCI.Make_Statement (SQL);

begin

   St.Use_String ("name");

   St.Prepare ("insert into countries(country_name) values(:name)");

   St.Set_Use_String ("name", "Poland");
   St.Execute (True);

   St.Set_Use_String ("name", "Switzerland");
   St.Execute (True);

   St.Set_Use_String ("name", "France");
   St.Execute (True);

end My_Program;

Note:

Each time the query is executed, the current values of use elements are transferred to the database.

Batch query with parameters and without results

This type of query requires vector use elements. Compare with the previous example.

with SOCI;

procedure My_Program is

   SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
   St : SOCI.Statement := SOCI.Make_Statement (SQL);
   First : SOCI.Vector_Index;

   use type SOCI.Vector_Index;

begin

   St.Use_Vector_String ("name");

   St.Use_Vectors_Resize (3);

   First := St.Use_Vectors_First_Index;

   St.Set_Use_Vector_String ("name", First + 0, "Poland");
   St.Set_Use_Vector_String ("name", First + 1, "Switzerland");
   St.Set_Use_Vector_String ("name", First + 2, "France");

   St.Prepare ("insert into countries(country_name) values(:name)");
   St.Execute (True);

end My_Program;

Note:

The whole bunch of data is transferred to the database if the target database server supports it and the statement is automatically repeated otherwise. This is the preferred way to transfer many rows of data to the server when the data for all rows are known before executing the query.

Note:

The query can be executed many times and each time a new batch of data can be transferred to the server. The size of the batch (set by calling Use_Vectors_Resize) can be different each time the query is executed, but cannot be larger than the size that was used the first time. The size of the batch defines a tradeoff between the amount of data being transmitted in a single step (this influences the memory used by the user program and the time of a single call) and the number of executions required to handle big data sets. The optimal size of the batch will therefore differ depending on the application, but in general tens of thousands is a reasonable limit for a batch size - the performance of the whole operation is usually not affected above this value so there is no need to imply higher memory usage at the client side.

Simple query with many rows of results

This type of query requires simple into elements.

with SOCI;
with Ada.Text_IO;

procedure My_Program is

   SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
   St : SOCI.Statement := SOCI.Make_Statement (SQL);
   Pos : SOCI.Into_Position;

begin

   Pos := St.Into_String;

   St.Prepare ("select country_name from countries");
   St.Execute;

   while St.Fetch loop

      Ada.Text_IO.Put_Line (St.Get_Into_String (Pos));

   end loop;

end My_Program;

Note:

The loop above executes as many times as there are rows in the result. After each row is read, the into elements contain the respective values from that row. The Execute operation is called without parameter, which is False by default, meaning that no data transfer is intended. The data is being transferred only during the Fetch operation, which returns False when no data has been retrieved and the result is exhausted.

This type of query can have simple parameters which are fixed at the execution time.

Batch query with many rows of results

This type of query requires vector into elements. Compare with previous example.

with SOCI;
with Ada.Text_IO;

procedure My_Program is

   SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
   St : SOCI.Statement := SOCI.Make_Statement (SQL);
   Pos : SOCI.Into_Position;

   Batch_Size : constant := 10;

begin

   Pos := St.Into_Vector_String;
   St.Into_Vectors_Resize (Batch_Size);

   St.Prepare ("select country_name from countries");
   St.Execute;

   while St.Fetch loop

      for I in St.Into_Vectors_First_Index .. St.Into_Vectors_Last_Index loop

         Ada.Text_IO.Put_Line (St.Get_Into_Vector_String (Pos, I));

      end loop;

      St.Into_Vectors_Resize (Batch_Size);

   end loop;

end My_Program;

Note:

The loop above is nested. The outer while loop fetches consecutive batches of rows from the database with requested batch size; the returned batch can be smaller than requested (the into vector elements are downsized automatically if needed) and the intended batch size is requested again before repeating the Fetch operation. For each returned batch, the into vector elements are inspected in the inner for loop. This scheme ensures correct operation independently on the size of returned batch and is therefore a recommended idiom for efficiently returning many rows of data.

There is a tradeoff between efficiency and memory usage and this tradeoff is controlled by the requested batch size. Similarly to one of the examples above, there is no benefit from using batches bigger than tens of thousands of rows.

This type of query can have simple (not vectors) parameters that are fixed at execution time.

Final note:

Follow good database usage principles and avoid constructing queries by concatenating strings computed at run-time. Thanks to a good type system Ada is much better in preventing various SQL-injection attacks than weaker languages like PHP, but there is still a potential for vulnerability or at least performance loss. As a rule of thumb, rely on use elements to parameterize your queries and to provide clean separation between data and code. This will prevent many security vulnerabilities and will allow some servers to optimize their work by reusing already cached execution plans.

soci-3.2.3/doc/languages/ada/reference.html0000644000000000000000000005514712511362240017246 0ustar rootroot SOCI-Ada - documentation

SOCI-Ada - manual

API Reference

The SOCI-Ada library is entirely implemented as a single package named SOCI. Additional child packages contain single procedures for static registration of backends - these child packages are not necessary for typical use, but can be useful to force static linking of backend code.

The following describes all publicly visible elements of this package:


   --
   --  General exception related to database and library usage.
   --

   Database_Error : exception;

Each problem related to the interaction with the database or to the incorrect usage of the library itself is signalled by raising this exception. Each occurrence of this exception has some human-readable error message that can be obtained by a call to Ada.Exceptions.Exception_Message.


   --
   --  Session.
   --

   type Session is tagged limited private;

   not overriding
   function Make_Session (Connection_String : in String) return Session;

   not overriding
   procedure Open (This : in out Session; Connection_String : in String);

   not overriding
   procedure Close (This : in out Session);

   not overriding
   function Is_Open (This : in Session) return Boolean;

The Session object can exist in two states: "connected" (or "open") and "disconnected". It can be created as connected at initialization time with a call to the constructor function Make_Session or left default-initialized in the disconnected state and later changed to connected with Open (the latter option is the only that is available in the Ada 95 version of the library). Session objects can be also associated with the connection pool, see below.

The Connection_String should have the form "backendname://parameters", where backendname is used to construct the name of the dynamically loadable library that will be used to provide specific database services. Backends included in the current distribution of the main SOCI library are:

  • oracle (implemented as libsoci_oracle.so or libsoci_oracle.dll)
  • postgresql (implemented as libsoci_postgresql.so or libsoci_postgresql.dll)
  • mysql (implemented as libsoci_mysql.so or libsoci_mysql.dll)

Other backends can be added to the library in the future or by the user himself, please see the documentation of the main SOCI library for details.

The parameters component of the Connection_String depends on the given backend, please see the documentation of the main SOCI project for the meaning and recognized options. The web pages related to the backends above are:

The Open operation can be called only in the disconnected state (which changes the state of Session object to connected). The Close operation can be called in any state (provided that the session is not associated with the connection pool, see below) and after that the Session is in the disconnected state.

Session objects are closed automatically as part of their finalization. If the Session object is associated with the connection pool, the finalizer detaches from the pool without closing the connection.


   --  Transaction management.

   not overriding
   procedure Start (This : in Session);

   not overriding
   procedure Commit (This : in Session);

   not overriding
   procedure Rollback (This : in Session);

These operations handle transactions. The exact meaning of transactions and whether transactions are automatic for some kinds of statements (and which ones) depend on the target database.


   --  Immediate query execution.
   not overriding
   procedure Execute (This : in Session; Query : in String);

This operation allows to create implicit statement, prepare it for the given Query and execute it.


   --
   --  Connection pool management.
   --

   type Connection_Pool (Size : Positive) is tagged limited private;

   not overriding
   procedure Open
     (This : in out Connection_Pool;
      Position : in Positive;
      Connection_String : in String);

   not overriding
   procedure Close (This : in out Connection_Pool; Position : in Positive);

   not overriding
   procedure Lease (This : in out Connection_Pool; S : in out Session'Class);

The Connection_Pool encapsulates a fixed-size collection of sessions. Individual sessions are indexed from 1 to Size (provided as discriminant) and can be Opened and Closed explicitly. Each connection in the pool can be created with different Connection_String, if needed.

The Lease operation allows to associate a given Session object (that has to be in the disconnected state itself) with one connection from the pool. The pool guarantees that at most one task can lease a given connection from the pool. If there are no free connections in the pool, the Lease operation will block waiting until some connection is freed.

The Session object that is associated with a connection from the pool automatically gives it back to pool as part of the Session's finalizer. There is no other way to "detach" from the pool.

Note:

It is assumed that the lifetime of Connection_Pool encloses the lifetimes of all Session objects that are leased from it. There is no particular protection against it and it is possible to construct a code example with allocators that create partially overlapping Connection_Pool and Session, but this is considered obscure and not representative to the actual use scenarios. To avoid any potential problems, create Connection_Pool in the scope that encloses the scopes of leased Sessions.


   --
   --  Statement.
   --

   type Statement (<>) is tagged limited private;

   type Data_State is (Data_Null, Data_Not_Null);

   type Into_Position is private;

   type Vector_Index is new Natural;

The Statement type and supporting types. Data_State is used to indicate null values in the database sense - each value of into or use elements has a state from this type.

Into_Position is used to identify into elements. Vector_Index is used to name individual entries in vector into and use elements.


   not overriding
   function Make_Statement (Sess : in Session'Class) return Statement;

   --  Ada 95 version:
   --  procedure Make_Statement (This : in out Statement; Sess : in Session'Class);

Construction function for creating Statement objects. The Statement is associated with one Session for its whole lifetime.


   --  Statement preparation and execution.

   not overriding
   procedure Prepare (This : in Statement; Query : in String);

   not overriding
   procedure Execute
     (This : in Statement;
      With_Data_Exchange : in Boolean := False);

   not overriding
   function Execute
     (This : in Statement;
      With_Data_Exchange : in Boolean := False) return Boolean;

   not overriding
   function Fetch (This : in Statement) return Boolean;

   not overriding
   function Got_Data (This : in Statement) return Boolean;

The Prepare operation needs to be called before any other operation in the above group and it prepares the execution for the given Query. No into and use elements can be created after this operation is called.

The Execute operations cause the statement to execute, which might be combined with data exchange if requested. The function version of this operation returns True if some data has been returned back from the database server.

The Fetch function is used to transfer next portion of data (a single row or a whole bunch) from the database server and returns True if some data has been fetched. If this function returns False it means that no new data will be ever fetched for this statement and indicates the end-of-row condition.

The Got_Data function returns True if the last execution or fetch resulted in some data being transmitted from the database server.


   --
   --  Data items handling.
   --

   --  Database-specific types.
   --  These types are most likely identical to standard Integer,
   --  Long_Long_Integer and Long_Float, but are defined distinctly
   --  to avoid interfacing problems with other compilers.

   type DB_Integer is new Interfaces.C.int;
   type DB_Long_Long_Integer is new Interfaces.Integer_64;
   type DB_Long_Float is new Interfaces.C.double;

The data types used for interaction with the database are:

  • String
  • DB_Integer, defined above
  • DB_Long_Long_Integer, defined above
  • DB_Long_Float, defined above
  • Ada.Calendar.Time

   --  Creation of single into elements.

   not overriding
   function Into_String (This : in Statement) return Into_Position;

   not overriding
   function Into_Integer (This : in Statement) return Into_Position;

   not overriding
   function Into_Long_Long_Integer (This : in Statement) return Into_Position;

   not overriding
   function Into_Long_Float (This : in Statement) return Into_Position;

   not overriding
   function Into_Time (This : in Statement) return Into_Position;

These functions instruct the library to create internal simple into elements of the relevant type. They return the position of the into element, which can be later used to identify it.

Note:

Simple into elements cannot be created together with vector into elements for the same statement.


   --  Creation of vector into elements.

   not overriding
   function Into_Vector_String (This : in Statement) return Into_Position;

   not overriding
   function Into_Vector_Integer (This : in Statement) return Into_Position;

   not overriding
   function Into_Vector_Long_Long_Integer (This : in Statement) return Into_Position;

   not overriding
   function Into_Vector_Long_Float (This : in Statement) return Into_Position;

   not overriding
   function Into_Vector_Time (This : in Statement) return Into_Position;

These functions instruct the library to create internal vector into elements of the relevant type. They return the position of the into element, which can be later used to identify it.

Note:

Vector into elements are empty (they have size 0) after they are created and have to be resized before any data is written to them.

Note:

Simple into elements cannot be created together with vector into elements for the same statement.


   --  Inspection of single into elements.

   not overriding
   function Get_Into_State
     (This : in Statement;
      Position : in Into_Position)
     return Data_State;

   not overriding
   function Get_Into_String
     (This : in Statement;
      Position : in Into_Position)
     return String;

   not overriding
   function Get_Into_Integer
     (This : in Statement;
      Position : in Into_Position)
     return DB_Integer;

   not overriding
   function Get_Into_Long_Long_Integer
     (This : in Statement;
      Position : in Into_Position)
     return DB_Long_Long_Integer;

   not overriding
   function Get_Into_Long_Float
     (This : in Statement;
      Position : in Into_Position)
     return DB_Long_Float;

   not overriding
   function Get_Into_Time
     (This : in Statement;
      Position : in Into_Position)
     return Ada.Calendar.Time;

These functions allow to inspect the state and value of the simple into element identified by its position. If the state of the given element is Data_Null, the data-reading functions raise exceptions for that element.


   --  Inspection of vector into elements.

   not overriding
   function Get_Into_Vectors_Size (This : in Statement) return Natural;

   not overriding
   function Into_Vectors_First_Index (This : in Statement) return Vector_Index;

   not overriding
   function Into_Vectors_Last_Index (This : in Statement) return Vector_Index;

   not overriding
   procedure Into_Vectors_Resize (This : in Statement; New_Size : in Natural);

The Get_Into_Vectors_Size returns the number of entries in any of the vector into elements for the given statement.

The Into_Vectors_First_Index returns the lowest index value for vector into elements (which is always 0, even if the vectors are empty). The Into_Vectors_Last_Index returns the last index of into vectors, and raises the CONSTRAINT_ERROR exception if the vectors are empty.

The Into_Vectors_Resize procedure allows to change the size of all use vectors for the given statement.


   not overriding
   function Get_Into_Vector_State
     (This : in Statement;
      Position : in Into_Position;
      Index : in Vector_Index)
     return Data_State;

   not overriding
   function Get_Into_Vector_String
     (This : in Statement;
      Position : in Into_Position;
      Index : in Vector_Index)
     return String;

   not overriding
   function Get_Into_Vector_Integer
     (This : in Statement;
      Position : in Into_Position;
      Index : in Vector_Index)
     return DB_Integer;

   not overriding
   function Get_Into_Vector_Long_Long_Integer
     (This : in Statement;
      Position : in Into_Position;
      Index : in Vector_Index)
     return DB_Long_Long_Integer;

   not overriding
   function Get_Into_Vector_Long_Float
     (This : in Statement;
      Position : in Into_Position;
      Index : in Vector_Index)
     return DB_Long_Float;

   not overriding
   function Get_Into_Vector_Time
     (This : in Statement;
      Position : in Into_Position;
      Index : in Vector_Index)
     return Ada.Calendar.Time;

These functions allow to inspect the state and value of the vector use element identified by its position and index. If the state of the given element is Data_Null, the data-reading functions raise exceptions for that element.


   --  Creation of single use elements.

   not overriding
   procedure Use_String (This : in Statement; Name : in String);

   not overriding
   procedure Use_Integer (This : in Statement; Name : in String);

   not overriding
   procedure Use_Long_Long_Integer (This : in Statement; Name : in String);

   not overriding
   procedure Use_Long_Float (This : in Statement; Name : in String);

   not overriding
   procedure Use_Time (This : in Statement; Name : in String);

These functions instruct the library to create internal simple use elements of the relevant type, identified by the given Name.

Note:

Simple use elements cannot be created together with vector use elements for the same statement.

Vector use elements cannot be created together with any into elements for the same statement.


   --  Creation of vector use elements.

   not overriding
   procedure Use_Vector_String (This : in Statement; Name : in String);

   not overriding
   procedure Use_Vector_Integer (This : in Statement; Name : in String);

   not overriding
   procedure Use_Vector_Long_Long_Integer (This : in Statement; Name : in String);

   not overriding
   procedure Use_Vector_Long_Float (This : in Statement; Name : in String);

   not overriding
   procedure Use_Vector_Time (This : in Statement; Name : in String);

These functions instruct the library to create internal vector use elements of the relevant type, identified by the given Name.

Note:

Simple use elements cannot be created together with vector use elements for the same statement.

Vector use elements cannot be created together with any into elements for the same statement.


   --  Modifiers for single use elements.

   not overriding
   procedure Set_Use_State
     (This : in Statement;
      Name : in String;
      State : in Data_State);

   not overriding
   procedure Set_Use_String
     (This : in Statement;
      Name : in String;
      Value : in String);

   not overriding
   procedure Set_Use_Integer
     (This : in Statement;
      Name : in String;
      Value : in DB_Integer);

   not overriding
   procedure Set_Use_Long_Long_Integer
     (This : in Statement;
      Name : in String;
      Value : in DB_Long_Long_Integer);

   not overriding
   procedure Set_Use_Long_Float
     (This : in Statement;
      Name : in String;
      Value : in DB_Long_Float);

   not overriding
   procedure Set_Use_Time
     (This : in Statement;
      Name : in String;
      Value : in Ada.Calendar.Time);

These operations allow to modify the state and value of simple use elements. Setting the value of use element automatically sets its state to Data_Not_Null.


   --  Modifiers for vector use elements.

   not overriding
   function Get_Use_Vectors_Size (This : in Statement) return Natural;

   not overriding
   function Use_Vectors_First_Index (This : in Statement) return Vector_Index;

   not overriding
   function Use_Vectors_Last_Index (This : in Statement) return Vector_Index;

   not overriding
   procedure Use_Vectors_Resize (This : in Statement; New_Size : in Natural);

The Get_Use_Vectors_Size returns the number of entries in any of the vector use elements for the given statement.

The Use_Vectors_First_Index returns the lowest index value for vector use elements (which is always 0, even if the vectors are empty). The Use_Vectors_Last_Index returns the last index of use vectors, and raises the CONSTRAINT_ERROR exception if the vectors are empty.

The Use_Vectors_Resize procedure allows to change the size of all use vectors for the given statement.


   not overriding
   procedure Set_Use_Vector_State
     (This : in Statement;
      Name : in String;
      Index : in Vector_Index;
      State : in Data_State);

   not overriding
   procedure Set_Use_Vector_String
     (This : in Statement;
      Name : in String;
      Index : in Vector_Index;
      Value : in String);

   not overriding
   procedure Set_Use_Vector_Integer
     (This : in Statement;
      Name : in String;
      Index : in Vector_Index;
      Value : in DB_Integer);

   not overriding
   procedure Set_Use_Vector_Long_Long_Integer
     (This : in Statement;
      Name : in String;
      Index : in Vector_Index;
      Value : in DB_Long_Long_Integer);

   not overriding
   procedure Set_Use_Vector_Long_Float
     (This : in Statement;
      Name : in String;
      Index : in Vector_Index;
      Value : in DB_Long_Float);

   not overriding
   procedure Set_Use_Vector_Time
     (This : in Statement;
      Name : in String;
      Index : in Vector_Index;
      Value : in Ada.Calendar.Time);

These operations allow to modify the state and value of vector use elements. Setting the value of use element automatically sets its state to Data_Not_Null.


   --  Inspection of single use elements.
   --
   --  Note: Use elements can be modified by the database if they
   --        are bound to out and inout parameters of stored procedures
   --        (although this is not supported by all database backends).
   --        This feature is available only for single use elements.

   not overriding
   function Get_Use_State
     (This : in Statement;
      Name : in String)
     return Data_State;

   not overriding
   function Get_Use_String
     (This : in Statement;
      Name : in String)
     return String;

   not overriding
   function Get_Use_Integer
     (This : in Statement;
      Name : in String)
     return DB_Integer;

   not overriding
   function Get_Use_Long_Long_Integer
     (This : in Statement;
      Name : in String)
     return DB_Long_Long_Integer;

   not overriding
   function Get_Use_Long_Float
     (This : in Statement;
      Name : in String)
     return DB_Long_Float;

   not overriding
   function Get_Use_Time
     (This : in Statement;
      Name : in String)
     return Ada.Calendar.Time;

These functions allow to inspect the state and value of the simple use element identified by its name. If the state of the given element is Data_Null, the data-reading functions raise exceptions for that element.

soci-3.2.3/doc/languages/ada/index.html0000644000000000000000000000636512511362240016415 0ustar rootroot SOCI-Ada Language Binding - documentation

SOCI-Ada Language Binding - documentation

Introduction
Compilation
Concepts
Common Idioms
API Reference


Introduction

SOCI-Ada is a database access library for Ada.

The library itself is a wrapper for the selected functionality of the SOCI library, which is a C++ database access library recognized for its high quality and innovative interface.

The SOCI-Ada library offers the following features to the Ada community:

Currently the following database servers are directly supported via their native interfaces:

  • Oracle
  • PostgreSQL
  • MySQL

Other backends exist in the SOCI Git repository and can be provided with future version of the library.

Compilation

In order to use SOCI-Ada, compile the C++ parts first (core and required backends).

Note: SOCI header files are not needed to use SOCI-Ada, only compiled SOCI libraries (core and relevant backend) need to exist to build and use SOCI-Ada programs.

The SOCI-Ada library itself is a single package named SOCI. This package can be just imported in the target project as is or pre-built to the binary form if required.

In order to link the user programs the -lsoci_core -lstdc++ linker options need to be provided on the Unix/Linux platforms.

soci-3.2.3/doc/languages/ada/style.css0000644000000000000000000000156412511362240016266 0ustar rootrootbody { background-color: white; color: black; margin-left: 100px; margin-right: 100px; font-family: arial, sans-serif; font-size: small; } div.note { border-color: black; border-style: dotted; border-width: 1px; margin-top: 20px; padding-left: 20px; padding-right: 20px; } span.note { font-size: large; font-weight: bold; } code { /* font-weight: bold; */ background-color: white; color: #8B0000; /* font-size: large; */ } pre.example { background-color: #F0F0F0; color: black; border-width: 1px; border-style: dashed; border-color: blue; padding: 10px 10px 10px 10px; } table.foot-links { width: 100%; padding-top: 20px; } td.foot-link-left { text-align: left; } td.foot-link-right { text-align: right; } p.copyright { border-top-color: black; border-top-style: solid; border-top-width: 1px; padding-top: 5px; } soci-3.2.3/doc/languages/ada/concepts.html0000644000000000000000000001010512511362240017107 0ustar rootroot SOCI-Ada - documentation

SOCI-Ada - manual

Concepts

The SOCI-Ada library borrows its concepts and naming from the main SOCI project. They are shortly explained here in the bottom-up fashion.

One of the main properties of the library is that the data objects which are bound for transfer to and from the database server are managed by the library itself and are not directly visible from the user code. This ensures that no aliasing of objects occurs between Ada and underlying C++ code, which makes the inter-language interface easier and more resilient to the differences in how compilers handle the linkage. As a direct result of this design choice, users of SOCI-Ada need to instruct the library to internally create all objects that will be subject to data transfer.

There are two kinds of objects that can be managed by the SOCI-Ada library:

  • Into elements, which are data objects that are transferred from the database to the user program as a result of executing a query. There are single into elements for binding single rows of results and vector into elements for binding whole bunches of data corresponding to whole result sets or their subranges. The into elements are identified by their position.
  • Use elements, which are data objects that are transferred from the user program to the database as parameters of the query (and, if supported by the target database, that can be modified by the database server and transferred back to the user program). There are single use elements for binding parameters of single-row queries and vector use elements for binding whole bunches of data for transfer. The use elements are identified by their name.

The user program can read the current value of into and use elements and assign new values to use elements. Elements are strongly typed and the following types are currently supported:

  • String
  • SOCI.DB_Integer, which is defined by the library in terms of Interfaces.C.int
  • SOCI.DB_Long_Long_Integer, which is defined in terms of Interfaces.Integer_64
  • SOCI.DB_Long_Float, which is defined in terms of Interfaces.C.double
  • Ada.Calendar.Time

Both into and use elements are managed for a single statement, which can be prepared once and executed once or many times, with data transfer handled during execution or fetch phase.

Statements can be managed explicitly, which is required if they are to be used repeteadly or when data transfer is needed or implicitly, which is a shorthand notation that is particularly useful with simple queries or DDL commands.

All statements are handled within the context of some session, which also supports transactions.

Sessions can be managed in isolation or as a group called connection pool, which helps to decouple tasking design choices from the concurrency policies at the database connection level. Sessions are leased from the pool for some time during which no other task can access them and returned back when no longer needed, where they can be acquired again by other tasks.

All potential problems are signalled via exceptions that have some descriptive message attached to them.

soci-3.2.3/doc/structure.odg0000644000000000000000000007164312511362240014461 0ustar rootrootPKr8.++mimetypeapplication/vnd.oasis.opendocument.graphicsPKr8Configurations2/statusbar/PKr8'Configurations2/accelerator/current.xmlPKPKr8Configurations2/floater/PKr8Configurations2/popupmenu/PKr8Configurations2/progressbar/PKr8Configurations2/menubar/PKr8Configurations2/toolbar/PKr8Configurations2/images/Bitmaps/PKr8ϣ[[-Pictures/10000000000000200000002000309F1C.pngPNG  IHDR DPLTE3f333f3333f3ffffff3f̙3f3f333f333333333f33333333f33f3ff3f3f3f3333f33̙33333f3333333f3333f3ffffff3f33ff3f3f3f3fff3ffffffffffff3ffff̙fff3fffffff3ffffff3f333f3333f3ffffff3f̙̙3̙f̙̙̙̙3f3f̙333f3̙333f3fff̙fff3f̙̙3f̙3f̙3f333f3333f3ffffff3f̙3f3fOIDATxc'F*U0RU<4IENDB`PKr8 content.xml[o+w @f٘$@[SҝbZ`7Zl6Jrlc_, -sÏǞO4^HQRݍa4,n}bqLC2XLIV!*x:+Rz7Zٔᒖ V$k]K&l.YWCnφ,QWC.k2cQOs\/ ͞FʧZcbndb ip"ZQhJltSRqݮK2bphpz5/H *\nԵ|pv̏9\bp ~8Tqmő 'm^кn/TaA͔]{X*7]k[k):I'aq !4tSD<۔VpARUuζ)S =8SvNpLK-ˊqP#$Gxk^(Ѩ.1x"F=s22΋=y |z4qp&z^@RLc@3A'>Y`f<8sƿeEͮ _UKi%xyVYR4To%4mK $ej#z -sqMd` LeiugR-al+bQXXνCf sH=A!%;Ӱ蔶ڒn'A9jƝG T9'ަfH~j٫WZ۫ LIeJB^H^JΗow?1$4 ۗM:cIeGL+]h]Ka?ѸS1tni)sM wOT熐< l1dxr.!d7! n2B"dMFȿXrQN{\0Bid],DuG\/ͣ5`ƢM{Q%~8#MrͯQnN+a.NujٟII=Gj8pYv6c\FH =elE]`z9I;^s#IY[V#{6{EX5mnQ`MyO*p3+yA|G0Ƽn(0焥*6JVdY|~ۖj.H.rF!|`'6}-5tCh &Fl NzS֫)8~ڣxhQ5-Z?su ?{)67[&6],CIbx}NMX?p&M[탃|5sw*0vđ~5%,[>mjY7ܑBvGIM#ZYI;ZzrEa~WVx"ZyK~tDR.G/%st97h 3>,R 6fZuچB@ qHx6TH!!~I!3,̣( #J"n-VTvDGds cYKF!l9b8aL$Q놵9aH\T9놦%km lE xfhבU$o=yG05(79سȓ-.r=C@syvS. i) Ā\"UJ.Фp6ѼQ[}s6}Xvr$PFXPBmDаjsΘQx" B hEGMh%ƍhEhsab2>u(j"i252i9ꐑ,:P17hX 0lsĐ|X& uE$L>}~x?_]poͧF4e1L#S_à\>[=L0zqZg>fu$=Fd͠+\ xNR1xe'&C(/}\ pxBBZ8 B/3N sj]XwsCٳEM)P5)TSjimQu_&afijY51Y=q庯cn4TRN;jDj?gz ;%m~1fvD Mew>4K]i_Czj)(l Թ6ۮҁ5l,OX" Bi^/T?#5t71Soh%=/mϰ0vEw mvr-Sjz:OWζ`=gXd>JԖoi2'3tg@KW/Ӓ$\疤_׮lvu]kW}Z]kWyuum WVVYU)}y{}^[YCXY0.0EzS[#r[}{(8Ë>i؝SR H*lkygфR0As;yL)%Z|%4,ͷ>$Cؗl Ʊ2ؓ5/C4aiѰ:p-NG#FNCkjME7&"Rr]Ƌ?QP027dنH֕+DgHlN2LGGyӝwk)=o0 i].fx&4,Z-_0BgSG^o#^‘_H( ѾuM;tU}GG7d ǷcBV{MrE3c@\,;0&?(;]&p"Yic;cЖ8wB?l=t TG:o7T3F~Re$5|+e҂ls(o\=V+ϟ zA{IKtrIݖQ vJ.i+fn!~ֆݓAĻ܋WNpL8YqI5E`i!KyاUr0)zL9m7L߃HZ&{V[AML4ޥKp˾x\h~gdȓeB!3|:~^%_F2zЛ #&SP΃ (SeM/VF0+e r_:x 'E!@ T@we^ 8i  88d k ̿UU%8jl֌Whl>QKNK~ˆlOc-&F]HƐ[\ [7䘯GQwZvlf[i=Z<*Nr7Y4&#a8N'.S?BPv{F [#jd1Pq \4ډ؜嫅=&o=JPE*1zyUdr0a!,f(䝔CI~ȣM<{hVչ&KQB6t >&[kg70ʒOSq^O_w#1|XZ(/a NG\ C7 乵]YBƫu c8Q+H[1gӃ@9GS?߆tR*!JlViW)ߒ>{ 76opCLSE`SN\20x !*ՏEaul#]Xv.Ëw͠_so[R'#1/@ɤ?XyEk>]VF}DVcNJ2XˢG-ـ=[Qt>yR#ۺ]OB cENsNBhߘZ޹=a5GWo!89&;_6cmJ#>&f\~oJ$6'"(EB m}Hyw|zHWGy{:L]op$rh'_)ݚؒ-TYmh> :6 -0*:[+d[<V?6}T/)w?q)DWjh\fAE<8}vqI)a:_c{JE.mD1%IqX4$UczF@M0&Xno|j]{T~R*|fnIn=LT\A1Pg\i3[a2D{-C!S}u ag¤Oȭ}\G _ -(,2&ՀwۗІZzۯDf6:Ut}(ǏN,WZ$.v/2|aU'emmLlHQkY$#(ujb<_Rs)C@3c@}*B@V\?3Œ! +ڪl|3/0Nɚv8 !%C4TJx;:gȶθw*o>\xa - +0:Zu#iI#RQ3)9S.p|ءh:VHAivAٜʥw؜X$w(W̘ KJ@]t3bL+sFSw_ s[ڢ.}"Si {}C_qRd&{t?-\OW*V>oF?o]sQU!D`_g5? sΓJ'{qtx,mHIj%S|9Sԍ^SADJ21UGKZ'`q9r]aP'Z[ÝXx]=>uۼҬ>:˪?v;怵#IyA33ʞ YMS5!f"7$,7 -F\"ZJ粉/N亷LG%HWRYg]$R} .;1~sy .-oе]{w1qq<_3FW%׃2"2TUEշ+ a~x2Nl`>g?~ۚz\obP'Uld˿^aRy7Gv̂`uz3 E=^HD=|!=)a$瘚f 8r?>bmDx'L\J:,Z7HR>|AFd M.E"p8櫱ж#ֈ1X%,q5 #O+񸊂e /퍴` b߽ aAA-D}{ ROPF_,~\T@ 6sx'VRjꆡq_z/g%}ݬ騸~"TNA|)G [ {\yՐ'&NmG-YScryޫ3t4 unʋ017o>SP?4!kaVۆW,#TȸxFDJ7m*lhճm[շ_PK J'PKr8Thumbnails/thumbnail.pdf{T\M(Np\ !%xpN #߷wgouUuUuUݞsRʋ1Y({{Z{~d!0@cS'3;F(fndw21652Gptr0ַFp69Mр:vb% :yzOo +TҞ'9kGŽe.3b&*3X zkZ`n!xݺmy?} :yŰ9YP^4r8|d`R5J$ E"RB#0Y^(1ԛ:oJ %gL }馪/vh?GF-֋gEIĵ}ϪF0(\<0y#ާl:> 8U52d1m>c d]0*5vpga^J|H.m}CR^VÌW]$oDz(Ƴql(NÌ홵tRۮǺ:8wΡҳ%mgoE&.,[W{(gK,_mSO þSuMs~:XE(JG(O3aՁNk:,'e=Jے |Ց' Rv쟽G0W9t=im$UeHU&cԫ@Ԕɴ1gBö{S*TEeBe/Go'vKzl;ч< JuigMd},}#KdqE)4ԟ#,B+ _FHmtx:15>SdQި_*|~aOve(E=c;T?7Idj\s}:wO7ǒL%t)vckpݘ+ؘ& 'P~0RКS9ym|1Ɯ2{ykl3Fe.BCuL m=DNu۔'r%m)̀cQn-`dw"臧Дw2>nV-Oa#QD\+Q^2ܵF!N`@΍d-SE:8)Р_ϔ@xY$..ζ3t[qL$w44_S3(n;.UU \IC CwSI_sUٮ,n@4#|D(k@c͞u3*\ |˴M.Rd5*1Ezo"7We(Y %R xܸe 1ϣfJ@Xte|.qC!EFX8oRg h`S P4 KHcBVaj$G>X0d}$v<|ϐVؖ.=!S8z%+=xfbm|鰨x)6+d4i߭[4-&@%ILZi昇DA.!Fe+vaz0 [] a>fKI ,Dnddod0!i:~)4S3^Dy(Alxw_UTS?kj 04 d{@${9eQYn G޵XW"SejrTG B(TWjmQ0)Ch>ZR-Oir'[x []EjQ,=)UnYzMo_.f'q(!xj*yٲ:e6NYJނپu(39*:7n&kUsxY2J| m|`E01GXQXb,?8qgؘY^S9oZeKK1`J_B:VN(7VV^BBb-ovhU&_t+\f`Kf;2}8wqM4_8*ThLӈ9fӲ,;Fi.9}aVͷI!Di^[j+SlBr|;s|ӼτWswJO3.MFwuCӫK2=w6",c~ƚ5V\~+0{lM y>QpīSxGtLtL%[[Xlߺ7q#ffR"X̦XmQZ,E(08Ā Oy&m40 UB9ng}&1q`ҾGL`b1qIrBx_/`DžpqC0ruq|׋4Ifͨ123t' cV%Y42yBm/CFV6AJuNL Fe}`yVQ@VQ ERs,pf\ &{fu[y[G()l q? aerJs.kxOPL_ jP*n ǷĜ~?="أR''j 74bԴ#;HV%op05"GE ݊$䂨K%C4:. 6Kd~6$0s\نT Ƒ<~Hq11;װ{gϸX} B/nJ:P(=82\H'VUHh<8;:ȆƤ|{#qTE~ 6X stߡ)o˫ǜi{צi *6[TĿeF#Vfܭ&o*%BD!3+(ىxlr:q?Xcs]~ ?L: )’SsҺx ~pvt|6 4:o2b0[J&5N H$@A!YHd6cbPF~Y4W%HƵHءH~Uw?C axWWjL*o2 F3nYqRmNYGiii49iiЗe2۾h!4?VTe"1-X6=_Mc4tvJ!*Av ! 0o3u?BA_ |kK-ڂm^Z&vHf~Oq -|_6*o%%>?lO/!7_;X\dT#34%a J_!V˩qx͢pRk<eh7^[k~ho96J!@y3'*&Ȑ&YOa_6Szee'?/4sRGc~|%gW5{~eUvDFҤS,-`zv`HyΰH7$0yq:rOj]TEȰ_?YY*3:[bT9,7iY+,¿-4N]]7^\%+VLr%V!elJGHM @wי)w qYcq秏ukuFDP>&DH Vzd0gin*x@_ɨA<4̜ӼQzeTJ?s|@U8Oղkxnrfzw뉺%]u YkFť։!MK1ywY|!oqMHTC^-Wlx#[xe\9TA5̇@@oY_8S03fƎ{hmK!i}wZ*{u(pݛqCrgn+]G}A}$Wb>~23p!@$x#%K '=G[u]5fE,zVA6_m ^2oQҨÜc$ŒI6;%o3"e871`u2̝8iSV_a#PH ?n:`wYtͺ@drֲw1 p߶e)bT{b7 UFCի1 V\Ǻ$51 1(-ތxcORF+ -69g^ ēܞu :'[S?TX Nm>C*JlcMbnW'BK5фA~'>zl'In+*p}Hwq"s>[Yw$OhW/ 6jpljʽPo`,ŬUcz5-4Q"7!8zrS8?RQhpPE_HdU.7C|o$P , %&ީ㮑 [|e.(1`h\qw,*XDS$-{| k {]Fo>vXF1q^/ ϐ&~5hXopEuKM=J, tޑA N2 [-6ң-\ފ)xyw"~XtP2gjhp1:- 7wZa 1}bmI1@ډ~~3A^s&{+#, ׍H7dA߹Mg,jp+R2:9LC~Ay`t\CJD6 qeow&cx7֝K=QI6p_E/hkss-V 4"M#| =rk(70) -Z@-z`x(9N>`kPyE7nFb/{+}8)ry!8|eWcW3S$agcޑ nսO[f>4aw0~*zo02R4c&C;4FpFRMf}PREriM3C$Mᒃ a-Gg[]?Nd/=?xFzZ8 A3atm!1LyR[P 5U0z}gba;\a?ϫm*{]4\T6B(ƯXlHќ.D)=ݫHƪlݎg^JZ+Ր];M3Ž&Z>UTzBf0[>0 V˩(q,{r o%ǏYNáZ>2Y-U/>?CAƔ7Yΰ9z^2(UJ$v8XhШ煬3u]]\LRtڔ5|{TQ_L[kճid%`v vk$bmcæaі d5NUKIP! 蘕y Ґ O]ʣ n,5; oVQyyu r}e),]*":%l!ה S-iTOGH42RYx:pN0* _inƅ\f/]AGbisF37*qpB5[)ƃҼP]/s<-鼚pEZbH nkͶr@jnT y.Noq3snѷ eBYAaJA'ywbGnCnI_€kWRY/T+je^g{m_$V-&q=",;l+e\CC By{HQۤKȯҸm*t֊|\exKp0< J74E9s忹C4#`jVTyhυFFi\su}K|uT0\_vŝs,)vB ̄Nf3kg8Fٮ3ͳ)$2pe:Wl-T$ɅFzؚl1>dݸQ+b^@bC BLzonh*QI.\8 I5B󕂘KȊ,~ظ[T7(43jX4ǂp4i`l{:n5+ &N>9uͥ4:N89t ma8sw1D4p!|"%Ĭ?(`ptmD O52挌ԑԖP|¢]&5~+3#wx{b99ƖrwvX ٴ-<B4IP&~l i Fg B'J07Z$Ve:אPq0>ط!ڏ·)<ϬKT"=[,]5h"jSEA0s/H>|jd&=7 yc!Q*ADžZyt&jtE9zg8󓋋'i^[ILbLb >*FoWraj bpMኰ{j/E7/~Hș9E?|ܴEE$M<&ӵ+aՔ6yo<ͣ>D~ @L°YǓދ^W5feH˃[P 0e*A]lcՆA1dtP=5z'$O WAc2[n W OͮbaI`܉Dl \J^ny*<ywja|NKh{eQ%d*i*즶n諬50NoZF@R/lJBI=0*Nsv}N A8/EC ~EHfr{4¬lO"oXR]7={EvDOqElK5bґOa4uGg]5 +VKkYŽ7y|;wK+!R_${,|f&DKd% _ [m>r:x2sWUQGxחU)Cghp5@؝IE Ƚ,'n#z2*LN?Q^]ºBS({)I,:sSSFT϶2oMU6 |q4WfsV\l* 蓒eK$?im,lݽ+0pplH.{#K0$7z_a\Sԯ[ ]]RVͻ\CDm'N6)G~TH)o3g̶v\|kor\ `̇92 zQVBTt){L]݈r5RJ ê^P'Xg)1< kGGo|+xx̅2Apur%DN`ci4D 1 _P09rqIOфC#/UB l C}rYOt}%+RAbh=: {! < vj#=bjcrGvF rr\o.lJ'd &!nKh^G ('IlˏI3UIצ1V=l}^(lk;HTn,8I8^.^jMB8Jau (Q,\!i@0o. =&YX+ K6 Tq 5ܣ2/[Tx 9y'Ikԫ~:]<5:KPm;{ks|t0H B2lnA2bbl /N+ϯ'DwGmOF@OKm[C3"335-.k".<غ'qvUU!W5t»+dWx(7!OIvc[gD6E8h&]z3!0J3rt=WV1/_yIIET4-MϠݯJyӉ`>(_1KƦ٣Q@Y_50azj>?~#Hr⴩„[}戀O]u!"(*w5ºGR~BxM3Jj-+ ଴ i{,-wqC8s[\}f8|҅Rɦ;kLqI۷Y&M@*$T-s>\Ϫ$o~pNYK%|`D!_?B02b;R u))lPL(Ag"FKzy-#[/ LeVt2AW(z܂WF9tKkWqUW G"馢 KO*~ؒޕ+ "9qӯ<>ga$ِ淡uX!5y~t;]_0E,D)KlrҀfpiRW[A6|~oȇUl)X@T7_"zʂok(T~9THo]y}D}+b6N"ƎvN ַ0675sp0A7uuF]ħOn-ff?d& b,oП룐2(oen(dcjenPZ codnc `yW*fnd.n? bcf[13NS `8Y{w8_\`foYlN?9尳sug K3/#3a_Կt4q5v6pkl7ᓾo G#1sG'a3}RBF31+4Tַ'_!1r1#b@㏡MQD;*;iEĀnNkڿfY(P^O'Yzy] E{FkS.6'+6P]һm0t +?.Ɗ⟀w |D3b#ـ/#f{dFZ mW:ߟ4[ӿuhg;c!C's[e546VVwLۋ,)'++33W8 I}'%q7iәX;f?wx7MDɘFss06AxvXyX&q v&wOE86&csqu!8??wӻҘPPHFggt]QV3ƞV{ZDʥ|J)yvVhWvM67i"StQ"mk9J 'Op=7Zoenb*vzfQr^(QqekPg"0 M*X*ݣ\/w`CJ!rݢav9"; )cuڒ'P<'"/FcY/{>D! b*,B)GuE>O_hdd縆$׈GhV"KQ8Ra+#L!#4]a;MaTYo xQBvw~d)E x]u[I6 x.a"Vwntf3fDE44^"uXfqJhD`a *))تΈ[ذǢ <ozf 'erÒذۑ툡>d xASCw ^.z5*K?:1|2sr+Aj8mGq],-Y*4O=ѣ/rZ\Q] vURBPg,L j]d.>t(1VL8&ˉE`k_ J*(\CfHEzBgcEת2ݍ5HH̍9CNHE;%N'U T=Y5}KP?v 1e;1ճ-c+j{=I+0cNIfO'͇ ebt$5~ʨ#QxUPah UrGI '}Irث RX}9*'r{J{a*tI( %[Q ~2,">ݿFgO߿_uyϛU aΧ/N# 'q2eҞۇ['PKaS&$PKr8META-INF/manifest.xmlQo +[Խld&>JBp?jv[̥;53Vni @*,~g6XFt%:0CeoZ=ewp4q?gwJtvP1VRPM]\\PQ^&h;AqS64 .8{!N2xo3f2+V$;낋 ${ztCO'ku2D uaRǃ="BA%dL;NWB>yo1ENoi'}D\:J#prfjUxumVPKmAjtPKr8.++mimetypePKr8QConfigurations2/statusbar/PKr8'Configurations2/accelerator/current.xmlPKr8Configurations2/floater/PKr8Configurations2/popupmenu/PKr8NConfigurations2/progressbar/PKr8Configurations2/menubar/PKr8Configurations2/toolbar/PKr8Configurations2/images/Bitmaps/PKr8ϣ[[-1Pictures/10000000000000200000002000309F1C.pngPKr8hvi content.xmlPKr8X}bmM hJ styles.xmlPKr8QU meta.xmlPKr8 J'Thumbnails/thumbnail.pngPKr8aܨl?`BV(Thumbnails/thumbnail.pdfPKr8aS&$ hsettings.xmlPKr8mAjtQmMETA-INF/manifest.xmlPKnsoci-3.2.3/doc/installation.html0000644000000000000000000005604512511401144015311 0ustar rootroot SOCI - structure

Installation

Requirements

Below is an overall list of SOCI core:

and backend-specific dependencies:

Downloading

Download package with latest release of the SOCI source code: soci-X.Y.Z, where X.Y.Z is the version number. Unpack the archive.

You can always clone SOCI from the Git repository:

git clone git://github.com/SOCI/soci.git

Building using CMake

SOCI is configured to build using CMake system in version 2.8+.

The build configuration allows to control various aspects of compilation and installation by setting common CMake variables that change behaviour, describe system or control build (see CMake help) as well as SOCI-specific variables described below. All these variables are available regardless of platform or compilation toolset used.

Running CMake from the command line allows to set variables in the CMake cache with the following syntax: -DVARIABLE:TYPE=VALUE. If you are new to CMake, you may find the tutorial Running CMake helpful.

The following tables provide summary of variables accepted by CMake scripts configuring SOCI build. The lists consist of common variables for SOCI core and all backends as well as variables specific to SOCI backends and their direct dependencies.

List of a few essential CMake variables
CMAKE_BUILD_TYPE string Specifies the build type for make based generators (see CMake help).
CMAKE_INSTALL_PREFIX path Install directory used by install command (see CMake help).
CMAKE_VERBOSE_MAKEFILE boolean If ON, create verbose makefile (see CMake help).
List of variables to control common SOCI features and dependencies
SOCI_STATIC boolean Request to build static libraries, along with shared, of SOCI core and all successfully configured backends.
SOCI_TESTS boolean Request to build regression tests for SOCI core and all successfully configured backends.
WITH_BOOST boolean Should CMake try to detect Boost C++ Libraries. If ON, CMake will try to find Boost headers and binaries of Boost.Date_Time library.

IBM DB2

SOCI DB2 backend configuration
WITH_DB2 boolean Should CMake try to detect IBM DB2 Call Level Interface (CLI) library.
DB2_INCLUDE_DIR string Path to DB2 CLI include directories where CMake should look for sqlcli1.h header.
DB2_LIBRARIES string Full paths to db2 or db2api libraries to link SOCI against to enable the backend support.
SOCI_DB2 boolean Requests to build DB2 backend. Automatically switched on, if WITH_DB2 is set to ON.
SOCI_DB2_TEST_CONNSTR string See DB2 backend refernece for details. Example: -DSOCI_DB2_TEST_CONNSTR:STRING="DSN=SAMPLE;Uid=db2inst1;Pwd=db2inst1;autocommit=off"

Firebird

SOCI Firebird backend configuration
WITH_FIREBIRD boolean Should CMake try to detect Firebird client library.
FIREBIRD_INCLUDE_DIR string Path to Firebird include directories where CMake should look for ibase.h header.
FIREBIRD_LIBRARIES string Full paths to Firebird fbclient or fbclient_ms libraries to link SOCI against to enable the backend support.
SOCI_FIREBIRD boolean Requests to build Firebird backend. Automatically switched on, if WITH_FIREBIRD is set to ON.
SOCI_FIREBIRD_TEST_CONNSTR string See Firebird backend refernece for details. Example: -DSOCI_FIREBIRD_TEST_CONNSTR:STRING="service=LOCALHOST:/tmp/soci_test.fdb user=SYSDBA password=masterkey"

MySQL

SOCI MySQL backend configuration
WITH_MYSQL boolean Should CMake try to detect mysqlclient libraries providing MySQL C API. Note, currently the mysql_config program is not being used.
MYSQL_DIR string Path to MySQL installation root directory. CMake will scan subdirectories MYSQL_DIR/include and MYSQL_DIR/lib respectively for MySQL headers and libraries.
MYSQL_INCLUDE_DIR string Path to MySQL include directory where CMake should look for mysql.h header.
MYSQL_LIBRARIES string Full paths to libraries to link SOCI against to enable the backend support.
SOCI_MYSQL boolean Requests to build MySQL backend. Automatically switched on, if WITH_MYSQL is set to ON.
SOCI_MYSQL_TEST_CONNSTR string Connection string to MySQL test database. Format of the string is explained MySQL backend refernece. Example: -DSOCI_MYSQL_TEST_CONNSTR:STRING="db=mydb user=mloskot password=secret"

ODBC

SOCI ODBC backend configuration
WITH_ODBC boolean Should CMake try to detect ODBC libraries. On Unix systems, CMake tries to find unixODBC or iODBC implementations.
ODBC_INCLUDE_DIR string Path to ODBC implementation include directories where CMake should look for sql.h header.
ODBC_LIBRARIES string Full paths to libraries to link SOCI against to enable the backend support.
SOCI_ODBC boolean Requests to build ODBC backend. Automatically switched on, if WITH_ODBC is set to ON.
SOCI_ODBC_TEST_{database}_CONNSTR string ODBC Data Source Name (DSN) or ODBC File Data Source Name (FILEDSN) to test database: Microsoft Access (.mdb), Microsoft SQL Server, MySQL, PostgreSQL or any other ODBC SQL data source. {database} is placeholder for name of database driver ACCESS, MYSQL, POSTGRESQL, etc. See ODBC backend refernece for details. Example: -DSOCI_ODBC_TEST_POSTGRESQL_CONNSTR="FILEDSN=/home/mloskot/dev/soci/_git/build/test-postgresql.dsn"

Oracle

SOCI Oracle backend configuration
WITH_ORACLE boolean Should CMake try to detect Oracle Call Interface (OCI) libraries.
ORACLE_INCLUDE_DIR string Path to Oracle include directory where CMake should look for oci.h header.
ORACLE_LIBRARIES string Full paths to libraries to link SOCI against to enable the backend support.
SOCI_ORACLE boolean Requests to build Oracle backend. Automatically switched on, if WITH_ORACLE is set to ON.
SOCI_ORACLE_TEST_CONNSTR string Connection string to Oracle test database. Format of the string is explained Oracle backend refernece. Example: -DSOCI_ORACLE_TEST_CONNSTR:STRING="service=orcl user=scott password=tiger"

PostgreSQL

SOCI PostgreSQL backend configuration
WITH_POSTGRESQL boolean Should CMake try to detect PostgreSQL client interface libraries. SOCI relies on libpq C library.
POSTGRESQL_INCLUDE_DIR string Path to PostgreSQL include directory where CMake should look for libpq-fe.h header.
POSTGRESQL_LIBRARIES string Full paths to libraries to link SOCI against to enable the backend support.
SOCI_POSTGRESQL boolean Requests to build PostgreSQL backend. Automatically switched on, if WITH_POSTGRESQL is set to ON.
SOCI_POSTGRESQL_TEST_CONNSTR boolean Connection string to PostgreSQL test database. Format of the string is explained PostgreSQL backend refernece. Example: -DSOCI_POSTGRESQL_TEST_CONNSTR:STRING="dbname=mydb user=mloskot"

SQLite 3

SOCI SQLite 3 backend configuration
WITH_SQLITE3 boolean Should CMak try to detect SQLite C/C++ library. As bonus, the configuration tries OSGeo4W distribution if OSGEO4W_ROOT environment variable is set.
SQLITE_INCLUDE_DIR string Path to SQLite 3 include directory where CMake should look for sqlite3.h header.
SQLITE_LIBRARIES string Full paths to libraries to link SOCI against to enable the backend support.
SOCI_SQLITE3 boolean Requests to build SQLite3 backend. Automatically switched on, if WITH_SQLITE3 is set to ON.
SOCI_SQLITE3_TEST_CONNSTR string Connection string is simply a file path where SQLite3 test database will be created (e.g. /home/john/soci_test.db). Check SQLite3 backend refernece for details. Example: -DSOCI_SQLITE3_TEST_CONNSTR="my.db"

Empty (sample backend)

SOCI empty sample backend configuration
SOCI_EMPTY boolean Builds the sample backend called Empty. Always ON by default.
SOCI_EMPTY_TEST_CONNSTR string Connection string used to run regression tests of the Empty backend. It is a dummy value. Example: -DSOCI_EMPTY_TEST_CONNSTR="dummy connection"

By default, CMake will try to determine availability of all depdendencies automatically. If you are lucky, you will not need to specify any of the CMake variables explained above. However, if CMake reports some of the core or backend-specific dependencies as missing, you will need specify relevant variables to tell CMake where to look for the required components.

CMake configures SOCI build performing sequence of steps. Each subsequent step is dependant on result of previous steps corresponding with particular feature. First, CMake checks system platform and compilation toolset. Next, CMake tries to find all external dependencies. Then, depending on the results of the dependency check, CMake determines SOCI backends which are possible to build. The SOCI-specific variables described above provide users with basic control of this behaviour.

Building using CMake on Unix

Short version using GNU Make makefiles:

$ mkdir build
$ cd build
$ cmake -G "Unix Makefiles" -DWITH_BOOST=OFF -DWITH_ORACLE=OFF (...) ../soci-X.Y.Z
$ make
$ make install

Building using CMake on Windows

Short version using Visual Studio 2010 and MSBuild:

C:\>MKDIR build
C:\>cd build
C:\build>cmake -G "Visual Studio 10" -DWITH_BOOST=OFF -DWITH_ORACLE=OFF (...) ..\soci-X.Y.Z
C:\build>msbuild.exe SOCI.sln

Building using classic Makefiles on Unix (deprecated)

NOTE: These Makefiles have not been maintained for long time. The officially maintained build configuration is CMake. If you still want to use these Makefiles, you've been warned that you may need to patch them.

The classic set of Makefiles for Unix/Linux systems is provided for those users who need complete control over the whole process and who can benefit from the basic scaffolding that they can extend on their own. In this sense, the basic Makefiles are supposed to provide a minimal starting point for custom experimentation and are not intended to be a complete build/installation solution.
At the same time, they are complete in the sense that they can compile the library with all test programs and for some users this level of support will be just fine.

The core directory of the library distribution contains the Makefile.basic that can be used to compile the core part of the library. Run make -f Makefile.basic or make -f Makefile.basic shared to get the static and shared versions, respectively. Similarly, the backends/name directory contains the backend part for each supported backend with the appropriate Makefile.basic and the backends/name/test directory contains the test program for the given backend.

For example, the simplest way to compile the static version of the library and the test program for PostgreSQL is:

$ cd src/core
$ make -f Makefile.basic
$ cd ../backends/postgresql
$ make -f Makefile.basic
$ cd test
$ make -f Makefile.basic

Note: For each backend and its test program, the Makefile.basics contain the variables that can have values specific to the given environment - they usually name the include and library paths. These variables are placed at the beginning of the Makefile.basics. Please review their values in case of any compilation problems.

The Makefiles for test programs can be a good starting point to find out correct compiler and linker options.

Running regression tests

The process of running regression tests highly depends on user's environment and build configuration, so it may be quite involving process. The CMake configuration provides variables to allow users willing to run the tests to configure build and specify database connection parameters (see the tables above for variable names).

In order to run regression tests, configure and build desired SOCI backends and prepare working database instances for them.

While configuring build with CMake, specify SOCI_TESTS=ON to enable building regression tests. Also, specify SOCI_{backend name}_TEST_CONNSTR variables to tell the tests runner how to connect with your test databases.

Dedicated make test target can be used to execute regression tests on build completion:

$ mkdir build
$ cd build
$ cmake -G "Unix Makefiles" -DWITH_BOOST=OFF \
   -DSOCI_TESTS=ON \
   -DSOCI_EMPTY_TEST_CONNSTR="dummy connection" \
   -DSOCI_SQLITE3_TEST_CONNSTR="test.db" \
   (...)
   ../soci-X.Y.Z
$ make
$ make test
$ make install

In the example above, regression tests for the sample Empty backend and SQLite 3 backend are configured for execution by make test target.

Libraries usage

CMake build produces set of shared and static libraries for SOCI core and backends separately. On Unix, for example, build/lib directory will consist of the static libraries named like libsoci_core.a, libsoci_sqlite3.a and shared libraries with names like libsoci_core.so.3.2.3, libsoci_sqlite3.so.3.2.3, and so on.

In order to use SOCI in your program, you need to specify your project build configuration with paths to SOCI headers and libraries, and specify linker to link against the libraries you want to use in your program.

soci-3.2.3/doc/interfaces.html0000644000000000000000000001001212511362240014716 0ustar rootroot SOCI - integration with Boost

Interfaces

One of the major features of SOCI, although not immediately visible, is the variety of interfaces (APIs) that are available for the user. These can be divided into sugar, core and simple.

Sugar

The most exposed and promoted interface supports the syntax sugar that makes SOCI similar in look and feel to embedded SQL. The example of application code using this interface is:

session sql("postgresql://dbname=mydb");

int id = 123;
string name;

sql << "select name from persons where id = :id", into(name), use(id);

Core

The above example is equivalent to the following, more explicit sequence of calls:

session sql("postgresql://dbname=mydb");

int id = 123;
string name;

statement st(sql);
st.exchange(into(name));
st.exchange(use(id));
st.alloc();
st.prepare("select name from persons where id = :id");
st.define_and_bind();
st.execute(true);

The value of the core interface is that it is the basis for all other interfaces, and can be also used by developers to easily prepare their own convenience interfaces. Users who cannot or for some reason do not want to use the natural sugar interface should try the core one as the foundation and access point to all SOCI functionality.

Note that the sugar interface wraps only those parts of the core that are related to data binding and query streaming.

Simple

The simple interface is provided specifically to allow easy integration of the SOCI library with other languages that have the ability to link with binaries using the "C" calling convention. To facilitate this integration, the simple interface does not use any pointers to data except C-style strings and opaque handles, but the consequence of this is that user data is managed by SOCI and not by user code. To avoid exceptions passing the module boundaries, all errors are reported as state variables of relevant objects.

The above examples can be rewritten as (without error-handling):

#include <soci-simple.h>

// ...
session_handle sql = soci_create_session("postgresql://dbname=mydb");

statement_handle st = soci_create_statement(sql);

soci_use_int(st, "id");
soci_set_use_int(st, "id", 123);

int namePosition = soci_into_string(st);

soci_prepare(st, "select name from persons where id = :id");

soci_execute(st, true);

char const * name = soci_get_into_string(st, namePosition);

printf("name is %s\n", name);

soci_destroy_statement(st);
soci_destroy_session(sql);

The simple interface supports single and bulk data exchange for static binding. Dynamic row description is not supported in this release.

See Simple client interface reference documentation for more details.

Low-level backend interface

The low-level backend interface allows to interact with backends directly and in principle allows to access the database without involving any other component. There is no particular reason to use this interface in the user code.

soci-3.2.3/doc/structure.png0000644000000000000000000006444712511362240014500 0ustar rootrootPNG  IHDRf5F pHYszhIDATx \׽ٟɒ@DIZ-Kk&!A4ph5懦4 P-ᦹiƴ7ћj[HX)4S Dksffwgq~py|̜8JqDz'}b\'< 1-H}2*_xIVuh~8)ԭiηq[p34#OTk|a'4"sI#ELREK<*~&8N'ǔ]9.F+'r}n>KeGQ;'b='d] v.%|-GǓth'nKJr/T;. \2p_cS4*ݖ-*'>Pn <}ܱt\0^UsĉJ硇ܬ=0 WuWtfMຠOw \G/Х5{?.;οu߽vZ0'!'Zn:B_`.4Ox ^ݸy%_h #t>yCh?v5۩pbO#w`Fsc'vv%w 옠Cḣ4YSfݳ|afXiii;/ro`~۟2c&sgLF}L[>~L `-6/<;G0T!hףyW ?'*rsmY–f &e&cNOnzkk\[{A*JRc)ǵ>TjkGerx:grGZjvag~gd۬sT^$Jgg&`dTLNg܁OW5\ m#FlBr \hSDG\>TZ[ZXLDiln XH0z ; _cF)_qG9<6gqdDI;`{ؕ&tY;~0ǂx$/cg[{㮬WRa< 2hI׹Q1G8ﳇˤ̏2IIV L7o-!cu3p7B~}0.Z%ĺvZCe~گʅS&[hy;-5'c-RhOf ϣ5S-,kԬy MN<5'XeOcO;*Nq88?W3kx#y=ňkgT)XކI%&0 |Er0ӄ##M.=A?}n+V4滺H xZ 6HJĿh[|*60qPwSS5qv"#.z'z*N<8w'F ><>1I- ]s$݈~ ?/NbPxFc[p3Ul5]::q{\q0R(tlXb>&,nGHSjo<%F>AFӄ[ h (RZJ_֞t٪xᝐC2͝S}iM3nZҺ,>$%sujO!.5i -c gMS!ۺk|̙Q`oo@$8a:%1ihosXhUZ Gjrk;NxBdxP{?!ip~kωNzC#-~5ӄW0N.Ѯe'N_> goƘK^@!V)ĿЍkmmB>4B#fφ?0#g-L3z RhfauQM^Ւò%6ڔq@3XPY#~ֶ$Mb??kmr=-uCz\3`mLGsM:#wV[L1t bN}wN^Ã3`/QddJGhY"YzB5چ{my"go) cP-ݥ߾aUފ7>&%5WrM#b#r02[ǽCxwSrօY5VO0#S}Z Y>l PHCv V/ceg{-'kG{Ƭ#)%kڔY+k9R?uم2>1rXw73k7 u{]jRlkk@wacq{v)0Bj2@1QS>&i}̏: ؛e&?&\ݾ.׶^]pc:ξNo& ʰ!yy+XVBlg9bKo{J8ZJZeĕb/^׶V"A.k&~ +G̱+(Q)Rv#.M<"fYƷ;H:Lm쵂wK?FtzF "o3[2Ǒ)Hg`Ix~+Uی_: #Oy,8ǿkdɑe{r18%VI\y?[mzZ|-8ak81X}҈bJs9 #Gc A\0EM+3CUɍz5x .G:5pVF u 2 Of P<.׃W4[ w;Kڤs-UK"x̐W.yt>̂[X"meܻ. 'F9$YK˛[_{zϻ= D|)Qm 5Аޓ8q"Y[.JS)|C[nM0a\Z[4B΁oxH aw.A5ɅWAZ?{QY/,OdK[(Kb25Fhu4g2q=N~doc?ڰ ?wiGu3̽ U:n"-)gޢOqx03`f?aCl!V }/GX./_$0AI}&%= ;:Ug #]I=qc ܦNQ9kk-K z[Q(~W> ě/=i#sCI FvZ؃nM2"*[y}qhG[PmS{󾫿xCh^ 8 -ii?=?/ںS$ qٲ\ۼ71A'G(Κg03lzκ'ZtM]y f4zj>q%DJ>9hZ ;gܳ||kJyMwͭhz +w64]Iķ8+ |{r~0)(4d 4$oL/4៭ _NJ8q ~)tt5~Н"l/Y، J l]VH(Y`Քxx+I-] |^g͑zkC˟zƥl,CY=r`% 6Dq撍`F&ŕ/^\ ͕JeP/F ДpmylL.[#?ŕ/~JKPC{ jh/1&g>wʪ[4t  5&uaϒ3cp.CP@#,^KPC{ O68֢]ZV͆3f6ff6hTSآx&EJSd^TCK 3ȭG[,1VϜD/cv$=/Q؆+lUcጧgJ|vAUU65=c)YqXU)lA))A>⳿FH˱=IOr,O8&OGc!ͯXV(^BpQٜ fEagqb\PC{ jh/A %5^ Zizds\Tl[5wq׀(Z-q-ru[mYؔq0)8Su=I_w&ZSb>;\֭Ko;}}6rbsљ=>|4=BYqT_;s)CXEc5]UJ12"w|(L Ђ?ͮvK&w,nbn}זqtY7z<]&Iph>F҄5yJoɂݛwh ʃsly3)J,r[1Q1 nV6qc7{ 5P܇@odn5W# ڊQP A[q9PWdE4T?izWE*۷V};'2u~.F:91CtmpimnҹK?8+&WfXbw4}=oG+UC=s5su\V@lTg`핎Ұ"߹,tO9s&s(ٰ ~@:+{Ƴ˴oblcFe\-ۢYf{Wic]tή>ȋHl\욖'n>#fŝQh L44H 2ɣб$ ^yMIFdhLxtR,^" 6K :}zՊaϥ-zʐ4鸵ɛ>J)޿B[jo | N|vm}?ge!O)2\֋HZl2t|I̢MZT~aTǛeޝv8jcYO xdM,O>"'gѪk)L4B]}C%8Y4A(~NF̲ZU F;}Ԯ|Ft1ֈ.aݱV}<0;9vg +Lph$!WܹrT;Ҟ+iʴj)Uy:|opBG%' E~4v 7iLZږ?ߑ0lggiisRw}!u򎇣?&f 7`i,KhkUV#&Ij!BX wZYDh }0"ְ?sn4L&F/Q)(}'l6C,BʴSԡ#"‰[8X)S2:%+2բ(L+vi_7rq]=@[Zb1낸܅𞮝вmo51 &l|*twڐ#!44H A2="Jֹ dP+ӗc*C1NUXXd]DoP[h F>vT3QSQ E{l[r\-9 sbvE11u\f) X˼dۨ3V2X_/-0`t U:ٚv5Jo-XBiaY& =*6IEzqV$9b܃]' . BW#o3#;S' _5cUKZ`b +Ӽ?oսT32VrXFA,+83.pGU!W":=3h-2e!Og k"B.VP$1?".o1qwTGBlsVFi-f1/hQWomti/#XM-_Zɮj. tIbI٬Sۄb Q\3G:7KB,?bu+iK|Q d-L3H A2M( AG4袶 <Ͱ h'L{ZH A2A{6'L{Bleh"s!aH(jhB1C{JdPJD* ٣Tgy ;kztfZSoCstW$`;K Nͭ@[IBeoql 浢':t {an4W[10Icևkq\ҩw% xrd }\*uUh>/l\xnJxdCMv)tusz3R" ϔ5s:O%:¶ [-g{Գ5ezjna[ΥW^,tzi6N4pUFTaϢKҠPU@GTa|ps-C~rō__:NAA|esZG,5/6벦m6k7Tռɟa/XR}sy阬6jY.3[Ѱ,A* &q8z Ux]k2{7ɿHd4>:0"m&?lɿ>.dq%'r̥[ l1#cқTز(J,]_,y-TA8^T%шHz*LF*0rѤ:o~xgH]RMdk&2_[髜!7T՚K2kbu䄵z[}8K*amazOKr!،Bμ`D!|e=xMO{Ǎ?^-GeKh%O'KU>ɡd LJCM.4&(ll\>Ʒer9J:I1-3Ga'D8ōWq(RE+m<^~R+ӄR!&44H a/Ӄ׺hn7*s]LbmUEN\>JR?-Hg}o[k+a3k9mʑ]'JSa G_PUq%)h!bXJUΕ/q閁;JT\3dOHKzKyoZVeuz |s 6wn,I<ӻdNt&|핎Ұ"1)jIbw4󿞸1ڡ>)bʸ1[E מkÅ2]G& +, gZ#;bogn=El@ȴO!ڃj;s)=%&& EZFTŰ}.~վg;]XWD?_?>z?Pձ3l]'r^%'Vom*~Ixgk ٯ+XOz~c|u[)̍6oùQIgs=+JnqO-;6acR1'ZQyt|B4Ff!_.>vO^Ši۠iXݕF1[ ](y0QP')o/]J7(g+H ,I?1hBF(bRggQbGb!,e{uZp'/WM>F8Tj w&^SVaXR&,#2GL`;"! zWp(,]p 鱨D=XViG~)*Q2GHoa{>/ñÊM0} Znaa.%0$cQ߅z5K>q#d=]1Wh+Q4s6 6t{{LOzu?H A2M( iBiLJdZiL+r2-n0VTe&J4,b핌@/EP4" vdːL{ }+H=پ$ӄ &44H /2<'ʫQ/2m@[?!{._dZ+=/}w`x5ue1[E1mio˴4t'%0xLĉ=,ʛ_=7xw]=MyK;"5-LJC)26AQrD:)kąHP`bGZn!-mP!Q8D~*/BMTI{ՉHI_g;"=/v满hZjYfwiۻczJXcAirl }[lDValf=yl6~y/7z6}O>ؘ{scۿ-F3)}fͽt~tДO-{SLKs/KKar^9nOz JDӿ]K6~3x>Gn|bTf5֩,1ɲ?2N, 4ۈ:f@vʗbοgyچW[vӿ=՚vϩi<+G975Ld6/n֧)-M/w`*0)^3n;T[oMSCXohޣcF8&"d:"wj-xQK1eO:)/ܲ@\hØ#L%~ a.R:)y6@zDztqh|eGu%-ojU;O0=V)]-]jGBkJK`sM~?nOm5p0wT9/e\4>&IROO#(4o T`25A̅v{W +,3*g]:C)2=;KIP'jc0"Al#A? FOwю!۱+;+Mu<~Rg <)3v[e hLwWP,9: v^h3ìo5ϲWL._mA cNټ sC;'8ޱ̴k_~rc|7+[~hodnx;Poߙ9f7ޡV>RL+1sZe>J߲{ O#F̟FToRbB)3l(iO\˿}[Yټ_cjG[u{ߺ{{|skn)Spʴ-CC8.|-C]ֳ;sWcHc _ځAe!#67Qb\*͋z\?wO\wKD6dxԅڄ1W`m#! l^Bw5J_1Z-/H? +LO-7L&?MdP$ӄ &44H A2;TFdRqь2&,"lz[~ozz'9ZKȐL>G #S2y8W0 l-&&#]tTVcXiV{[|u*avbX1 VnQj'T(c4@pָۘӳ `$GS8҇>;\4[ vˎ0<h5zpKeG jiw;{`:hja$U.I e4&Y\>! 8~7[6Oi- BЬ$!9PPd.1XduC킑7bYش ӗX +7ñ+VQ29ʭ6nb=b-]@22~pV!ţhSٰ"OI2r6b86n7Y C2M( iBiLJdP$ӄ &44F #ER^51 3 |i_ ȱ!#gGIL> H A2M( iBi-ӣޞv c˴s#Х=ZLBi`ik-$8+"՞ 4\H @\EB2M( iBiLJdP$ӄXf;@נo"u!m]Dס>Int݉',0m%ElV ޵Yя$ b64&Nocq:"+S@UGX']tRT48jD_n ؉zEϗ5A2hv![6,X^6.Ɓ>}(4aS`1*-KdC_oǙ3Ba:k`;wr0CicYJ{ѼF`H͗ܢ Q:߇HsV3%X-<ӛd'~ET[ -H/`:IYȓf琫פ*Qсp4G=7tFC.v0\e-jfߤR ,)Cys^h/+@9L k,K%Gv K<-J&c*bB*Lr0sD=[Pwqh)LrXr|4Cy=JRlN)~FXm9`4v_/ LJr, fx?L fQk+r[- aɖ0Ium)ÿ>.ea 'uErsϩAf`ED+Ȣ Fs)س4%HJG|8#[,w0X-+Ik#=D>$0e']N3“alsJt[B1 y nþY*e!aNB|z;<+QGbAnƩ$NR@VCl.ԗ?U.:~ 44H A2M( iBiLJdPjeL[!hυl AnυLxjaOZў m`!ht/CxiOAY|ɴ ,dP$ӄ &44H=H+軇G! Fp> ,Qqf`QD9m=\%F'IC CMM( zG$44H A2M( iBiL^:6ѺE;GΪ?.,Zr@*C]6ZqNͷTMc|Rͬ(((`>]_Sh3]j3Gr O/R4JǩaB2 (_$vWߎ훞ⅼv3i5m*pܑ쪖qCPl]aRD`8&>pE8kJ.j l=xn]'պ\}UB":fH@]YQ97%0͸Xx滘|euo&h1i+vh,ݴ}-m ..҈}DCV =ggVGP fMRR)u\IO*ITUw:X ŽE`]R8sMY]K>%%׍dp4u)DiBiLJdP$ӄ &""@(*`پׅBׅc Cx3D4B@F]tǍq \] z_#v}] —&kHMA5 RA~jz<@\)(,mږrJߚ_|F}w<0m[T[w\"e ,_BBZd=sT6]!¤\s6I:=h9]Iw6OtOޣ6 ګMMǤd.ŞMYb,ʕF%?of~ 2Dv&+KL0[$ڡ57Lܮ32<P?XlZ &Fxڛ¤<#{:-Mn|r\*lPOeA-*8U6j #,:e Ȩߦ#R۸3~ZfkZ/r{MQ#3>VGg/ 1ݡ}ue sxnilQzœY`J6ik^8Ub9bǦeK7m[EQm /*bSU@ePѓ/T/VfYJS;,q;kboۡRFZʡQcsv@A1gzv٤Xl \qf6,7|1,zNn\ޗ.ݿ=G)]sYse,PbZL,{FnB&.ɓ :5MX&kHMA5 RA~t XM},]@.G9Ty?b`ɽׅ?c.ti}vLXMWuhF}EPt !D˛E,TE_h@(i(? 5"Դ #FIuQ*tMA5 RA~ i 4p:Bh73o`琚&g9N{'48kD@j:ر , z@j:xa`t`q B$MD@j &kHMA5 RA~ i|p?Ğ"N86{\%c᚜9=?A|'wCjp7SQ:>>}MU4ٌ1S kj 419}:L@[Ah`jǻzh m8bg3+k9jƾh @ G6?ţ;ڋR9VKa#o޸(kUmQ= tt`of;INM/A+bC.AG:R-8J31iHM#뇨sZ,~';9 }LذaP uz]_#!5_4ی*YF e܇a旨e)Iecjvb4^S(XY7Ub7X<8f! b&&~%J>FG B#gwpoFV/=<5cs* \@Ҥ IcAj6u QX+ 8l$7ߙa:)WjP bx,~\lԠ˼`O–"4'I#&YpMFyE8kyVJ3wBĤ!5MMDbݾU]ɍ酚/)5"i"/$A iwD%0ׅ 4A_Cj ¯!5Mא&kHMmf>P A`4u@: 57?SC.&HM5Jꩩ̪u&A@p7Ƣ-zY+HMvvDBjH^ܓ4&kHMA5 RA~ i Դ&o9$`79w`kD іG׈\HM: Wr@ڙPA 0Ľ¯P21}a0< 1^`{:KExj#S0=ebĉb4mI({5ݘ !$^}ŪihBUS,DMh5M3ug?Ci _Ư!%c]< K(^r{fk~62Ua Ts-Dq!({0&$IN=p7fjac2%r6,J͔=Z͕O2esR~Cg35dY?^CO?#p]և0D8m/XbhkPr y& 4NŃڅQ= ttD4t 5X?Bv :|[(L~NX!p׹CE3VEI];R-8JZe$c/`Zznsujbl,{y) zWG_|nkp?{'7=V|QGg~xfiG27<U캡zCr<o+O>RQWݴF{%!?HԆ/<#K}Uے4YsyV<߼ۑBcKBI|:)W_nGLvzvd߁vC}'BŃUև| e܇!֧E.@E,Cm>ӝjsv ri^'~8f_*T3wq9,裫ĴwQr :!t6{/sPg=Hm!5@Ym*߾akކܸkzL^ޝ9^c 0kNł[Zq}s}2F11~9L'kJ\|S,~֖[^|d>BBjoHСfPVGb=݌#1B/;u6c#6_8r+Q1:zpO8" _mh5c|*bx;Mq, ögX;J!x4?J+)mXeۇw1[_I~=y<#g)7Թ"{5ge>zøn.ۅP##!SO36Iu QX/}ll❭%I3ѠE> "tJD 氳3_f'1Vcx׳v˕|B%GJ:N,eY^b^V! 7L}N\a%42 ӧϏ !e Y^n0,#l `!l^+ 7nL:uʌ,Y0h< &+/!5퇨@,+ u?VGc#s_`ljw#D+M3]0pZz5(~\/W!LG7 -PNH$S_k0<KiYYZlYʢ?x{-9v楽7,"U3l ˎeyS?'긲Vôܶio.:W ϰ?z˟܎7y')U_tԬ 5,"?}DV X#F nyc@4 ~)ψEw4WRG)dѭ7"|@1qk75LE3­10?,|o-s֬ػnj!piCwu9!a RACH('- wr6t.6i CiL-0h1qzEܛ1_ێ6,&؁z)]e -Z>M#Dt?$5=GV̫<݋{nKK,x/Zo&MavܷnOngLhEޝ~˰WW ؿ!i֔$防_Aj:hf%Gl2"^t+1:Ohut NqT:NS0Pw %²j f&̧D=kd{ƼGIO OYn48${:W&kHMA5 ¿q-:p DsUӢdK&k "@ZԁM֊iӲBnQccMi\N@QY" 2%R^iO\5Eʡc- 7b,$)7&QHZ!iblS,gԵ!P&NНV 1cB%p!5Mא&kHMA5 RA~ ibl&69@:R0B( ibl\ ܅ X'qਯ]_t@"0(4~Ľ{>CwiIA&"P_`MD"S֊UӤ PUAʀ4A_Cj ¯!5Mא&kHM'񣷰n߆XmS4b.A3'__̄w!5M}mQ!-7jzߏ={6SQ:rn8%y,pi@4VLlÖTz %/'y{҃cpv ^)fdW`r>}z:I6#b-0С}0#Ac[f$oǡSAU% Pӊ!dwqRF8Bck$>$DcĶ:l^ UK%9'Hm:˧,̛ܞ!h܉w8jC;I65ʣCi­T2P,xP&y*1]Cc)ϜL~^Vc!p%3Gd04PP-N )Ǖ;3tB),CXa+/^G~Ŏ{c<&wVBɋiaś&s;(h) @%kN.B+\dSIxRӄ[IPSp ypq9z]oo+mc3;{CɺOQ5|El}/ux3=ؑpŎ@B[KȐ ^BI:^\EKe^Պɒ^E+ע4\$6Q`o/{31y*qsm/ctx\p8fiieO6^/Q;sca:43LM&VTy0@t2hmkN$Є4<{O`ּ]]Jx+÷%G<IJVͿ`LSԈ31]cS|,Y!TEv:d6F11MDhi""EcL)cHDDiw{h4DrY\/sLCJjkh h/yLxtwjZ sW")\ ((2DaMgYbS$0šЅ h411MDhi""Eg1=5nRf)fD QMJpbzo#;` xj<1wp3iEÐә"lFLF޽ Gj Z8)< ,>"%;P58C s՟8-!37htVV6J=/GVގn^FK^6Kxo m"DT=3:Ĵr3Z1D]OS LZ[Zjl~3v,6^6`6U2У g'ht@uW+Ӣc#lƶW%tmpO_BœtRѶWs [#ixп#}x:9 }'X]6K{/mŨoČsב'M tI&޾ϻp:1b @F7Pقk(J/[ks;B><5pׁn:掁!E˜^BB*18߫hj!*7rf!Z\&ޮwGB-ҟUv]䕉ݘ0$.p ,m

y OFc?B?uf+[dCT 5/C]vY%ah b43 ܾ-Z*RgAY৫Q2da҉#b "WB&|k7ֆʆ,8珉g+]NxwxUvTQM0:.c{7czimkW:I@C5x8YeESD'Ɋ6x pb{3 Ri޽oMȪ=<8lG:3h-d F+Rm*TJZ(rAFx7HccifN"lrA?BWyzwEMFEudygJNMfȅ  63b?Cb18dԶ?bIrcczΙP!>f*5gfRb> Sڪ͊jl}y O`up%cT!U8&$I<цLK_Y]kRD0iq Rˊ0}11MDhi""EcL)cHTl)8'5&"RjfqfaMDό禽 hZ;xckDpr/! `.t#JƘin: V.4HWvM+cHDDƘ&"R441i?ڒ%ҊØ'mvw[t1M+zo&R>#J"̴̝XL4gDDJ0ѡ*LDU|7Tl""}ܣ/!)cHDDƘ&"R441ajızPPc!'%v1y&wתn3}4/,cbKW=)ޒ#nR7<7m'z?=awwi11|m/mY#3Ijkp5)[Ʊu`=cf\pP}rGØ^v7nX]g+=7U+kYqA{{fesK׶תoq϶Ԏl'6g֟),;֜3cP(d11P3n骕X2=cSͨ t싉Bͧf ~bΗgbnfs0*Z[y\^d[-czM]xΦtghUJеɨlkq [t@MۑcŊ#}N7'su'kyabaɚk'_*>}](3ћ\78k/18w6/¡~90t!N[<v<'b2JtRollfݔ7~hmn}Mo(~--6}`{`+bIj*!vݮR'u=$Q1^LZ]wmh[Fm܁]?931ʟ:0!Pabc4ɞMr4tLk_q[Uݟ\<00ir Lpoܙ}wQhL-p,8oq-$B .Tn>Z_!,U 2Zvy7rB\a֡ϧmLt?#$r'Cfq)~s8_cltՌuxEKgˎb7 IOT?VE+bgbQJyeSWǽI.+(9< %-ptDoh-W~>Ag.riʪ>rŝ>[1u::k {{D"YK2Zd;0km6{N|oʻ+N~=}k<Ѫ%+Sw\|odSOF[wiUR8_:#m=7._ {X[e]BTAMۏ￐[/Y5h$< A%mq-mn ;+bRcPV7ιp(89&o`ܩsB=-/ƴxTskU yQdujqYJQo7zÙO9Ⱦ*+CzI)2jl6Ƭkhs7eέg.* SOCI - multithreading

Multithreading

The general rule for multithreading is that SOCI classes are not thread-safe, meaning that their instances should not be used concurrently by multiple threads.

The simplest solution for multithreaded code is to set up a separate session object for each thread that needs to inteact with the database. Depending on the design of the client application this might be also the most straightforward approach.

For some applications, however, it might be preferable to decouple the set of threads from the set of sessions, so that they can be optimized separately with different resources in mind. The connection_pool class is provided for this purpose:

// phase 1: preparation

const size_t poolSize = 10;
connection_pool pool(poolSize);

for (size_t i = 0; i != poolSize; ++i)
{
    session & sql = pool.at(i);

    sql.open("postgresql://dbname=mydb");
}

// phase 2: usage from working threads

{
    session sql(pool);

    sql << "select something from somewhere...";

} // session is returned to the pool automatically

The connection_pool's constructor expects the size of the pool and internally creates an array of sessions in the disconnected state. Later, the at function provides non-synchronized access to each element of the array. Note that this function is not thread-safe and exists only to make it easier to set up the pool in the initialization phase.

Note that it is not obligatory to use the same connection parameters for all sessions in the pool, although this will be most likely the usual case.

The working threads that need to lease a single session from the pool use the dedicated constructor of the session class - this constructor blocks until some session object becomes available in the pool and attaches to it, so that all further uses will be forwarded to the session object managed by the pool. As long as the local session object exists, the associated session in the pool is locked and no other thread will gain access to it. When the local session variable goes out of scope, the related entry in the pool's internal array is released, so that it can be used by other threads. This way, the connection pool guarantees that its session objects are never used by more than one thread at a time.

Note that the above scheme is the simplest way to use the connection pool, but it is also constraining in the fact that the session's constructor can block waiting for the availability of some entry in the pool. For more demanding users there are also low-level functions that allow to lease sessions from the pool with timeout on wait. Please consult the reference for details.

soci-3.2.3/doc/queries.html0000644000000000000000000001134612511362240014263 0ustar rootroot SOCI - queries

Queries

Simple SQL statements

In many cases, the SQL query is intended to be executed only once, which means that statement parsing and execution can go together. The session class provides a special once member, which triggers parsing and execution of such one-time statements:

sql.once << "drop table persons";

For shorter syntax, the following form is also allowed:

sql << "drop table persons";

The IOStream-like interface is exactly what it looks like, so that the statement text can be composed of many parts, involving anything that is streamable (including custom classes, if they have appropriate operator<<):

string tableName = "persons";
sql << "drop table " << tableName;

int id = 123;
sql << "delete from companies where id = " << id;

Query transformation

In SOCI 3.2.0, query transformation mechanism was introduced.

Query transformation is specified as user-defined unary function or callable function object with input parameter of type std::string which returns object of type std::string as well.

The query transformation function is registered for current database session using dedicated session::set_query_transformation method. Then, the transformation function is called with query string as argument just before the query is sent to database backend for execution or for preparation.

For one-time statements, query transformation is performed before each execution of statement. For prepared statements, query is transformed only once, before preparation, regardless how many times it is executed.

A few short examples how to use query transformation:

  • defined as free function:
std::string less_than_ten(std::string query)
{
    return query + " WHERE price < 10";
}

session sql(postgresql, "dbname=mydb");
sql.set_query_transformation(less_than_ten);
sql << "DELETE FROM item";
  • defined as function object:
struct order : std::unary_function<std::string, std::string>
{
    order(std::string const& by) : by_(by) {}

    result_type operator()(argument_type query) const
    {
        return query + " ORDER BY " + by_;
    }

    std::string by_;
};

char const* query = "SELECT * FROM product";
sql.set_query_transformation(order("price");
sql << query;
sql.set_query_transformation(order("id");
sql << query;
  • defined as lambda function (since C++11):
std::string dep = "sales";
sql.set_query_transformation(
    [&dep](std::string const& query) {
        return query + " WHERE department = '" + dep + "'";
});
sql << "SELECT * FROM employee";

Query transformations enable users with simple mechanism to apply extra requirements to or interact with SQL statement being executed and that is without changing the SQL statement itself which may be passed from different parts of application.

For example, the query transformation may be used to:

  • modify or add clauses of SQL statements (i.e. WHERE clause with new condition)
  • prefix table names with new schema to allow namespaces switch
  • validate SQL statements
  • perform sanitization checking for any unverified input
  • apply database-specific features like add optimization hints to SQL statements (i.e. SELECT /*+RULE*/ A FROM C in Oracle 9)

Query transformation mechanism can also be considered for similar uses as prefix_with function from SQLAlchemy Expressions API.

soci-3.2.3/doc/index.html0000644000000000000000000000620312511362240013711 0ustar rootroot SOCI

Documentation and tutorial

The following (complete!) example is purposedly provided without any explanation.

#include "soci.h"
#include "soci-oracle.h"
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <exception>

using namespace soci;
using namespace std;

bool get_name(string &name)
{
    cout << "Enter name: ";
    return cin >> name;
}

int main()
{
    try
    {
        session sql(oracle, "service=mydb user=john password=secret");

        int count;
        sql << "select count(*) from phonebook", into(count);

        cout << "We have " << count << " entries in the phonebook.\n";

        string name;
        while (get_name(name))
        {
            string phone;
            indicator ind;
            sql << "select phone from phonebook where name = :name",
                into(phone, ind), use(name);

            if (ind == i_ok)
            {
                cout << "The phone number is " << phone << '\n';
            }
            else
            {
                cout << "There is no phone for " << name << '\n';
            }
        }
    }
    catch (exception const &e)
    {
        cerr << "Error: " << e.what() << '\n';
    }
}
soci-3.2.3/doc/style.css0000644000000000000000000000267312511362240013575 0ustar rootrootbody { background-color: white; color: black; margin-left: 100px; margin-right: 100px; font-family: arial, sans-serif; font-size: small; } p.banner { font-size: x-large; font-weight: bold; font-stretch: expanded; border-bottom-color: black; border-bottom-style: solid; border-bottom-width: 1px; padding-bottom: 5px; } div.navigation { } div.navigation-indented { margin-left: 40px; } div.diagram { text-align: center; } div.note { border-color: black; border-style: dotted; border-width: 1px; margin-top: 20px; padding-left: 20px; padding-right: 20px; } span.note { font-size: large; font-weight: bold; } code { /* font-weight: bold; */ background-color: white; color: #8B0000; /* font-size: large; */ } pre.example { background-color: #F0F0F0; color: black; border-width: 1px; border-style: dashed; border-color: blue; padding: 10px 10px 10px 10px; } table.foot-links { width: 100%; padding-top: 20px; } td.foot-link-left { text-align: left; } td.foot-link-right { text-align: right; } table.cmake-variables { width: 100%; /*border: solid;*/ } caption.cmake-variables { background-color: #E0E0E0; font-style: italic; font-weight: bold; } td.variable-name { width: 25%; } td.variable-type { width: 7%; } tr.header { /* background-color: #F0F0F0; */ } p.copyright { border-top-color: black; border-top-style: solid; border-top-width: 1px; padding-top: 5px; } soci-3.2.3/doc/errors.html0000644000000000000000000000672712511362240014131 0ustar rootroot SOCI - errors

Errors

All DB-related errors manifest themselves as exceptions of type soci_error, which is derived from std::runtime_error.
This allows to handle database errors within the standard exception framework:

int main()
{
    try
    {
        // regular code
    }
    catch (std::exception const & e)
    {
        cerr << "Bang! " << e.what() << endl;
    }
}

Portability note:

The Oracle backend can also throw the instances of the oracle_soci_error, which is publicly derived from soci_error and has an additional public err_num_ member containing the Oracle error code:

int main()
{
    try
    {
        // regular code
    }
    catch (soci::oracle_soci_error const & e)
    {
        cerr << "Oracle error: " << e.err_num_
            << " " << e.what() << endl;
    }
    catch (soci::exception const & e)
    {
        cerr << "Some other error: " << e.what() << endl;
    }
}

Portability note:

The MySQL backend can throw instances of the mysql_soci_error, which is publicly derived from soci_error and has an additional public err_num_ member containing the MySQL error code (as returned by mysql_errno()):

int main()
{
    try
    {
        // regular code
    }
    catch (soci::mysql_soci_error const & e)
    {
        cerr << "MySQL error: " << e.err_num_
            << " " << e.what() << endl;
    }
    catch (soci::exception const & e)
    {
        cerr << "Some other error: " << e.what() << endl;
    }
}

Portability note:

The PostgreSQL backend can also throw the instances of the postgresql_soci_error, which is publicly derived from soci_error and has an additional public sqlstate() member function returning the five-character "SQLSTATE" error code:

int main()
{
    try
    {
        // regular code
    }
    catch (soci::postgresql_soci_error const & e)
    {
        cerr << "PostgreSQL error: " << e.sqlstate()
            << " " << e.what() << endl;
    }
    catch (soci::exception const & e)
    {
        cerr << "Some other error: " << e.what() << endl;
    }
}
soci-3.2.3/doc/statements.html0000644000000000000000000003601312511401144014770 0ustar rootroot SOCI - statements, procedures and transactions

Statements, procedures and transactions

Statement preparation and repeated execution

Consider the following examples:

// Example 1.
for (int i = 0; i != 100; ++i)
{
    sql << "insert into numbers(value) values(" << i << ")";
}

// Example 2.
for (int i = 0; i != 100; ++i)
{
    sql << "insert into numbers(value) values(:val)", use(i);
}

Both examples will populate the table numbers with the values from 0 to 99.

The problem is that in both examples, not only the statement execution is repeated 100 times, but also the statement parsing and preparation. This means unnecessary overhead, even if some of the database servers are likely to optimize the second case. In fact, more complicated queries are likely to suffer in terms of lower performance, because finding the optimal execution plan is quite expensive and here it would be needlessly repeated.

The following example uses the class statement explicitly, by preparing the statement only once and repeating its execution with changing data (note the use of prepare member of session class):

int i;
statement st = (sql.prepare <<
                "insert into numbers(value) values(:val)",
                use(i));
for (i = 0; i != 100; ++i)
{
    st.execute(true);
}

The true parameter given to the execute method indicates that the actual data exchange is wanted, so that the meaning of the whole example is "prepare the statement and exchange the data for each value of variable i".

Portability note:

The above syntax is supported for all backends, even if some database server does not actually provide this functionality - in which case the library will internally execute the query in a single phase, without really separating the statement preparation from execution.

For PostgreSQL servers older than 8.0 it is necessary to define the SOCI_POSTGRESQL_NOPREPARE macro while compiling the library to fall back to this one-phase behaviour. Simply, pass -DSOCI_POSTGRESQL_NOPREPARE=ON variable to CMake.

Rowset and iterator-based access

The rowset class provides an alternative means of executing queries and accessing results using STL-like iterator interface.

The rowset_iterator type is compatible with requirements defined for input iterator category and is available via iterator and const_iterator definitions in the rowset class.

The rowset itself can be used only with select queries.

The following example creates an instance of the rowset class and binds query results into elements of int type - in this query only one result column is expected. After executing the query the code iterates through the query result using rowset_iterator:

rowset<int> rs = (sql.prepare << "select values from numbers");

for (rowset<int>::const_iterator it = rs.begin(); it != rs.end(); ++it)
{
     cout << *it << '\n';
}

Another example shows how to retrieve more complex results, where rowset elements are of type row and therefore use dynamic bindings:

// person table has 4 columns

rowset<row> rs = (sql.prepare << "select id, firstname, lastname, gender from person");

// iteration through the resultset:
for (rowset<row>::const_iterator it = rs.begin(); it != rs.end(); ++it)
{
    row const& row = *it;

    // dynamic data extraction from each row:
    cout << "Id: " << row.get<int>(0) << '\n'
         << "Name: " << row.get<string>(1) << " " << row.get<string>(2) << '\n'
         << "Gender: " << row.get<string>(3) << endl;
}

rowset_iterator can be used with standard algorithms as well:

rowset<string> rs = (sql.prepare << "select firstname from person");

std::copy(rs.begin(), rs.end(), std::ostream_iterator<std::string>(std::cout, "\n"));

Above, the query result contains a single column which is bound to rowset element of type of std::string. All records are sent to standard output using the std::copy algorithm.

Bulk operations

When using some databases, further performance improvements may be possible by having the underlying database API group operations together to reduce network roundtrips. SOCI makes such bulk operations possible by supporting std::vector based types.

The following example presents how to insert 100 records in 4 batches. It is also important to note, that size of vector remains equal in every batch interaction. This ensures vector is not reallocated and, what's crucial for the bulk trick, new data should be pushed to the vector before every call to statement::execute:

// Example 3.
void fill_ids(std::vector& ids)
{
   for (std::size_t i = 0; i < ids.size(); ++i)
      ids[i] = i; // mimics source of a new ID
}

const int BATCH_SIZE = 25;
std::vector ids(BATCH_SIZE);

statement st = (sql.prepare <<
                "insert into numbers(value) values(:val)",
                use(ids));
for (int i = 0; i != 4; ++i)
{
    fill_ids(ids);
    st.execute(true);
}

Given batch size is 25, this example should insert 4 x 25 = 100 records.

(Of course, the size of the vector that will achieve optimum performance will vary, depending on many environmental factors, such as network speed.)

It is also possible to read all the numbers written in the above examples:

int i;
statement st = (sql.prepare <<
                "select value from numbers order by value",
                into(i));
st.execute();
while (st.fetch())
{
    cout << i << '\n';
}

In the above example, the execute method is called with the default parameter false. This means that the statement should be executed, but the actual data exchange will be performed later.

Further fetch calls perform the actual data retrieval and cursor traversal. The end-of-cursor condition is indicated by the fetch function returning false.

The above code example should be treated as an idiomatic way of reading many rows of data, one at a time.

It is further possible to select records in batches into std::vector based types, with the size of the vector specifying the number of records to retrieve in each round trip:

std::vector<int> valsOut(100);
sql << "select val from numbers", into(valsOut);

Above, the value 100 indicates that no more values should be retrieved, even if it would be otherwise possible. If there are less rows than asked for, the vector will be appropriately down-sized.

The statement::execute() and statement::fetch() functions can also be used to repeatedly select all rows returned by a query into a vector based type:

const int BATCH_SIZE = 30;
std::vector<int> valsOut(BATCH_SIZE);
statement st = (sql.prepare <<
                "select value from numbers",
                into(valsOut));
st.execute();
while (st.fetch())
{
    std::vector<int>::iterator pos;
    for(pos = valsOut.begin(); pos != valsOut.end(); ++pos)
    {
        cout << *pos << '\n';
    }

    valsOut.resize(BATCH_SIZE);
}

Assuming there are 100 rows returned by the query, the above code will retrieve and print all of them. Since the output vector was created with size 30, it will take (at least) 4 calls to fetch() to retrieve all 100 values. Each call to fetch() can potentially resize the vector to a size less than its initial size - how often this happens depends on the underlying database implementation. This explains why the resize(BATCH_SIZE) operation is needed - it is there to ensure that each time the fetch() is called, the vector is ready to accept the next bunch of values. Without this operation, the vector might be getting smaller with subsequent iterations of the loop, forcing more iterations to be performed (because all rows will be read anyway), than really needed.

Note the following details about the above examples:

  • After performing fetch(), the vector's size might be less than requested, but fetch() returning true means that there was at least one row retrieved.
  • It is forbidden to manually resize the vector to the size higher than it was initially (this can cause the vector to reallocate its internal buffer and the library can lose track of it).

Taking these points under consideration, the above code example should be treated as an idiomatic way of reading many rows by bunches of requested size.

Portability note:

Actually, all supported backends guarantee that the requested number of rows will be read with each fetch and that the vector will never be down-sized, unless for the last fetch, when the end of rowset condition is met. This means that the manual vector resizing is in practice not needed - the vector will keep its size until the end of rowset. The above idiom, however, is provided with future backends in mind, where the constant size of the vector might be too expensive to guarantee and where allowing fetch to down-size the vector even before reaching the end of rowset might buy some performance gains.

Stored procedures

The procedure class provides a convenient mechanism for calling stored procedures:

sql << "create or replace procedure echo(output out varchar2,"
       "input in varchar2) as "
       "begin output := input; end;";

std::string in("my message");
std::string out;
procedure proc = (sql.prepare << "echo(:output, :input)",
                                 use(out, "output"),
                                 use(in, "input"));
proc.execute(true);
assert(out == "my message");

Portability note:

The above way of calling stored procedures is provided for portability of the code that might need it. It is of course still possible to call procedures or functions using the syntax supported by the given database server.

Transactions

The SOCI library provides the following members of the session class for transaction management:

  • void begin();
  • void commit();
  • void rollback();

In addition to the above there is a RAII wrapper that allows to associate the transaction with the given scope of code:

class transaction
{
public:
    explicit transaction(session & sql);

    ~transaction();

    void commit();
    void rollback();

private:
    // ...
};

The object of class transaction will roll back automatically when the object is destroyed (usually as a result of leaving the scope) and when the transaction was not explicitly committed before that.

A typical usage pattern for this class might be:

{
    transaction tr(sql);

    sql << "insert into ...";
    sql << "more sql queries ...";
    // ...

    tr.commit();
}

With the above pattern the transaction is committed only when the code successfully reaches the end of block. If some exception is thrown before that, the scope will be left without reaching the final statement and the transaction object will automatically roll back in its destructor.

Portability note:

Different database servers have different policies with regard to the implicit transaction management. Some of them start the implicit transaction with the first DML statement and keep it open until explicitly commited or rolled back (or closing the whole session). Others will treat each statement as if it was a separate, auto-commited transaction. For better compatibility, it is recommended to use the above functions for explicit transaction management.

Basic logging support

The following members of the session class support the basic logging functionality:

  • void set_log_stream(std::ostream * s);
  • std::ostream * get_log_stream() const;
  • std::string get_last_query() const;

The first two functions allow to set the user-provided output stream object for logging. The NULL value, which is the default, means that there is no logging. An example use might be:

session sql(oracle, "...");

ofstream file("my_log.txt");
sql.set_log_stream(&file);

// ...

Each statement logs its query string before the preparation step (whether explicit or implicit) and therefore logging is effective whether the query succeeds or not. Note that each prepared query is logged only once, independent on how many times it is executed.

The get_last_query function allows to retrieve the last used query.

soci-3.2.3/doc/structure.html0000644000000000000000000000572712511362240014654 0ustar rootroot SOCI - structure

Structure

Library structure diagram

The picture above presents the structure of the library, together with its clients and servers. The boxes filled with cyan represent components that are part of the library distribution.

The SOCI library is extensible in the following ways:

  • More backends can be added to target various database servers.
  • More interfaces can be defined on top of common backend interface.
  • Other languages can use the simple interface, which was designed specifically for the "C" calling convention to ensure easy binding.

The core part of the library and the backend interface definition are placed in the core directory of the library distribution. The soci-backend.h file is an internal abstract interface to the actual backends, which are needed to perform operations on the given database server. Normally, the C++ client program needs to interface with the soci.h header and the header(s) relevant to the given backend(s) (for example, soci-oracle.h), although with dynamic backend loading this can be avoided. It is possible for the same program to use many backends at the same time.

Everything in SOCI is declared in the namespace soci. All code examples presented in this documentation assume that your code begins with something like:

#include "soci.h"
// other includes if necessary

using namespace soci;

// ...

Note: In simple programs, #include for the relevant backend is needed only in the file where the session object is created with explicit name of the backend factory. The example program on the previous page shows the appropriate #include directive for the Oracle backend. It is also possible to name backends at run-time as part of the connection string, in which case no backend-specific #include directive is necessary.

soci-3.2.3/doc/backends.html0000644000000000000000000004573612511362240014372 0ustar rootroot SOCI - backends

Backends reference

This part of the documentation is provided for those who want to write (and contribute!) their own backends. It is anyway recommended that authors of new backend see the code of some existing backend for hints on how things are really done.

The backend interface is a set of base classes that the actual backends are supposed to specialize. The main SOCI interface uses only the interface and respecting the protocol (for example, the order of function calls) described here. Note that both the interface and the protocol were initially designed with the Oracle database in mind, which means that whereas it is quite natural with respect to the way Oracle API (OCI) works, it might impose some implementation burden on other backends, where things are done differently and therefore have to be adjusted, cached, converted, etc.

The interface to the common SOCI interface is defined in the core/soci-backend.h header file. This file is dissected below.

All names are defined in either soci or soci::details namespace.

// data types, as seen by the user
enum data_type
{
    dt_string, dt_date, dt_double, dt_integer, dt_long_long, dt_unsigned_long_long
};

// the enum type for indicator variables
enum indicator { i_ok, i_null, i_truncated };

// data types, as used to describe exchange format
enum exchange_type
{
    x_char,
    x_stdstring,
    x_short,
    x_integer,
    x_long_long,
    x_unsigned_long_long,
    x_double,
    x_stdtm,
    x_statement,
    x_rowid,
    x_blob
};

struct cstring_descriptor
{
    cstring_descriptor(char * str, std::size_t bufSize)
        : str_(str), bufSize_(bufSize) {}

    char * str_;
    std::size_t bufSize_;
};

// actually in error.h:
class soci_error : public std::runtime_error
{
public:
    soci_error(std::string const & msg);
};

The data_type enumeration type defines all types that form the core type support for SOCI. The enum itself can be used by clients when dealing with dynamic rowset description.

The indicator enumeration type defines all recognized states of data. The i_truncated state is provided for the case where the string is retrieved from the database into the char buffer that is not long enough to hold the whole value.

The exchange_type enumeration type defines all possible types that can be used with the into and use elements.

The cstring_descriptor is a helper class that allows to store the address of char buffer together with its size. The objects of this class are passed to the backend when the x_cstring type is involved.

The soci_error class is an exception type used for database-related (and also usage-related) errors. The backends should throw exceptions of this or derived type only.

class standard_into_type_backend
{
public:
    standard_into_type_backend() {}
    virtual ~standard_into_type_backend() {}

    virtual void define_by_pos(int& position, void* data, exchange_type type) = 0;

    virtual void pre_fetch() = 0;
    virtual void post_fetch(bool gotData, bool calledFromFetch, indicator* ind) = 0;

    virtual void clean_up() = 0;
};

The standard_into_type_back_end class implements the dynamic interactions with the simple (non-bulk) into elements. The objects of this class (or, rather, of the derived class implemented by the actual backend) are created by the statement object when the into element is bound - in terms of lifetime management, statement is the master of this class.

  • define_by_pos - Called when the into element is bound, once and before the statement is executed. The data pointer points to the variable used for into element (or to the cstring_descriptor object, which is artificially created when the plain char buffer is used for data exchange). The position parameter is a "column number", assigned by the library. The backend should increase this parameter, according to the number of fields actually taken (usually 1).
  • pre_fetch - Called before each row is fetched.
  • post_fetch - Called after each row is fetched. The gotData parameter is true if the fetch operation really retrieved some data and false otherwise; calledFromFetch is true when the call is from the fetch operation and false if it is from the execute operation (this is also the case for simple, one-time queries). In particular, (calledFromFetch && !gotData) indicates that there is an end-of-rowset condition. ind points to the indicator provided by the user, or is NULL, if there is no indicator.
  • clean_up - Called once when the statement is destroyed.

The intended use of pre_fetch and post_fetch functions is to manage any internal buffer and/or data conversion for each value retrieved from the database. If the given server supports binary data transmission and the data format for the given type agrees with what is used on the client machine, then these two functions need not do anything; otherwise buffer management and data conversions should go there.

class vector_into_type_backend
{
public:
    vector_into_type_backend() {}
    virtual ~vector_into_type_backend() {}

    virtual void define_by_pos(int& position, void* data, exchange_type type) = 0;

    virtual void pre_fetch() = 0;
    virtual void post_fetch(bool gotData, indicator* ind) = 0;

    virtual void resize(std::size_t sz) = 0;
    virtual std::size_t size() = 0;

    virtual void clean_up() = 0;
};

The vector_into_type_back_end has similar structure and purpose as the previous one, but is used for vectors (bulk data retrieval).

The data pointer points to the variable of type std::vector<T> (and not to its internal buffer), resize is supposed to really resize the user-provided vector and size is supposed to return the current size of this vector. The important difference with regard to the previous class is that ind points (if not NULL) to the beginning of the array of indicators. The backend should fill this array according to the actual state of the retrieved data.

class standard_use_type_backend
{
public:
    virtual ~standard_use_type_backend() {}

    virtual void bind_by_pos(int& position,
        void* data, exchange_type type, bool readOnly) = 0;
    virtual void bind_by_name(std::string const& name,
        void* data, exchange_type type, bool readOnly) = 0;

    virtual void pre_use(indicator const* ind) = 0;
    virtual void post_use(bool gotData, indicator* ind) = 0;

    virtual void clean_up() = 0;
};

The standard_use_type_backend implements the interactions with the simple (non-bulk) use elements, created and destroyed by the statement object.

  • bind_by_pos - Called for each use element, once and before the statement is executed - for those use elements that do not provide explicit names for parameter binding. The meaning of parameters is same as in previous classes.
  • bind_by_name - Called for those use elements that provide the explicit name.
  • pre_use - Called before the data is transmitted to the server (this means before the statement is executed, which can happen many times for the prepared statement). ind points to the indicator provided by the user (or is NULL).
  • post_use - Called after statement execution. gotData and ind have the same meaning as in standard_into_type_back_end::post_fetch, and this can be used by those backends whose respective servers support two-way data exchange (like in/out parameters in stored procedures).

The intended use for pre_use and post_use methods is to manage any internal buffers and/or data conversion. They can be called many times with the same statement.

class vector_use_type_backend
{
public:
    virtual ~vector_use_type_backend() {}

    virtual void bind_by_pos(int& position,
        void* data, exchange_type type) = 0;
    virtual void bind_by_name(std::string const& name,
        void* data, exchange_type type) = 0;

    virtual void pre_use(indicator const* ind) = 0;

    virtual std::size_t size() = 0;

    virtual void clean_up() = 0;
};

Objects of this type (or rather of type derived from this one) are used to implement interactions with user-provided vector (bulk) use elements and are managed by the statement object. The data pointer points to the whole vector object provided by the user (and not to its internal buffer); ind points to the beginning of the array of indicators (or is NULL). The meaning of this interface is analogous to those presented above.

class statement_backend
{
public:
    statement_backend() {}
    virtual ~statement_backend() {}

    virtual void alloc() = 0;
    virtual void clean_up() = 0;

    virtual void prepare(std::string const& query, statement_type eType) = 0;

    enum exec_fetch_result
    {
        ef_success,
        ef_no_data
    };

    virtual exec_fetch_result execute(int number) = 0;
    virtual exec_fetch_result fetch(int number) = 0;

    virtual long long get_affected_rows() = 0;
    virtual int get_number_of_rows() = 0;

    virtual std::string rewrite_for_procedure_call(std::string const& query) = 0;

    virtual int prepare_for_describe() = 0;
    virtual void describe_column(int colNum, data_type& dtype,
        std::string& column_name) = 0;

    virtual standard_into_type_backend* make_into_type_backend() = 0;
    virtual standard_use_type_backend* make_use_type_backend() = 0;
    virtual vector_into_type_backend* make_vector_into_type_backend() = 0;
    virtual vector_use_type_backend* make_vector_use_type_backend() = 0;
};

The statement_backend type implements the internals of the statement objects. The objects of this class are created by the session object.

  • alloc - Called once to allocate everything that is needed for the statement to work correctly.
  • clean_up - Supposed to clean up the resources, called once.
  • prepare - Called once with the text of the SQL query. For servers that support explicit query preparation, this is the place to do it.
  • execute - Called to execute the query; if number is zero, the intent is not to exchange data with the user-provided objects (into and use elements); positive values mean the number of rows to exchange (more than 1 is used only for bulk operations).
  • fetch - Called to fetch next bunch of rows; number is positive and determines the requested number of rows (more than 1 is used only for bulk operations).
  • get_affected_rows - Called to determine the actual number of rows affected by data modifying statement.
  • get_number_of_rows - Called to determine the actual number of rows retrieved by the previous call to execute or fetch.
  • rewrite_for_procedure_call - Used when the procedure is used instead of statement, to call the stored procedure. This function should rewrite the SQL query (if necessary) to the form that will allow to execute the given procedure.
  • prepare_for_describe - Called once when the into element is used with the row type, which means that dynamic rowset description should be performed. It is supposed to do whatever is needed to later describe the column properties and should return the number of columns.
  • describe_column - Called once for each column (column numbers - colNum - start from 1), should fill its parameters according to the column properties.
  • make_into_type_backend, make_use_type_backend, make_vector_into_type_backend, make_vector_use_type_backend - Called once for each into or use element, to create the objects of appropriate classes (described above).

Notes:

  1. Whether the query is executed using the simple one-time syntax or is prepared, the alloc, prepare and execute functions are always called, in this order.
  2. All into and use elements are bound (their define_by_pos or bind_by_pos/bind_by_name functions are called) between statement preparation and execution.
class rowid_backend
{
public:
    virtual ~rowid_backend() {}
};

The rowid_backend class is a hook for the backends to provide their own state for the row identifier. It has no functions, since the only portable interaction with the row identifier object is to use it with into and use elements.

class blob_backend
{
public:
    virtual ~blob_backend() {}

    virtual std::size_t get_len() = 0;
    virtual std::size_t read(std::size_t offset, char * buf,
        std::size_t toRead) = 0;
    virtual std::size_t write(std::size_t offset, char const * buf,
        std::size_t toWrite) = 0;
    virtual std::size_t append(char const * buf, std::size_t toWrite) = 0;
    virtual void trim(std::size_t newLen) = 0;
};

The blob_backend interface provides the entry points for the blob methods.

class session_backend
{
public:
    virtual ~session_backend() {}

    virtual void begin() = 0;
    virtual void commit() = 0;
    virtual void rollback() = 0;

    virtual bool get_next_sequence_value(session&, std::string const&, long&);
    virtual bool get_last_insert_id(session&, std::string const&, long&);

    virtual std::string get_backend_name() const = 0;

    virtual statement_backend * make_statement_backend() = 0;
    virtual rowid_backend * make_rowid_backend() = 0;
    virtual blob_backend * make_blob_backend() = 0;
};

The object of the class derived from session_backend implements the internals of the session object.

  • begin, commit, rollback - Forward-called when the same functions of session are called by user.
  • get_next_sequence_value, get_last_insert_id - Called to retrieve sequences or auto-generated values and every backend should define at least one of them to allow the code using auto-generated values to work.
  • make_statement_backend, make_rowid_backend, make_blob_backend - Called to create respective implementations for the statement, rowid and blob classes.
struct backend_factory
{
    virtual ~backend_factory() {}

    virtual details::session_backend * make_session(
        std::string const& connectString) const = 0;
};

The backend_factory is a base class for backend-provided factory class that is able to create valid sessions. The connectString parameter passed to make_session is provided here by the session constructor and contains only the backend-related parameters, without the backend name (if the dynamic backend loading is used).

The actual backend factory object is supposed to be provided by the backend implementation and declared in its header file. In addition to this, the factory_ABC function with the "C" calling convention and returning the pointer to concrete factory object should be provided, where ABC is the backend name.

The following example is taken from soci-postgresql.h, which declares entities of the PostgreSQL backend:

struct postgresql_backend_factory : backend_factory
{
    virtual postgresql_session_backend* make_session(
        std::string const& connectString) const;
};

extern postgresql_backend_factory const postgresql;

extern "C"
{

// for dynamic backend loading
backend_factory const * factory_postgresql();

} // extern "C"

With the above declarations, it is enough to pass the postgresql factory name to the constructor of the session object, which will use this factory to create concrete implementations for any other objects that are needed, with the help of appropriate make_XYZ functions. Alternatively, the factory_postgresql function will be called automatically by the backend loader if the backend name is provided at run-time instead.

Note that the backend source code is placed in the backends/name directory (for example, backends/oracle) and the test driver is in backends/name/test. There is also backends/empty directory provided as a skeleton for development of new backends and their tests. It is recommended that all backends respect naming conventions by just appending their name to the base-class names. The backend name used for the global factory object should clearly identify the given database engine, like oracle, postgresql, mysql, and so on.

soci-3.2.3/CHANGES0000644000000000000000000003456512511401144012153 0ustar rootrootThis file contains the history of changes in the SOCI library. --- Version 3.2.3 differs from 3.2.2 in the following ways: - Improved Boost Tuple & Fusion integration by using boost::fusion::foreach to reference each member of a sequence. Breaks compatibility with Boost 1.35 (2008). - Fixed linker error when building 64-bit target with Visual Studio. - Fixed several issues with building using Cygwin and MinGW. - Clarified documentation and examples on bulk operations. - MySQL -- Fixed building against MySQL 3.23. - ODBC - Improve readability of ODBC error messages. - Fixed CMake configuration of ODBC backend for Visual Studio 64-bit targets. - Oracle -- We've had to disable Oracle target in the Travis CI configuration until we figure out how to setup Oracle on Travis CI directly. Therefore, this release hasn't been extensively tested against Oracle. - PostgreSQL -- Added support for UUID column type (tests and docs updated). - SQLite3 -- Added sqlite3_soci_error exception as subclass of soci_error to provide useful exposure of specific SQLite3 error codes (tests and docs updated). --- Version 3.2.2 differs from 3.2.1 in the following ways: - Fixed once_temp_type destructor with noexcept(false) specifier for C++11 - Fix uninitialized indicators in conversion_into_type and conversion_use_type specialisations - Fixed placeholder matching for PostgreSQL-style casts with ORM - Fixed memory leaking in use binding in case of bind/unbind sequence - Fixed sscanf formatter for MinGW/MSVC in backends - Fixed partial placeholder name matching for ORM cases - Added test for use of indicators with rowset - Added test for get_affected_rows after bulk operations - DB2 -- Enable build and testing on Travis CI -- Fixed use type size calculation during bind/pre_use - Firebird -- Enable memory cleanup to avoid leaks after binding -- Added missing C++ library headers -- Added get_affected_rows() support for bulk operations -- Fixed compilation with VS2008 -- Fixed building tests with the backend built as DLL. - MySQL -- Added get_affected_rows() support for bulk operations - ODBC -- Always call ASCII version of ODBC function SQLGetDiagRec -- Fixed invalid condition test in assertions -- Added get_affected_rows() support for bulk operations -- Added support for (unsigned) long long vectors -- Changed mapping of SQL_BIGINT to dt_long_long in ODBC backend -- Added some trivial optimizations in statement preparation code - Oracle -- Fixed missing noData_ reported in particular case when OCIStmtExecute returns success -- Improved Oracle testing setup on Travis CI - PostgreSQL -- Added session::get_next_sequence_value() for PostgreSQL backend -- Added get_affected_rows() support for bulk operations -- Applied RAII and simplified error handling logic -- Fixed issue with exceptions escaping postgresql_statement_backend destructor - SQLite3 -- Replaced sqlite3_prepare with sqlite3_prepare_v2 -- Added missing header -- Fixed wrong size used in memcpy() during bulk processing -- Added get_affected_rows() support for bulk operations -- Added shared_cache=true propery to control SQLITE_OPEN_SHAREDCACHE flag - Documentation -- Corrected usage examples - Building -- Updated CMake for Oracle 12g -- Restructured and improved Travis CI setup to do single build per backend -- Fixed wrong GCC_VERSION used in CMake config for commandline-overriden GCC -- Allows CMake to find 32-bit DB2 on Windows x64 -- Removed redundant Oracle libclntsh library lookup -- Fixed SQLITE3_LIBRARIES handling by find_package_handle_standard_args --- Version 3.2.1 differs from 3.2.0 in the following ways: - Fixed binding of Oracle type NUMBER(9,0) to C++ int, by Tomasz Olszewski - Fixed Oracle client library detection on Windows, by Tomasz Olszewski - Fixed PostgreSQL issue with deallocate_prepared_statement called for non-existing statement - Fixed prepared insert statements with custom data types support, by Tomasz Olszewski - Fixed recent improvements in x:=y name binding, by Poul Bondo - Fixed query transformation assignment in pooled sessions, by Stefan Chrobot - Cleaned up SOCI_POSTGRESQL_NOPARAMS and related options in code and documentation - Dropped patch (micro) version number from documentation URLs on the website --- Version 3.2.0 differs from 3.1.0 in the following ways: - SOCI is now organization at GitHub -- Git repository moved to https://github.com/SOCI/soci -- Opened new bug tracker (SF.net tracker is read-only) -- Opened Wiki for FAQ and development articles -- Website, mailing lists and downloads remain on SourceForge.net -- Applied GitFlow branching model -- Added package maintenance repository https://github.com/SOCI/soci-pkg - Core -- Added connection_parameters to enable support for session options used by core, backends or low-level API. -- Added user-defined query transformation support based on function, functor and lambda -- Fixed missing connection check and backend setup ensured for session -- Fixed backend initialization when used with connection pool (Core) -- Fixed memory leaks on exception thrown during statement preparation stage - DB2 -- Added new backend for IBM DB2 - Firebird -- Fixed bug in repeated statement execution -- Fixed issues with input parameter binding -- Fixed connection string parsing to handle possible white-spaces -- Fixed issues with C++ type unsigned long -- Fixed reading negative values into C++ type double -- Added option to fetch numeric/decimal data into string of characters -- Added CMake configuration -- Updated tests -- Continued regular testing on Windows and Unix platforms - MySQL -- Replaced use of type=InnoDB with engine=InnoDB -- Improved CMake configuration - ODBC -- Added connection_parameters option ODBC_OPTION_DRIVER_COMPLETE -- Fixed issues in handling C++ types int and long on 64-bit architectures -- Added missing CMake configuration for tests -- Continued regular testing on Windows and Unix platforms - Oracle -- Implemented statement::get_affected_rows() operation -- Use OCI_THREADED and OCI_ENV_NO_MUTEX with OCIEnvCreate -- Added numerous fixes and improvements in tests -- Added option to fetch numeric/decimal data into string of characters -- Fixed issues in binding procedure IN/OUT parameters - PostgreSQL -- Add reading of BYTEA data into std::string (not fully-featured binary data support yet) -- Add JSON data type support available in PostgreSQL 9.2+ -- Fixed incorrect assertion in postgresql::get_error_details -- Fixed premature deallocation of prepared statements -- Fixed servers-side memory leak in prepared statements -- Fixed memory leak of PGresult on exception thrown -- Fixed isues in parsing complex PL/PSQL functions - SQLite3 -- Implemented statement::get_affected_rows() operation -- Fixed handling of database file path with spaces - Building, testing and installation -- Marked Makefile.basic as deprecated (maintainer wanted) -- Cleaned numerous compilation warnings reported by various compilers -- Improved compilation using latest version of clang -- Added numerous improvements in CMake configuration -- Added SOCI_STATIC option to enable/disable static libraries build -- Fixed issues with ignored -DWITH_ options -- Fixed FindMySQL.cmake to allow use of mysqlclient from custom location -- Added support of SQLITE_ROOT_DIR variable to FindSQLite3.cmake module -- Fixed and tested CMake configuration on OSX -- Fixed and tested CMake configuration on FreeBSD -- Fixed and tested CMake configuration to use with Ninja -- Fixed building using Visual Studio 2010 -- Added support for building using Visual Studio 2012 -- Set up SOCI continuous integration at travis-ci.org -- Added Debian packaging support to soci-pkg repository -- Added Fedora/CentOS/RedHat packaging support to soci-pkg repository - Documentation -- Review and update to catch up with current status quo -- Updated code examples -- Start maintenance and hosting of SOCI documentation per released version --- Version 3.1.0 differs from 3.0.0 in the following ways: - Added Ada language binding - Migraded build system from GNU Autotools and Visual Studio projects to CMake - CMake build tested with Visual Studio, GCC and clang - Incorporated a compromise for naming versioned shared libraries - Enhanced and improved integration with Boost libraries: -- Boost.DateTime -- Boost.Fusion -- Boost.Optional -- Boost.Tuple - Bug fixes and improvements in core and backends: -- Added soci::values::get_properties accessor useful for composing soci::type_conversion -- Export advanced API of backend loader from DLL. -- Added static factory registration functions for backends -- Added get_affected_rows operation -- Fixed thread-safety of connection pool under Windows -- Fixed bug with droping const qualifiers when binding to std::vector -- Fixed bug in default initialization of an object of const backend_factory wihch requires user-provided default constructor (see C++03/C++0x) -- Fixes for 64-bit builds -- Removed redundant exchange_traits breaking ODR on LP64 -- Better ODBC support -- Type conversion support for unsigned integer types -- Bug ID:1971436 - incorrect rowset copy operations -- Bug ID:2010367 - memory leak (ODBC) -- Bug ID:2010409 - invalid memory allocaton in define by position (ODBC) -- Bug ID:2021243 - long long type support in Visual C++ -- Patch ID:2483066 - 64bit Linux and 64bit integer submitted -- Patch ID:2809809 - Fix build with GCC 4.4 -- Patch ID:2809810 - Fix SQLite3 build with GCC 4.3 -- Patch ID:2581206 - Windows unicode application -- Patch ID:3058275 - install target for cmake build submitted -- Patch ID:3069375 - use $(prefix)/lib64 on AMD64 platforms. -- Improved performance while accessing query results (MySQL) -- Bug fixes for PROCEDURE support (MySQL) -- Removed throw statements from mysql_rowid_backend and mysql_blob_backend destructors (MySQL) -- Verify that prepared statements survive session::reconnect() operatoin (MySQL) -- Improved support for time and date (MySQL, PostgreSQL) -- Fixed bug with strings of length exceeding 255 characters (ODBC) -- Improved interpretation of the connect string (Oracle) -- Added handling of unsigned long long (Oracle, SQLite3, PostgreSQL) -- Fixes in integral types support (PostgreSQL) -- Support for colon-casts (PostgreSQL) -- Added possibility for use BLOB (PostgreSQL) -- Added support for connection property "synchronous=on|off" (SQLite3) -- Improved BLOB data handling (SQLite3) -- Improved boolean type suppport (SQLite3) -- Session timeout support (SQLite3) -- Improved tests clean-up (SQLite3) -- Added missing typedef of sqlite3_destructor_type which has been defined in sqlite3.h but since 3.3.10 (see comment for reference to SQLite ticket) - Updated tests for various backends and SQL data types - Migrated from CVS to Git repository - Changed naming convensions and style across all the source code - Firebird backend removed from official release as not actively maintained. Available in the Git repository. --- Version 3.0.0 differs from 2.2.0 in the following ways: - Exposed the session's locale object. - Moved the "no data" flag from indicators to statement. - Allowed const objects as "use" elements. - Added connection mode for Oracle. - Added RAII support for transactions. - Added the open/close/reconnect functionality. - Added support for long long as a fundamental data type. - Unified column names for dynamic rowset description, to overcome differences between database servers. - Added the "simple" interface for interfacing from other languages. - Added thread-safe connection pool. - Added integrated support for Boost data types: gregorian_date, fusion and tuple. - Added dynamic backend loading. - Changed the naming convention to comply with Boost recommendations. --- Version 2.2.0 differs from 2.1.0 in the following ways: - Added true support for statement preparation with PostgreSQL. - Added support for the stream-like extraction from Row. - Added STL-compatible iterator interface for select statements. - Refactored the set of common tests to validate core library functionality independently on the target database server. - Introduced new backends for MS SQL Server (via ODBC) and Firebird. - Provided complete build system for both Unix (autotools) and Windows (solution and project files for MSVC++). --- Version 2.1.0 differs from 2.0.1 in the following ways: - Added two additional backends: MySQL and SQLite3 - Restructured the source code layout so that the whole library was broken into the "core" part and independent "backends", each in its own directory together with appropriate tests. - Provided basic Makefiles for static and shared libraries on Linux-compatible systems. - Added the general class and function reference to the documentation. --- Version 2.0.1 differs from 2.0.0 in the following ways: - Corrected some typos in documentation. - Corrected handling of dynamic rowset description for those backends which do not have dedicated description functionality. - A bug fix to correctly handle std::tm in the Oracle backend. - A bug fix to correctly handle object relational mapping when Values::set() and Values::get() are called where T is a TypeConversion-based type. --- Version 2.0.0 differs from 1.2.1 in the following ways: - The whole library was internally re-architectured to allow operation with many different backends. The top-level part of the library (the syntax layer) provides essentially the same interface as in previous versions of the library, but it can work with independent (and dynamically selected) backends, possibly targeting different database engines. As a prove of concept (and to encourage developments of new backends), the PostgreSQL backend was provided in addition to the Oracle one. During this re-architecturing, some minor bugs were fixed as well. - The old Boost-style license was changed to the new (v. 1.0) Boost license. --- The version 1.2.1 differs from 1.2.0 in the following ways: - A bug was fixed that caused compile errors on MS VC++ compiler. --- The version 1.2.0 differs from 1.1.0 in the following ways: - A memory leak when reading into Row objects was fixed. - Bulk (array) operations were introduced for high-performance applications, where the number of network round-trips can be significantly reduced by operating on whole arrays (vectors). --- The version 1.1.0 differs from 1.0.1 in the following ways: - Explicit support for calling stored procedures was added. - Dynamic row recognition (type discovery) was added. - Support for user-defined data types was added. soci-3.2.3/README.md0000644000000000000000000000271212511361676012443 0ustar rootrootSOCI - The C++ Database Access Library ====================================== Website: http://soci.sourceforge.net GitHub hosts SOCI source code repository, issues tracker and wiki: https://github.com/SOCI Downloads and mailing lists at http://sourceforge.net/projects/soci/ Travis CI service at https://travis-ci.org/SOCI/soci [![Build Status](https://api.travis-ci.org/SOCI/soci.png)](https://travis-ci.org/SOCI/soci) License ------- The SOCI library is distributed under the terms of the [Boost Software License](http://www.boost.org/LICENSE_1_0.txt). Requirements ------------ Core: * C++ compiler * Boost C++ Libraries (optional, headers only) Backend specific client libraries for: * DB2 * Firebird * MySQL * ODBC andwith specific database driver * Oracle * PostgreSQL * SQLite 3 See documentation at http://soci.sourceforge.net for details Brief History ------------- Originally, SOCI was developed by [Maciej Sobczak](http://www.msobczak.com/) at [CERN](http://www.cern.ch/) as abstraction layer for Oracle, a **Simple Oracle Call Interface**. Later, several database backends have been developed for SOCI, thus the long name has lost its practicality. Currently, if you like, SOCI may stand for **Simple Open (Database) Call Interface** or something similar. > "CERN is also a user of the SOCI library, which serves as a database access > layer in some of the control system components." -- Maciej Sobczak at [Inspirel](http://www.inspirel.com/users.html) soci-3.2.3/LICENSE_1_0.txt0000644000000000000000000000247212511362240013435 0ustar rootrootBoost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. soci-3.2.3/AUTHORS0000644000000000000000000000243112511401144012213 0ustar rootroot=== SOCI Team === Alex Ott David Courtney Denis Arnaud Denis Chapligin Julian Taylor Maciej Sobczak Mateusz Łoskot Paweł Aleksander Fedoryński Rafał Bobrowski Sergei Nikulov Steve Hutton Vadim Zeitlin Viacheslav Naydenov === SOCI Contributors === We would like to thank you for your contributions - they allowed us to improve the quality of the SOCI library: Adesmier Alex Volanis Andrey Belobrov Andrey Utkin Andriy Gapon Artyom Beilis Artyom Tonkikh avg-I b-s-a Brian R. Toonen Cengizhan Paşaoğlu Chris Weed Cory Bennett creste Daniel Lidström Eli Green Faik Uygur Fedor Trushkin Frank Bielig Frederic Chateau Gevorg Voskanyan Henning Basold Howard Butler Ilia Barahovski Jakub Stachowski jamercee Joerg Sonnenberger Krzysztof Bieleń Mario Valesco Martin Muenstermann Mathias Hasselmann Matt Arsenault Matthieu Kermagoret Michael Davidsaver Mika Fischer pacocamberos Paul Bondo Petr Vanek Philip Pemberton Rainer Bauer Ricardo Andrade ryandesign Robert Massaioli Roger Orr Sergey Belyashov Shridhar Daithankar Sören Meyer-Eppler soyersoyer Stefan Chrobot Tomasz Olszewski Vaclav Slavik xol There are a lot of people that help to drive SOCI project forward, if we have forgot to mention someone in here, if you would like to be listed by name instead of GitHub username, send us an email! soci-3.2.3/languages/0000755000000000000000000000000012511362240013114 5ustar rootrootsoci-3.2.3/languages/ada/0000755000000000000000000000000012511362240013641 5ustar rootrootsoci-3.2.3/languages/ada/soci-oracle.ads0000644000000000000000000000075112511362240016535 0ustar rootroot-- Copyright (C) 2008-2011 Maciej Sobczak -- Distributed under the Boost Software License, Version 1.0. -- (See accompanying file LICENSE_1_0.txt or copy at -- http://www.boost.org/LICENSE_1_0.txt) package SOCI.Oracle is -- -- Registers the Oracle backend so that it is ready for use -- by the dynamic backend loader. -- procedure Register_Factory_Oracle; pragma Import (C, Register_Factory_Oracle, "register_factory_oracle"); end SOCI.Oracle; soci-3.2.3/languages/ada/postgresql_client.gpr0000644000000000000000000000033512511362240020115 0ustar rootrootproject PostgreSQL_Client is for Externally_Built use "true"; for Source_Dirs use (); for Library_Dir use "/usr/local/lib"; for Library_Name use "pq"; for Library_Kind use "static"; end PostgreSQL_Client; soci-3.2.3/languages/ada/soci.adb0000644000000000000000000013372012511362240015254 0ustar rootroot-- Copyright (C) 2008-2011 Maciej Sobczak -- Distributed under the Boost Software License, Version 1.0. -- (See accompanying file LICENSE_1_0.txt or copy at -- http://www.boost.org/LICENSE_1_0.txt) with Ada.Strings.Fixed; with Interfaces.C.Strings; package body SOCI is procedure Check_Session_State (Handle : in Session_Handle) is function Soci_Session_State (S : in Session_Handle) return Interfaces.C.int; pragma Import (C, Soci_Session_State, "soci_session_state"); function Soci_Session_Error_Message (S : in Session_Handle) return Interfaces.C.Strings.chars_ptr; pragma Import (C, Soci_Session_Error_Message, "soci_session_error_message"); State : constant Interfaces.C.int := Soci_Session_State (Handle); Bad_State : constant Interfaces.C.int := 0; use type Interfaces.C.int; begin if State = Bad_State then declare Message : constant String := Interfaces.C.Strings.Value (Soci_Session_Error_Message (Handle)); begin raise Database_Error with Message; end; end if; end Check_Session_State; function Make_Session_Handle (Connection_String : in String) return Session_Handle is function Soci_Create_Session (C : in Interfaces.C.char_array) return Session_Handle; pragma Import (C, Soci_Create_Session, "soci_create_session"); Connection_String_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Connection_String); Handle : constant Session_Handle := Soci_Create_Session (Connection_String_C); begin if Handle = Null_Session_Handle then raise Database_Error with "Cannot create session object."; else return Handle; end if; end Make_Session_Handle; function Data_State_To_Int (State : in Data_State) return Interfaces.C.int is begin if State = Data_Not_Null then return 1; else return 0; end if; end Data_State_To_Int; function Int_To_Data_State (State : in Interfaces.C.int) return Data_State is use type Interfaces.C.int; begin if State /= 0 then return Data_Not_Null; else return Data_Null; end if; end Int_To_Data_State; procedure Check_Is_Open (This : in Session'Class) is begin if not This.Initialized then raise Database_Error with "Session is not initialized."; end if; end Check_Is_Open; procedure Check_Statement_State (Handle : in Statement_Handle) is function Soci_Statement_State (S : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Statement_State, "soci_statement_state"); function Soci_Statement_Error_Message (S : in Statement_Handle) return Interfaces.C.Strings.chars_ptr; pragma Import (C, Soci_Statement_Error_Message, "soci_statement_error_message"); State : constant Interfaces.C.int := Soci_Statement_State (Handle); Bad_State : constant Interfaces.C.int := 0; use type Interfaces.C.int; begin if State = Bad_State then declare Message : constant String := Interfaces.C.Strings.Value (Soci_Statement_Error_Message (Handle)); begin raise Database_Error with Message; end; end if; end Check_Statement_State; function String_To_Time (Source : in String) return Ada.Calendar.Time is Year_N : Natural; Month_N : Natural; Day_N : Natural; Hour_N : Natural; Minute_N : Natural; Second_N : Natural; procedure Get_Next_Number (Source : in String; Position : in out Natural; Result : out Natural) is I : Natural; begin I := Ada.Strings.Fixed.Index (Source => Source, Pattern => " ", From => Position); if I /= 0 then Result := Natural'Value (Source (Position .. I)); Position := I + 1; else Result := Natural'Value (Source (Position .. Source'Last)); Position := 0; end if; end Get_Next_Number; Pos : Natural := 1; begin Get_Next_Number (Source => Source, Position => Pos, Result => Year_N); Get_Next_Number (Source => Source, Position => Pos, Result => Month_N); Get_Next_Number (Source => Source, Position => Pos, Result => Day_N); Get_Next_Number (Source => Source, Position => Pos, Result => Hour_N); Get_Next_Number (Source => Source, Position => Pos, Result => Minute_N); Get_Next_Number (Source => Source, Position => Pos, Result => Second_N); return Ada.Calendar.Time_Of (Year_N, Month_N, Day_N, Duration (Hour_N * 3_600 + Minute_N * 60 + Second_N)); end String_To_Time; function Time_To_String (Date : in Ada.Calendar.Time) return String is Year : Ada.Calendar.Year_Number; Month : Ada.Calendar.Month_Number; Day : Ada.Calendar.Day_Number; Seconds : Ada.Calendar.Day_Duration; Hour : Natural; Minute : Natural; Seconds_N : Natural; begin Ada.Calendar.Split (Date, Year, Month, Day, Seconds); Seconds_N := Natural (Seconds); Hour := Seconds_N / 3_600; Minute := (Seconds_N - Natural (Hour) * 3_600) / 60; Seconds_N := Seconds_N - Natural (Hour) * 3_600 - Natural (Minute) * 60; return Ada.Calendar.Year_Number'Image (Year) & " " & Ada.Calendar.Month_Number'Image (Month) & " " & Ada.Calendar.Day_Number'Image (Day) & " " & Natural'Image (Hour) & " " & Natural'Image (Minute) & " " & Natural'Image (Seconds_N); end Time_To_String; function Make_Session (Connection_String : in String) return Session is begin return S : Session do S.Handle := Make_Session_Handle (Connection_String); S.Initialized := True; Check_Session_State (S.Handle); end return; end Make_Session; procedure Open (This : in out Session; Connection_String : in String) is begin if This.Initialized then raise Database_Error with "Session is already initialized."; else declare Handle : constant Session_Handle := Make_Session_Handle (Connection_String); begin Check_Session_State (Handle); This.Handle := Handle; This.Initialized := True; end; end if; end Open; procedure Close (This : in out Session) is procedure Soci_Destroy_Session (S : in Session_Handle); pragma Import (C, Soci_Destroy_Session, "soci_destroy_session"); begin if This.Initialized then if This.Belongs_To_Pool then raise Database_Error with "Cannot close session - not an owner (session in pool)."; else Soci_Destroy_Session (This.Handle); This.Initialized := False; end if; end if; end Close; function Is_Open (This : in Session) return Boolean is begin return This.Initialized; end Is_Open; procedure Finalize (This : in out Session) is begin if This.Initialized then if This.Belongs_To_Pool then This.Pool.all.Give_Back (This.Position_In_Pool); This.Initialized := False; else This.Close; end if; end if; end Finalize; procedure Start (This : in Session) is procedure Soci_Begin (S : in Session_Handle); pragma Import (C, Soci_Begin, "soci_begin"); begin Check_Is_Open (This); Soci_Begin (This.Handle); Check_Session_State (This.Handle); end Start; procedure Commit (This : in Session) is procedure Soci_Commit (S : in Session_Handle); pragma Import (C, Soci_Commit, "soci_commit"); begin Check_Is_Open (This); Soci_Commit (This.Handle); Check_Session_State (This.Handle); end Commit; procedure Rollback (This : in Session) is procedure Soci_Rollback (S : in Session_Handle); pragma Import (C, Soci_Rollback, "soci_rollback"); begin Check_Is_Open (This); Soci_Rollback (This.Handle); Check_Session_State (This.Handle); end Rollback; procedure Execute (This : in Session; Query : in String) is S : Statement := Make_Statement (This); begin S.Prepare (Query); S.Execute; end Execute; protected body Connection_Pool_PS is procedure Open (Position : in Positive; Connection_String : in String) is begin if Position > Size then raise Database_Error with "Index out of range."; end if; Connections (Position).Open (Connection_String); end Open; procedure Close (Position : in Positive) is begin if Position > Size then raise Database_Error with "Index out of range."; end if; if Is_Used (Position) then raise Database_Error with "Cannot close connection that is currently in use."; end if; Connections (Position).Close; end Close; entry Lease (S : in out Session'Class) when Available is Found : Boolean := False; begin if S.Initialized then raise Database_Error with "This session is already initialized."; end if; -- Find some connection in the pool that is not currently used. for I in 1 .. Size loop if not Is_Used (I) then Check_Is_Open (Connections (I)); S.Handle := Connections (I).Handle; S.Initialized := True; S.Belongs_To_Pool := True; S.Position_In_Pool := I; -- WORKAROUND: -- The S.Pool component is set in the Lease procedure -- of the Connection_Pool type, because here the access -- to the protected object could not be taken (compiler bug). Is_Used (I) := True; Found := True; exit; end if; end loop; if not Found then raise Database_Error with "Internal error."; end if; -- Update the Available flag. Found := False; for I in 1 .. Size loop if not Is_Used (I) then Found := True; exit; end if; end loop; Available := Found; end Lease; procedure Give_Back (Position : in Positive) is begin if Position > Size then raise Database_Error with "Index out of range."; end if; if not Is_Used (Position) then raise Database_Error with "Cannot give back connection that is not in use."; end if; Is_Used (Position) := False; Available := True; end Give_Back; end Connection_Pool_PS; procedure Open (This : in out Connection_Pool; Position : in Positive; Connection_String : in String) is begin This.Pool.Open (Position, Connection_String); end Open; procedure Close (This : in out Connection_Pool; Position : in Positive) is begin This.Pool.Close (Position); end Close; procedure Lease (This : in out Connection_Pool; S : in out Session'Class) is begin This.Pool.Lease (S); -- WORKAROUND: -- The S.Pool component is set here because the access -- to protected object cannot be taken in protected body (compiler bug.) -- JUSTIFICATION: -- The Unchecked_Access is taken here to enable the session to properly -- "unregister" from the pool in Session's Finalize. -- An alternative would be to rely on the user to explicitly unlock -- the appropriate entry in the pool, which is too error prone. -- It is assumed that connection pool always has wider lifetime -- than that of the session which is temporarily leased from the pool -- - this guarantees that S.Pool always points to a valid pool object. S.Pool := This.Pool'Unchecked_Access; end Lease; function Make_Statement (Sess : in Session'Class) return Statement is function Soci_Create_Statement (Sess : in Session_Handle) return Statement_Handle; pragma Import (C, Soci_Create_Statement, "soci_create_statement"); begin Check_Is_Open (Sess); declare Handle : constant Statement_Handle := Soci_Create_Statement (Sess.Handle); begin return S : Statement do S.Handle := Handle; S.Initialized := True; Check_Statement_State (S.Handle); end return; end; end Make_Statement; procedure Finalize (This : in out Statement) is procedure Soci_Destroy_Statement (S : in Statement_Handle); pragma Import (C, Soci_Destroy_Statement, "soci_destroy_statement"); begin if This.Initialized then Soci_Destroy_Statement (This.Handle); This.Initialized := False; end if; end Finalize; procedure Prepare (This : in Statement; Query : in String) is procedure Soci_Prepare (St : in Statement_Handle; Q : in Interfaces.C.char_array); pragma Import (C, Soci_Prepare, "soci_prepare"); Query_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Query); begin Soci_Prepare (This.Handle, Query_C); Check_Statement_State (This.Handle); end Prepare; procedure Execute (This : in Statement; With_Data_Exchange : in Boolean := False) is Result : constant Boolean := This.Execute (With_Data_Exchange); begin null; end Execute; function Execute (This : in Statement; With_Data_Exchange : in Boolean := False) return Boolean is function Soci_Execute (St : in Statement_Handle; WDE : in Interfaces.C.int) return Interfaces.C.int; pragma Import (C, Soci_Execute, "soci_execute"); WDE_C : Interfaces.C.int; Result : Interfaces.C.int; use type Interfaces.C.int; begin if With_Data_Exchange then WDE_C := 1; else WDE_C := 0; end if; Result := Soci_Execute (This.Handle, WDE_C); Check_Statement_State (This.Handle); return Result /= 0; end Execute; function Fetch (This : in Statement) return Boolean is function Soci_Fetch (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Fetch, "soci_fetch"); Result : constant Interfaces.C.int := Soci_Fetch (This.Handle); use type Interfaces.C.int; begin Check_Statement_State (This.Handle); return Result /= 0; end Fetch; function Got_Data (This : in Statement) return Boolean is function Soci_Got_Data (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Got_Data, "soci_got_data"); Result : constant Interfaces.C.int := Soci_Got_Data (This.Handle); use type Interfaces.C.int; begin Check_Statement_State (This.Handle); return Result /= 0; end Got_Data; function Into_String (This : in Statement) return Into_Position is function Soci_Into_String (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Into_String, "soci_into_string"); Result : constant Interfaces.C.int := Soci_Into_String (This.Handle); begin Check_Statement_State (This.Handle); return Into_Position (Result); end Into_String; function Into_Integer (This : in Statement) return Into_Position is function Soci_Into_Int (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Into_Int, "soci_into_int"); Result : constant Interfaces.C.int := Soci_Into_Int (This.Handle); begin Check_Statement_State (This.Handle); return Into_Position (Result); end Into_Integer; function Into_Long_Long_Integer (This : in Statement) return Into_Position is function Soci_Into_Long_Long (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Into_Long_Long, "soci_into_long_long"); Result : constant Interfaces.C.int := Soci_Into_Long_Long (This.Handle); begin Check_Statement_State (This.Handle); return Into_Position (Result); end Into_Long_Long_Integer; function Into_Long_Float (This : in Statement) return Into_Position is function Soci_Into_Double (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Into_Double, "soci_into_double"); Result : constant Interfaces.C.int := Soci_Into_Double (This.Handle); begin Check_Statement_State (This.Handle); return Into_Position (Result); end Into_Long_Float; function Into_Time (This : in Statement) return Into_Position is function Soci_Into_Date (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Into_Date, "soci_into_date"); Result : constant Interfaces.C.int := Soci_Into_Date (This.Handle); begin Check_Statement_State (This.Handle); return Into_Position (Result); end Into_Time; function Into_Vector_String (This : in Statement) return Into_Position is function Soci_Into_String_V (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Into_String_V, "soci_into_string_v"); Result : constant Interfaces.C.int := Soci_Into_String_V (This.Handle); begin Check_Statement_State (This.Handle); return Into_Position (Result); end Into_Vector_String; function Into_Vector_Integer (This : in Statement) return Into_Position is function Soci_Into_Int_V (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Into_Int_V, "soci_into_int_v"); Result : constant Interfaces.C.int := Soci_Into_Int_V (This.Handle); begin Check_Statement_State (This.Handle); return Into_Position (Result); end Into_Vector_Integer; function Into_Vector_Long_Long_Integer (This : in Statement) return Into_Position is function Soci_Into_Long_Long_V (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Into_Long_Long_V, "soci_into_long_long_v"); Result : constant Interfaces.C.int := Soci_Into_Long_Long_V (This.Handle); begin Check_Statement_State (This.Handle); return Into_Position (Result); end Into_Vector_Long_Long_Integer; function Into_Vector_Long_Float (This : in Statement) return Into_Position is function Soci_Into_Double_V (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Into_Double_V, "soci_into_double_v"); Result : constant Interfaces.C.int := Soci_Into_Double_V (This.Handle); begin Check_Statement_State (This.Handle); return Into_Position (Result); end Into_Vector_Long_Float; function Into_Vector_Time (This : in Statement) return Into_Position is function Soci_Into_Date_V (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Into_Date_V, "soci_into_date_v"); Result : constant Interfaces.C.int := Soci_Into_Date_V (This.Handle); begin Check_Statement_State (This.Handle); return Into_Position (Result); end Into_Vector_Time; function Get_Into_State (This : in Statement; Position : in Into_Position) return Data_State is function Soci_Get_Into_State (St : in Statement_Handle; P : in Interfaces.C.int) return Interfaces.C.int; pragma Import (C, Soci_Get_Into_State, "soci_get_into_state"); Result : constant Interfaces.C.int := Soci_Get_Into_State (This.Handle, Interfaces.C.int (Position)); use type Interfaces.C.int; begin Check_Statement_State (This.Handle); return Int_To_Data_State (Result); end Get_Into_State; function Get_Into_String (This : in Statement; Position : in Into_Position) return String is function Soci_Get_Into_String (St : in Statement_Handle; P : in Interfaces.C.int) return Interfaces.C.Strings.chars_ptr; pragma Import (C, Soci_Get_Into_String, "soci_get_into_string"); Result : constant Interfaces.C.Strings.chars_ptr := Soci_Get_Into_String (This.Handle, Interfaces.C.int (Position)); begin Check_Statement_State (This.Handle); return Interfaces.C.Strings.Value (Result); end Get_Into_String; function Get_Into_Integer (This : in Statement; Position : in Into_Position) return DB_Integer is function Soci_Get_Into_Int (St : in Statement_Handle; P : in Interfaces.C.int) return Interfaces.C.int; pragma Import (C, Soci_Get_Into_Int, "soci_get_into_int"); Result : constant Interfaces.C.int := Soci_Get_Into_Int (This.Handle, Interfaces.C.int (Position)); begin Check_Statement_State (This.Handle); return DB_Integer (Result); end Get_Into_Integer; function Get_Into_Long_Long_Integer (This : in Statement; Position : in Into_Position) return DB_Long_Long_Integer is function Soci_Get_Into_Long_Long (St : in Statement_Handle; P : in Interfaces.C.int) return Interfaces.Integer_64; pragma Import (C, Soci_Get_Into_Long_Long, "soci_get_into_long_long"); Result : constant Interfaces.Integer_64 := Soci_Get_Into_Long_Long (This.Handle, Interfaces.C.int (Position)); begin Check_Statement_State (This.Handle); return DB_Long_Long_Integer (Result); end Get_Into_Long_Long_Integer; function Get_Into_Long_Float (This : in Statement; Position : in Into_Position) return DB_Long_Float is function Soci_Get_Into_Double (St : in Statement_Handle; P : in Interfaces.C.int) return Interfaces.C.double; pragma Import (C, Soci_Get_Into_Double, "soci_get_into_double"); Result : constant Interfaces.C.double := Soci_Get_Into_Double (This.Handle, Interfaces.C.int (Position)); begin Check_Statement_State (This.Handle); return DB_Long_Float (Result); end Get_Into_Long_Float; function Get_Into_Time (This : in Statement; Position : in Into_Position) return Ada.Calendar.Time is function Soci_Get_Into_Date (St : in Statement_Handle; P : in Interfaces.C.int) return Interfaces.C.Strings.chars_ptr; pragma Import (C, Soci_Get_Into_Date, "soci_get_into_date"); Result_C : constant Interfaces.C.Strings.chars_ptr := Soci_Get_Into_Date (This.Handle, Interfaces.C.int (Position)); Result : constant String := Interfaces.C.Strings.Value (Result_C); begin Check_Statement_State (This.Handle); return String_To_Time (Result); end Get_Into_Time; function Get_Into_Vectors_Size (This : in Statement) return Natural is function Soci_Into_Get_Size_V (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Into_Get_Size_V, "soci_into_get_size_v"); Result_C : constant Interfaces.C.int := Soci_Into_Get_Size_V (This.Handle); begin Check_Statement_State (This.Handle); return Natural (Result_C); end Get_Into_Vectors_Size; function Into_Vectors_First_Index (This : in Statement) return Vector_Index is begin return 0; end Into_Vectors_First_Index; function Into_Vectors_Last_Index (This : in Statement) return Vector_Index is begin return Vector_Index (This.Get_Into_Vectors_Size - 1); end Into_Vectors_Last_Index; procedure Into_Vectors_Resize (This : in Statement; New_Size : in Natural) is procedure Soci_Into_Resize_V (St : in Statement_Handle; New_Size : in Interfaces.C.int); pragma Import (C, Soci_Into_Resize_V, "soci_into_resize_v"); begin Soci_Into_Resize_V (This.Handle, Interfaces.C.int (New_Size)); Check_Statement_State (This.Handle); end Into_Vectors_Resize; function Get_Into_Vector_State (This : in Statement; Position : in Into_Position; Index : in Vector_Index) return Data_State is function Soci_Get_Into_State_V (St : in Statement_Handle; P : in Interfaces.C.int; I : in Interfaces.C.int) return Interfaces.C.int; pragma Import (C, Soci_Get_Into_State_V, "soci_get_into_state_v"); Result : constant Interfaces.C.int := Soci_Get_Into_State_V (This.Handle, Interfaces.C.int (Position), Interfaces.C.int (Index)); use type Interfaces.C.int; begin Check_Statement_State (This.Handle); return Int_To_Data_State (Result); end Get_Into_Vector_State; function Get_Into_Vector_String (This : in Statement; Position : in Into_Position; Index : in Vector_Index) return String is function Soci_Get_Into_String_V (St : in Statement_Handle; P : in Interfaces.C.int; I : in Interfaces.C.int) return Interfaces.C.Strings.chars_ptr; pragma Import (C, Soci_Get_Into_String_V, "soci_get_into_string_v"); Result : constant Interfaces.C.Strings.chars_ptr := Soci_Get_Into_String_V (This.Handle, Interfaces.C.int (Position), Interfaces.C.int (Index)); begin Check_Statement_State (This.Handle); return Interfaces.C.Strings.Value (Result); end Get_Into_Vector_String; function Get_Into_Vector_Integer (This : in Statement; Position : in Into_Position; Index : in Vector_Index) return DB_Integer is function Soci_Get_Into_Int_V (St : in Statement_Handle; P : in Interfaces.C.int; I : in Interfaces.C.int) return Interfaces.C.int; pragma Import (C, Soci_Get_Into_Int_V, "soci_get_into_int_v"); Result : constant Interfaces.C.int := Soci_Get_Into_Int_V (This.Handle, Interfaces.C.int (Position), Interfaces.C.int (Index)); begin Check_Statement_State (This.Handle); return DB_Integer (Result); end Get_Into_Vector_Integer; function Get_Into_Vector_Long_Long_Integer (This : in Statement; Position : in Into_Position; Index : in Vector_Index) return DB_Long_Long_Integer is function Soci_Get_Into_Long_Long_V (St : in Statement_Handle; P : in Interfaces.C.int; I : in Interfaces.C.int) return Interfaces.Integer_64; pragma Import (C, Soci_Get_Into_Long_Long_V, "soci_get_into_long_long_v"); Result : constant Interfaces.Integer_64 := Soci_Get_Into_Long_Long_V (This.Handle, Interfaces.C.int (Position), Interfaces.C.int (Index)); begin Check_Statement_State (This.Handle); return DB_Long_Long_Integer (Result); end Get_Into_Vector_Long_Long_Integer; function Get_Into_Vector_Long_Float (This : in Statement; Position : in Into_Position; Index : in Vector_Index) return DB_Long_Float is function Soci_Get_Into_Double_V (St : in Statement_Handle; P : in Interfaces.C.int; I : in Interfaces.C.int) return Interfaces.C.double; pragma Import (C, Soci_Get_Into_Double_V, "soci_get_into_double_v"); Result : constant Interfaces.C.double := Soci_Get_Into_Double_V (This.Handle, Interfaces.C.int (Position), Interfaces.C.int (Index)); begin Check_Statement_State (This.Handle); return DB_Long_Float (Result); end Get_Into_Vector_Long_Float; function Get_Into_Vector_Time (This : in Statement; Position : in Into_Position; Index : in Vector_Index) return Ada.Calendar.Time is function Soci_Get_Into_Date_V (St : in Statement_Handle; P : in Interfaces.C.int; I : in Interfaces.C.int) return Interfaces.C.Strings.chars_ptr; pragma Import (C, Soci_Get_Into_Date_V, "soci_get_into_date_v"); Result_C : constant Interfaces.C.Strings.chars_ptr := Soci_Get_Into_Date_V (This.Handle, Interfaces.C.int (Position), Interfaces.C.int (Index)); Result : constant String := Interfaces.C.Strings.Value (Result_C); begin Check_Statement_State (This.Handle); return String_To_Time (Result); end Get_Into_Vector_Time; procedure Use_String (This : in Statement; Name : in String) is procedure Soci_Use_String (St : in Statement_Handle; Name : in Interfaces.C.char_array); pragma Import (C, Soci_Use_String, "soci_use_string"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); begin Soci_Use_String (This.Handle, Name_C); Check_Statement_State (This.Handle); end Use_String; procedure Use_Integer (This : in Statement; Name : in String) is procedure Soci_Use_Int (St : in Statement_Handle; Name : in Interfaces.C.char_array); pragma Import (C, Soci_Use_Int, "soci_use_int"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); begin Soci_Use_Int (This.Handle, Name_C); Check_Statement_State (This.Handle); end Use_Integer; procedure Use_Long_Long_Integer (This : in Statement; Name : in String) is procedure Soci_Use_Long_Long (St : in Statement_Handle; Name : in Interfaces.C.char_array); pragma Import (C, Soci_Use_Long_Long, "soci_use_long_long"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); begin Soci_Use_Long_Long (This.Handle, Name_C); Check_Statement_State (This.Handle); end Use_Long_Long_Integer; procedure Use_Long_Float (This : in Statement; Name : in String) is procedure Soci_Use_Double (St : in Statement_Handle; Name : in Interfaces.C.char_array); pragma Import (C, Soci_Use_Double, "soci_use_double"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); begin Soci_Use_Double (This.Handle, Name_C); Check_Statement_State (This.Handle); end Use_Long_Float; procedure Use_Time (This : in Statement; Name : in String) is procedure Soci_Use_Date (St : in Statement_Handle; Name : in Interfaces.C.char_array); pragma Import (C, Soci_Use_Date, "soci_use_date"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); begin Soci_Use_Date (This.Handle, Name_C); Check_Statement_State (This.Handle); end Use_Time; procedure Use_Vector_String (This : in Statement; Name : in String) is procedure Soci_Use_String_V (St : in Statement_Handle; Name : in Interfaces.C.char_array); pragma Import (C, Soci_Use_String_V, "soci_use_string_v"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); begin Soci_Use_String_V (This.Handle, Name_C); Check_Statement_State (This.Handle); end Use_Vector_String; procedure Use_Vector_Integer (This : in Statement; Name : in String) is procedure Soci_Use_Int_V (St : in Statement_Handle; Name : in Interfaces.C.char_array); pragma Import (C, Soci_Use_Int_V, "soci_use_int_v"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); begin Soci_Use_Int_V (This.Handle, Name_C); Check_Statement_State (This.Handle); end Use_Vector_Integer; procedure Use_Vector_Long_Long_Integer (This : in Statement; Name : in String) is procedure Soci_Use_Long_Long_V (St : in Statement_Handle; Name : in Interfaces.C.char_array); pragma Import (C, Soci_Use_Long_Long_V, "soci_use_long_long_v"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); begin Soci_Use_Long_Long_V (This.Handle, Name_C); Check_Statement_State (This.Handle); end Use_Vector_Long_Long_Integer; procedure Use_Vector_Long_Float (This : in Statement; Name : in String) is procedure Soci_Use_Double_V (St : in Statement_Handle; Name : in Interfaces.C.char_array); pragma Import (C, Soci_Use_Double_V, "soci_use_double_v"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); begin Soci_Use_Double_V (This.Handle, Name_C); Check_Statement_State (This.Handle); end Use_Vector_Long_Float; procedure Use_Vector_Time (This : in Statement; Name : in String) is procedure Soci_Use_Date_V (St : in Statement_Handle; Name : in Interfaces.C.char_array); pragma Import (C, Soci_Use_Date_V, "soci_use_date_v"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); begin Soci_Use_Date_V (This.Handle, Name_C); Check_Statement_State (This.Handle); end Use_Vector_Time; procedure Set_Use_State (This : in Statement; Name : in String; State : in Data_State) is procedure Soci_Set_Use_State (St : in Statement_Handle; Name : in Interfaces.C.char_array; State : in Interfaces.C.int); pragma Import (C, Soci_Set_Use_State, "soci_set_use_state"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); State_C : constant Interfaces.C.int := Data_State_To_Int (State); begin Soci_Set_Use_State (This.Handle, Name_C, State_C); Check_Statement_State (This.Handle); end Set_Use_State; procedure Set_Use_String (This : in Statement; Name : in String; Value : in String) is procedure Soci_Set_Use_String (St : in Statement_Handle; Name : in Interfaces.C.char_array; Value : in Interfaces.C.char_array); pragma Import (C, Soci_Set_Use_String, "soci_set_use_string"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Value_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Value); begin Soci_Set_Use_String (This.Handle, Name_C, Value_C); Check_Statement_State (This.Handle); end Set_Use_String; procedure Set_Use_Integer (This : in Statement; Name : in String; Value : in DB_Integer) is procedure Soci_Set_Use_Int (St : in Statement_Handle; Name : in Interfaces.C.char_array; Value : in Interfaces.C.int); pragma Import (C, Soci_Set_Use_Int, "soci_set_use_int"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Value_C : constant Interfaces.C.int := Interfaces.C.int (Value); begin Soci_Set_Use_Int (This.Handle, Name_C, Value_C); Check_Statement_State (This.Handle); end Set_Use_Integer; procedure Set_Use_Long_Long_Integer (This : in Statement; Name : in String; Value : in DB_Long_Long_Integer) is procedure Soci_Set_Use_Long_Long (St : in Statement_Handle; Name : in Interfaces.C.char_array; Value : in Interfaces.Integer_64); pragma Import (C, Soci_Set_Use_Long_Long, "soci_set_use_long_long"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Value_C : constant Interfaces.Integer_64 := Interfaces.Integer_64 (Value); begin Soci_Set_Use_Long_Long (This.Handle, Name_C, Value_C); Check_Statement_State (This.Handle); end Set_Use_Long_Long_Integer; procedure Set_Use_Long_Float (This : in Statement; Name : in String; Value : in DB_Long_Float) is procedure Soci_Set_Use_Double (St : in Statement_Handle; Name : in Interfaces.C.char_array; Value : in Interfaces.C.double); pragma Import (C, Soci_Set_Use_Double, "soci_set_use_double"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Value_C : constant Interfaces.C.double := Interfaces.C.double (Value); begin Soci_Set_Use_Double (This.Handle, Name_C, Value_C); Check_Statement_State (This.Handle); end Set_Use_Long_Float; procedure Set_Use_Time (This : in Statement; Name : in String; Value : in Ada.Calendar.Time) is procedure Soci_Set_Use_Date (St : in Statement_Handle; Name : in Interfaces.C.char_array; Value : in Interfaces.C.char_array); pragma Import (C, Soci_Set_Use_Date, "soci_set_use_date"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Value_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Time_To_String (Value)); begin Soci_Set_Use_Date (This.Handle, Name_C, Value_C); Check_Statement_State (This.Handle); end Set_Use_Time; function Get_Use_Vectors_Size (This : in Statement) return Natural is function Soci_Use_Get_Size_V (St : in Statement_Handle) return Interfaces.C.int; pragma Import (C, Soci_Use_Get_Size_V, "soci_use_get_size_v"); Result_C : constant Interfaces.C.int := Soci_Use_Get_Size_V (This.Handle); begin Check_Statement_State (This.Handle); return Natural (Result_C); end Get_Use_Vectors_Size; function Use_Vectors_First_Index (This : in Statement) return Vector_Index is begin return 0; end Use_Vectors_First_Index; function Use_Vectors_Last_Index (This : in Statement) return Vector_Index is begin return Vector_Index (This.Get_Use_Vectors_Size - 1); end Use_Vectors_Last_Index; procedure Use_Vectors_Resize (This : in Statement; New_Size : in Natural) is procedure Soci_Use_Resize_V (St : in Statement_Handle; New_Size : in Interfaces.C.int); pragma Import (C, Soci_Use_Resize_V, "soci_use_resize_v"); begin Soci_Use_Resize_V (This.Handle, Interfaces.C.int (New_Size)); Check_Statement_State (This.Handle); end Use_Vectors_Resize; procedure Set_Use_Vector_State (This : in Statement; Name : in String; Index : in Vector_Index; State : in Data_State) is procedure Soci_Set_Use_State_V (St : in Statement_Handle; Name : in Interfaces.C.char_array; Index : in Interfaces.C.int; State : in Interfaces.C.int); pragma Import (C, Soci_Set_Use_State_V, "soci_set_use_state_v"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Index_C : constant Interfaces.C.int := Interfaces.C.int (Index); State_C : constant Interfaces.C.int := Data_State_To_Int (State); begin Soci_Set_Use_State_V (This.Handle, Name_C, Index_C, State_C); Check_Statement_State (This.Handle); end Set_Use_Vector_State; procedure Set_Use_Vector_String (This : in Statement; Name : in String; Index : in Vector_Index; Value : in String) is procedure Soci_Set_Use_String_V (St : in Statement_Handle; Name : in Interfaces.C.char_array; Index : in Interfaces.C.int; Value : in Interfaces.C.char_array); pragma Import (C, Soci_Set_Use_String_V, "soci_set_use_string_v"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Index_C : constant Interfaces.C.int := Interfaces.C.int (Index); Value_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Value); begin Soci_Set_Use_String_V (This.Handle, Name_C, Index_C, Value_C); Check_Statement_State (This.Handle); end Set_Use_Vector_String; procedure Set_Use_Vector_Integer (This : in Statement; Name : in String; Index : in Vector_Index; Value : in DB_Integer) is procedure Soci_Set_Use_Int_V (St : in Statement_Handle; Name : in Interfaces.C.char_array; Index : in Interfaces.C.int; Value : in Interfaces.C.int); pragma Import (C, Soci_Set_Use_Int_V, "soci_set_use_int_v"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Index_C : constant Interfaces.C.int := Interfaces.C.int (Index); Value_C : constant Interfaces.C.int := Interfaces.C.int (Value); begin Soci_Set_Use_Int_V (This.Handle, Name_C, Index_C, Value_C); Check_Statement_State (This.Handle); end Set_Use_Vector_Integer; procedure Set_Use_Vector_Long_Long_Integer (This : in Statement; Name : in String; Index : in Vector_Index; Value : in DB_Long_Long_Integer) is procedure Soci_Set_Use_Long_Long_V (St : in Statement_Handle; Name : in Interfaces.C.char_array; Index : in Interfaces.C.int; Value : in Interfaces.Integer_64); pragma Import (C, Soci_Set_Use_Long_Long_V, "soci_set_use_long_long_v"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Index_C : constant Interfaces.C.int := Interfaces.C.int (Index); Value_C : constant Interfaces.Integer_64 := Interfaces.Integer_64 (Value); begin Soci_Set_Use_Long_Long_V (This.Handle, Name_C, Index_C, Value_C); Check_Statement_State (This.Handle); end Set_Use_Vector_Long_Long_Integer; procedure Set_Use_Vector_Long_Float (This : in Statement; Name : in String; Index : in Vector_Index; Value : in DB_Long_Float) is procedure Soci_Set_Use_Double_V (St : in Statement_Handle; Name : in Interfaces.C.char_array; Index : in Interfaces.C.int; Value : in Interfaces.C.double); pragma Import (C, Soci_Set_Use_Double_V, "soci_set_use_double_v"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Index_C : constant Interfaces.C.int := Interfaces.C.int (Index); Value_C : constant Interfaces.C.double := Interfaces.C.double (Value); begin Soci_Set_Use_Double_V (This.Handle, Name_C, Index_C, Value_C); Check_Statement_State (This.Handle); end Set_Use_Vector_Long_Float; procedure Set_Use_Vector_Time (This : in Statement; Name : in String; Index : in Vector_Index; Value : in Ada.Calendar.Time) is procedure Soci_Set_Use_Date_V (St : in Statement_Handle; Name : in Interfaces.C.char_array; Index : in Interfaces.C.int; Value : in Interfaces.C.char_array); pragma Import (C, Soci_Set_Use_Date_V, "soci_set_use_date_v"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Index_C : constant Interfaces.C.int := Interfaces.C.int (Index); Value_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Time_To_String (Value)); begin Soci_Set_Use_Date_V (This.Handle, Name_C, Index_C, Value_C); Check_Statement_State (This.Handle); end Set_Use_Vector_Time; function Get_Use_State (This : in Statement; Name : in String) return Data_State is function Soci_Get_Use_State (St : in Statement_Handle; Name : in Interfaces.C.char_array) return Interfaces.C.int; pragma Import (C, Soci_Get_Use_State, "soci_get_use_state"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Result : constant Interfaces.C.int := Soci_Get_Use_State (This.Handle, Name_C); use type Interfaces.C.int; begin Check_Statement_State (This.Handle); return Int_To_Data_State (Result); end Get_Use_State; function Get_Use_String (This : in Statement; Name : in String) return String is function Soci_Get_Use_String (St : in Statement_Handle; Name : in Interfaces.C.char_array) return Interfaces.C.Strings.chars_ptr; pragma Import (C, Soci_Get_Use_String, "soci_get_use_string"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Result : constant Interfaces.C.Strings.chars_ptr := Soci_Get_Use_String (This.Handle, Name_C); begin Check_Statement_State (This.Handle); return Interfaces.C.Strings.Value (Result); end Get_Use_String; function Get_Use_Integer (This : in Statement; Name : in String) return DB_Integer is function Soci_Get_Use_Int (St : in Statement_Handle; Name : in Interfaces.C.char_array) return Interfaces.C.int; pragma Import (C, Soci_Get_Use_Int, "soci_get_use_int"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Result : constant Interfaces.C.int := Soci_Get_Use_Int (This.Handle, Name_C); begin Check_Statement_State (This.Handle); return DB_Integer (Result); end Get_Use_Integer; function Get_Use_Long_Long_Integer (This : in Statement; Name : in String) return DB_Long_Long_Integer is function Soci_Get_Use_Long_Long (St : in Statement_Handle; Name : in Interfaces.C.char_array) return Interfaces.Integer_64; pragma Import (C, Soci_Get_Use_Long_Long, "soci_get_use_long_long"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Result : constant Interfaces.Integer_64 := Soci_Get_Use_Long_Long (This.Handle, Name_C); begin Check_Statement_State (This.Handle); return DB_Long_Long_Integer (Result); end Get_Use_Long_Long_Integer; function Get_Use_Long_Float (This : in Statement; Name : in String) return DB_Long_Float is function Soci_Get_Use_Double (St : in Statement_Handle; Name : in Interfaces.C.char_array) return Interfaces.C.double; pragma Import (C, Soci_Get_Use_Double, "soci_get_use_double"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Result : constant Interfaces.C.double := Soci_Get_Use_Double (This.Handle, Name_C); begin Check_Statement_State (This.Handle); return DB_Long_Float (Result); end Get_Use_Long_Float; function Get_Use_Time (This : in Statement; Name : in String) return Ada.Calendar.Time is function Soci_Get_Use_Date (St : in Statement_Handle; Name : in Interfaces.C.char_array) return Interfaces.C.Strings.chars_ptr; pragma Import (C, Soci_Get_Use_Date, "soci_get_use_date"); Name_C : constant Interfaces.C.char_array := Interfaces.C.To_C (Name); Result_C : constant Interfaces.C.Strings.chars_ptr := Soci_Get_Use_Date (This.Handle, Name_C); Result : constant String := Interfaces.C.Strings.Value (Result_C); begin Check_Statement_State (This.Handle); return String_To_Time (Result); end Get_Use_Time; end SOCI; soci-3.2.3/languages/ada/soci_postgresql.gpr0000644000000000000000000000036112511362240017573 0ustar rootrootproject SOCI_PostgreSQL is for Externally_Built use "true"; for Source_Dirs use (); for Library_Dir use "../../backends/postgresql"; for Library_Name use "soci_postgresql"; for Library_Kind use "static"; end SOCI_PostgreSQL; soci-3.2.3/languages/ada/soci.ads0000644000000000000000000003036212511362240015273 0ustar rootroot-- -- Thin wrapper for the simple interface of the SOCI database access library. -- -- Copyright (C) 2008-2011 Maciej Sobczak -- Distributed under the Boost Software License, Version 1.0. -- (See accompanying file LICENSE_1_0.txt or copy at -- http://www.boost.org/LICENSE_1_0.txt) with Ada.Calendar; with Interfaces.C; private with System; private with Ada.Finalization; package SOCI is -- -- General exception related to database and library usage. -- Database_Error : exception; -- -- Session. -- type Session is tagged limited private; not overriding function Make_Session (Connection_String : in String) return Session; not overriding procedure Open (This : in out Session; Connection_String : in String); not overriding procedure Close (This : in out Session); not overriding function Is_Open (This : in Session) return Boolean; -- Transaction management. not overriding procedure Start (This : in Session); not overriding procedure Commit (This : in Session); not overriding procedure Rollback (This : in Session); -- Immediate query execution. not overriding procedure Execute (This : in Session; Query : in String); -- -- Connection pool management. -- type Connection_Pool (Size : Positive) is tagged limited private; not overriding procedure Open (This : in out Connection_Pool; Position : in Positive; Connection_String : in String); not overriding procedure Close (This : in out Connection_Pool; Position : in Positive); not overriding procedure Lease (This : in out Connection_Pool; S : in out Session'Class); -- -- Statement. -- type Statement (<>) is tagged limited private; type Data_State is (Data_Null, Data_Not_Null); type Into_Position is private; type Vector_Index is new Natural; not overriding function Make_Statement (Sess : in Session'Class) return Statement; -- Statement preparation and execution. not overriding procedure Prepare (This : in Statement; Query : in String); not overriding procedure Execute (This : in Statement; With_Data_Exchange : in Boolean := False); not overriding function Execute (This : in Statement; With_Data_Exchange : in Boolean := False) return Boolean; not overriding function Fetch (This : in Statement) return Boolean; not overriding function Got_Data (This : in Statement) return Boolean; -- -- Data items handling. -- -- Database-specific types. -- These types are most likely identical to standard Integer, -- Long_Long_Integer and Long_Float, but are defined distinctly -- to avoid interfacing problems with other compilers. type DB_Integer is new Interfaces.C.int; type DB_Long_Long_Integer is new Interfaces.Integer_64; type DB_Long_Float is new Interfaces.C.double; -- Creation of single into elements. not overriding function Into_String (This : in Statement) return Into_Position; not overriding function Into_Integer (This : in Statement) return Into_Position; not overriding function Into_Long_Long_Integer (This : in Statement) return Into_Position; not overriding function Into_Long_Float (This : in Statement) return Into_Position; not overriding function Into_Time (This : in Statement) return Into_Position; -- Creation of vector into elements. not overriding function Into_Vector_String (This : in Statement) return Into_Position; not overriding function Into_Vector_Integer (This : in Statement) return Into_Position; not overriding function Into_Vector_Long_Long_Integer (This : in Statement) return Into_Position; not overriding function Into_Vector_Long_Float (This : in Statement) return Into_Position; not overriding function Into_Vector_Time (This : in Statement) return Into_Position; -- Inspection of single into elements. not overriding function Get_Into_State (This : in Statement; Position : in Into_Position) return Data_State; not overriding function Get_Into_String (This : in Statement; Position : in Into_Position) return String; not overriding function Get_Into_Integer (This : in Statement; Position : in Into_Position) return DB_Integer; not overriding function Get_Into_Long_Long_Integer (This : in Statement; Position : in Into_Position) return DB_Long_Long_Integer; not overriding function Get_Into_Long_Float (This : in Statement; Position : in Into_Position) return DB_Long_Float; not overriding function Get_Into_Time (This : in Statement; Position : in Into_Position) return Ada.Calendar.Time; -- Inspection of vector into elements. not overriding function Get_Into_Vectors_Size (This : in Statement) return Natural; not overriding function Into_Vectors_First_Index (This : in Statement) return Vector_Index; not overriding function Into_Vectors_Last_Index (This : in Statement) return Vector_Index; not overriding procedure Into_Vectors_Resize (This : in Statement; New_Size : in Natural); not overriding function Get_Into_Vector_State (This : in Statement; Position : in Into_Position; Index : in Vector_Index) return Data_State; not overriding function Get_Into_Vector_String (This : in Statement; Position : in Into_Position; Index : in Vector_Index) return String; not overriding function Get_Into_Vector_Integer (This : in Statement; Position : in Into_Position; Index : in Vector_Index) return DB_Integer; not overriding function Get_Into_Vector_Long_Long_Integer (This : in Statement; Position : in Into_Position; Index : in Vector_Index) return DB_Long_Long_Integer; not overriding function Get_Into_Vector_Long_Float (This : in Statement; Position : in Into_Position; Index : in Vector_Index) return DB_Long_Float; not overriding function Get_Into_Vector_Time (This : in Statement; Position : in Into_Position; Index : in Vector_Index) return Ada.Calendar.Time; -- Creation of single use elements. not overriding procedure Use_String (This : in Statement; Name : in String); not overriding procedure Use_Integer (This : in Statement; Name : in String); not overriding procedure Use_Long_Long_Integer (This : in Statement; Name : in String); not overriding procedure Use_Long_Float (This : in Statement; Name : in String); not overriding procedure Use_Time (This : in Statement; Name : in String); -- Creation of vector use elements. not overriding procedure Use_Vector_String (This : in Statement; Name : in String); not overriding procedure Use_Vector_Integer (This : in Statement; Name : in String); not overriding procedure Use_Vector_Long_Long_Integer (This : in Statement; Name : in String); not overriding procedure Use_Vector_Long_Float (This : in Statement; Name : in String); not overriding procedure Use_Vector_Time (This : in Statement; Name : in String); -- Modifiers for single use elements. not overriding procedure Set_Use_State (This : in Statement; Name : in String; State : in Data_State); not overriding procedure Set_Use_String (This : in Statement; Name : in String; Value : in String); not overriding procedure Set_Use_Integer (This : in Statement; Name : in String; Value : in DB_Integer); not overriding procedure Set_Use_Long_Long_Integer (This : in Statement; Name : in String; Value : in DB_Long_Long_Integer); not overriding procedure Set_Use_Long_Float (This : in Statement; Name : in String; Value : in DB_Long_Float); not overriding procedure Set_Use_Time (This : in Statement; Name : in String; Value : in Ada.Calendar.Time); -- Modifiers for vector use elements. not overriding function Get_Use_Vectors_Size (This : in Statement) return Natural; not overriding function Use_Vectors_First_Index (This : in Statement) return Vector_Index; not overriding function Use_Vectors_Last_Index (This : in Statement) return Vector_Index; not overriding procedure Use_Vectors_Resize (This : in Statement; New_Size : in Natural); not overriding procedure Set_Use_Vector_State (This : in Statement; Name : in String; Index : in Vector_Index; State : in Data_State); not overriding procedure Set_Use_Vector_String (This : in Statement; Name : in String; Index : in Vector_Index; Value : in String); not overriding procedure Set_Use_Vector_Integer (This : in Statement; Name : in String; Index : in Vector_Index; Value : in DB_Integer); not overriding procedure Set_Use_Vector_Long_Long_Integer (This : in Statement; Name : in String; Index : in Vector_Index; Value : in DB_Long_Long_Integer); not overriding procedure Set_Use_Vector_Long_Float (This : in Statement; Name : in String; Index : in Vector_Index; Value : in DB_Long_Float); not overriding procedure Set_Use_Vector_Time (This : in Statement; Name : in String; Index : in Vector_Index; Value : in Ada.Calendar.Time); -- Inspection of single use elements. -- -- Note: Use elements can be modified by the database if they -- are bound to out and inout parameters of stored procedures -- (although this is not supported by all database backends). -- This feature is available only for single use elements. not overriding function Get_Use_State (This : in Statement; Name : in String) return Data_State; not overriding function Get_Use_String (This : in Statement; Name : in String) return String; not overriding function Get_Use_Integer (This : in Statement; Name : in String) return DB_Integer; not overriding function Get_Use_Long_Long_Integer (This : in Statement; Name : in String) return DB_Long_Long_Integer; not overriding function Get_Use_Long_Float (This : in Statement; Name : in String) return DB_Long_Float; not overriding function Get_Use_Time (This : in Statement; Name : in String) return Ada.Calendar.Time; private -- Connection pool and supporting types. type Connection_Array is array (Positive range <>) of Session; type Used_Array is array (Positive range <>) of Boolean; -- Protected state for the connection pool. protected type Connection_Pool_PS (Size : Positive) is procedure Open (Position : in Positive; Connection_String : in String); procedure Close (Position : in Positive); entry Lease (S : in out Session'Class); procedure Give_Back (Position : in Positive); private Connections : Connection_Array (1 .. Size); Is_Used : Used_Array (1 .. Size) := (others => False); Available : Boolean := True; end Connection_Pool_PS; type Connection_Pool_PS_Ptr is access all Connection_Pool_PS; type Connection_Pool (Size : Positive) is tagged limited record Pool : aliased Connection_Pool_PS (Size); end record; -- Session and supporting types. type Session_Handle is new System.Address; Null_Session_Handle : constant Session_Handle := Session_Handle (System.Null_Address); type Session is new Ada.Finalization.Limited_Controlled with record Handle : Session_Handle; Initialized : Boolean := False; Belongs_To_Pool : Boolean := False; Pool : Connection_Pool_PS_Ptr; Position_In_Pool : Positive; end record; overriding procedure Finalize (This : in out Session); -- Statement and supporting types. type Statement_Handle is new System.Address; Null_Statement_Handle : constant Statement_Handle := Statement_Handle (System.Null_Address); type Statement is new Ada.Finalization.Limited_Controlled with record Handle : Statement_Handle; Initialized : Boolean := False; end record; overriding procedure Finalize (This : in out Statement); type Into_Position is new Natural; end SOCI; soci-3.2.3/languages/ada/soci-postgresql.ads0000644000000000000000000000100112511362240017460 0ustar rootroot-- Copyright (C) 2008-2011 Maciej Sobczak -- Distributed under the Boost Software License, Version 1.0. -- (See accompanying file LICENSE_1_0.txt or copy at -- http://www.boost.org/LICENSE_1_0.txt) package SOCI.PostgreSQL is -- -- Registers the PostgreSQL backend so that it is ready for use -- by the dynamic backend loader. -- procedure Register_Factory_PostgreSQL; pragma Import (C, Register_Factory_PostgreSQL, "register_factory_postgresql"); end SOCI.PostgreSQL; soci-3.2.3/languages/ada/soci_ada.gpr0000644000000000000000000000051612511362240016117 0ustar rootrootwith "std_cpp.gpr"; with "soci_core.gpr"; project SOCI_Ada is for Source_Dirs use ("."); for Object_Dir use "."; for Library_Name use "soci_ada"; for Library_Dir use "lib"; for Library_Kind use "static"; package Compiler is for Default_Switches ("Ada") use ("-gnat05", "-O2"); end Compiler; end SOCI_Ada; soci-3.2.3/languages/ada/soci-mysql.ads0000644000000000000000000000074312511362240016436 0ustar rootroot-- Copyright (C) 2008-2011 Maciej Sobczak -- Distributed under the Boost Software License, Version 1.0. -- (See accompanying file LICENSE_1_0.txt or copy at -- http://www.boost.org/LICENSE_1_0.txt) package SOCI.MySQL is -- -- Registers the MySQL backend so that it is ready for use -- by the dynamic backend loader. -- procedure Register_Factory_MySQL; pragma Import (C, Register_Factory_MySQL, "register_factory_mysql"); end SOCI.MySQL; soci-3.2.3/languages/ada/soci_core.gpr0000644000000000000000000000031712511362240016321 0ustar rootrootproject SOCI_Core is for Externally_Built use "true"; for Source_Dirs use (); for Library_Dir use "../../core"; for Library_Name use "soci_core"; for Library_Kind use "static"; end SOCI_Core; soci-3.2.3/languages/ada/test/0000755000000000000000000000000012511362240014620 5ustar rootrootsoci-3.2.3/languages/ada/test/postgresql_test.gpr0000644000000000000000000000042612511362240020576 0ustar rootrootwith "../soci_ada.gpr"; with "../soci_postgresql.gpr"; with "../postgresql_client.gpr"; project PostgreSQL_Test is for Main use ("postgresql_test"); package Compiler is for Default_Switches ("Ada") use ("-gnat05", "-gnata"); end Compiler; end PostgreSQL_Test; soci-3.2.3/languages/ada/test/postgresql_test.adb0000644000000000000000000005640512511362240020544 0ustar rootrootwith SOCI; with SOCI.PostgreSQL; with Ada.Text_IO; with Ada.Calendar; with Ada.Exceptions; with Ada.Numerics.Discrete_Random; with Ada.Command_Line; procedure PostgreSQL_Test is procedure Test_1 (Connection_String : in String) is begin Ada.Text_IO.Put_Line ("testing basic constructor function"); declare S : SOCI.Session := SOCI.Make_Session (Connection_String); begin null; end; exception when E : SOCI.Database_Error => Ada.Text_IO.Put_Line ("Database_Error: "); Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Message (E)); end Test_1; procedure Test_2 (Connection_String : in String) is S : SOCI.Session; begin Ada.Text_IO.Put_Line ("testing open/close"); S.Close; S.Open (Connection_String); S.Close; end Test_2; procedure Test_3 (Connection_String : in String) is begin Ada.Text_IO.Put_Line ("testing empty start/commit"); declare S : SOCI.Session := SOCI.Make_Session (Connection_String); begin S.Start; S.Commit; end; end Test_3; procedure Test_4 (Connection_String : in String) is begin Ada.Text_IO.Put_Line ("testing simple statements"); declare SQL : SOCI.Session := SOCI.Make_Session (Connection_String); begin SQL.Execute ("create table ada_test ( i integer )"); SQL.Execute ("drop table ada_test"); end; end Test_4; procedure Test_5 (Connection_String : in String) is begin Ada.Text_IO.Put_Line ("testing independent statements"); declare SQL : SOCI.Session := SOCI.Make_Session (Connection_String); St_1 : SOCI.Statement := SOCI.Make_Statement (SQL); St_2 : SOCI.Statement := SOCI.Make_Statement (SQL); begin St_1.Prepare ("create table ada_test ( i integer )"); St_2.Prepare ("drop table ada_test"); St_1.Execute; St_2.Execute; end; end Test_5; procedure Test_6 (Connection_String : in String) is begin Ada.Text_IO.Put_Line ("testing data types and into elements"); declare SQL : SOCI.Session := SOCI.Make_Session (Connection_String); begin declare St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos : SOCI.Into_Position; begin Pos := St.Into_String; St.Prepare ("select 'Hello'"); St.Execute (True); pragma Assert (St.Get_Into_String (Pos) = "Hello"); end; declare St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos : SOCI.Into_Position; Value : SOCI.DB_Integer; use type SOCI.DB_Integer; begin Pos := St.Into_Integer; St.Prepare ("select 123"); St.Execute (True); Value := St.Get_Into_Integer (Pos); pragma Assert (Value = 123); end; declare St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos : SOCI.Into_Position; Value : SOCI.DB_Long_Long_Integer; use type SOCI.DB_Long_Long_Integer; begin Pos := St.Into_Long_Long_Integer; St.Prepare ("select 10000000000"); St.Execute (True); Value := St.Get_Into_Long_Long_Integer (Pos); pragma Assert (Value = 10_000_000_000); end; declare St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos : SOCI.Into_Position; Value : SOCI.DB_Long_Float; use type SOCI.DB_Long_Float; begin Pos := St.Into_Long_Float; St.Prepare ("select 3.625"); St.Execute (True); Value := St.Get_Into_Long_Float (Pos); pragma Assert (Value = SOCI.DB_Long_Float (3.625)); end; declare St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos : SOCI.Into_Position; Value : Ada.Calendar.Time; begin Pos := St.Into_Time; St.Prepare ("select timestamp '2008-06-30 21:01:02'"); St.Execute (True); Value := St.Get_Into_Time (Pos); pragma Assert (Ada.Calendar.Year (Value) = 2008); pragma Assert (Ada.Calendar.Month (Value) = 6); pragma Assert (Ada.Calendar.Day (Value) = 30); pragma Assert (Ada.Calendar.Seconds (Value) = Ada.Calendar.Day_Duration (21 * 3_600 + 1 * 60 + 2)); end; end; end Test_6; procedure Test_7 (Connection_String : in String) is begin Ada.Text_IO.Put_Line ("testing types with into vectors"); declare SQL : SOCI.Session := SOCI.Make_Session (Connection_String); St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos_Id : SOCI.Into_Position; Pos_Str : SOCI.Into_Position; Pos_LL : SOCI.Into_Position; Pos_LF : SOCI.Into_Position; Pos_TM : SOCI.Into_Position; use type SOCI.Data_State; use type Ada.Calendar.Time; use type SOCI.DB_Integer; use type SOCI.DB_Long_Long_Integer; use type SOCI.DB_Long_Float; begin SQL.Execute ("create table soci_test (" & " id integer," & " str varchar (20)," & " ll bigint," & " lf double precision," & " tm timestamp" & ")"); SQL.Execute ("insert into soci_test (id, str, ll, lf, tm)" & " values (1, 'abc', 10000000000, 3.0, timestamp '2008-06-30 21:01:02')"); SQL.Execute ("insert into soci_test (id, str, ll, lf, tm)" & " values (2, 'xyz', -10000000001, -3.125, timestamp '2008-07-01 21:01:03')"); SQL.Execute ("insert into soci_test (id, str, ll, lf, tm)" & " values (3, null, null, null, null)"); Pos_Id := St.Into_Vector_Integer; Pos_Str := St.Into_Vector_String; Pos_LL := St.Into_Vector_Long_Long_Integer; Pos_LF := St.Into_Vector_Long_Float; Pos_TM := St.Into_Vector_Time; St.Into_Vectors_Resize (10); -- arbitrary batch size St.Prepare ("select id, str, ll, lf, tm from soci_test order by id"); St.Execute (True); pragma Assert (St.Get_Into_Vectors_Size = 3); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 0) = 1); pragma Assert (St.Get_Into_Vector_State (Pos_Str, 0) = SOCI.Data_Not_Null); pragma Assert (St.Get_Into_Vector_String (Pos_Str, 0) = "abc"); pragma Assert (St.Get_Into_Vector_Long_Long_Integer (Pos_LL, 0) = 10_000_000_000); pragma Assert (St.Get_Into_Vector_Long_Float (Pos_LF, 0) = SOCI.DB_Long_Float (3.0)); pragma Assert (St.Get_Into_Vector_Time (Pos_TM, 0) = Ada.Calendar.Time_Of (2008, 6, 30, Duration (21 * 3_600 + 1 * 60 + 2))); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 1) = 2); pragma Assert (St.Get_Into_Vector_State (Pos_Str, 1) = SOCI.Data_Not_Null); pragma Assert (St.Get_Into_Vector_String (Pos_Str, 1) = "xyz"); pragma Assert (St.Get_Into_Vector_Long_Long_Integer (Pos_LL, 1) = -10_000_000_001); pragma Assert (St.Get_Into_Vector_Long_Float (Pos_LF, 1) = SOCI.DB_Long_Float (-3.125)); pragma Assert (St.Get_Into_Vector_Time (Pos_TM, 1) = Ada.Calendar.Time_Of (2008, 7, 1, Duration (21 * 3_600 + 1 * 60 + 3))); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 2) = 3); pragma Assert (St.Get_Into_Vector_State (Pos_Str, 2) = SOCI.Data_Null); pragma Assert (St.Get_Into_Vector_State (Pos_LL, 2) = SOCI.Data_Null); pragma Assert (St.Get_Into_Vector_State (Pos_LF, 2) = SOCI.Data_Null); pragma Assert (St.Get_Into_Vector_State (Pos_TM, 2) = SOCI.Data_Null); SQL.Execute ("drop table soci_test"); end; end Test_7; procedure Test_8 (Connection_String : in String) is begin Ada.Text_IO.Put_Line ("testing multi-batch operation with into vectors"); declare SQL : SOCI.Session := SOCI.Make_Session (Connection_String); St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos_Id : SOCI.Into_Position; Got_Data : Boolean; use type SOCI.DB_Integer; begin SQL.Execute ("create table soci_test (" & " id integer" & ")"); SQL.Execute ("insert into soci_test (id) values (1)"); SQL.Execute ("insert into soci_test (id) values (2)"); SQL.Execute ("insert into soci_test (id) values (3)"); SQL.Execute ("insert into soci_test (id) values (4)"); SQL.Execute ("insert into soci_test (id) values (5)"); SQL.Execute ("insert into soci_test (id) values (6)"); SQL.Execute ("insert into soci_test (id) values (7)"); SQL.Execute ("insert into soci_test (id) values (8)"); SQL.Execute ("insert into soci_test (id) values (9)"); SQL.Execute ("insert into soci_test (id) values (10)"); Pos_Id := St.Into_Vector_Integer; St.Into_Vectors_Resize (4); -- batch of 4 elements St.Prepare ("select id from soci_test order by id"); St.Execute; Got_Data := St.Fetch; pragma Assert (Got_Data); pragma Assert (St.Get_Into_Vectors_Size = 4); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 0) = 1); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 1) = 2); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 2) = 3); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 3) = 4); Got_Data := St.Fetch; pragma Assert (Got_Data); pragma Assert (St.Get_Into_Vectors_Size = 4); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 0) = 5); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 1) = 6); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 2) = 7); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 3) = 8); Got_Data := St.Fetch; pragma Assert (Got_Data); pragma Assert (St.Get_Into_Vectors_Size = 2); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 0) = 9); pragma Assert (St.Get_Into_Vector_Integer (Pos_Id, 1) = 10); Got_Data := St.Fetch; pragma Assert (not Got_Data); pragma Assert (St.Get_Into_Vectors_Size = 0); SQL.Execute ("drop table soci_test"); end; end Test_8; procedure Test_9 (Connection_String : in String) is begin Ada.Text_IO.Put_Line ("testing data types and use elements"); declare SQL : SOCI.Session := SOCI.Make_Session (Connection_String); use type SOCI.DB_Integer; use type SOCI.DB_Long_Long_Integer; use type SOCI.DB_Long_Float; begin declare St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos : SOCI.Into_Position; begin St.Use_String ("value"); St.Set_Use_String ("value", "123"); Pos := St.Into_Integer; St.Prepare ("select cast(:value as integer)"); St.Execute (True); pragma Assert (St.Get_Into_Integer (Pos) = 123); end; declare St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos : SOCI.Into_Position; begin St.Use_Integer ("value"); St.Set_Use_Integer ("value", 123); Pos := St.Into_String; St.Prepare ("select cast(:value as text)"); St.Execute (True); pragma Assert (St.Get_Into_String (Pos) = "123"); end; declare St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos : SOCI.Into_Position; begin St.Use_Long_Long_Integer ("value"); St.Set_Use_Long_Long_Integer ("value", 10_000_000_000); Pos := St.Into_String; St.Prepare ("select cast(:value as text)"); St.Execute (True); pragma Assert (St.Get_Into_String (Pos) = "10000000000"); end; declare St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos : SOCI.Into_Position; begin St.Use_Long_Float ("value"); St.Set_Use_Long_Float ("value", SOCI.DB_Long_Float (5.625)); Pos := St.Into_String; St.Prepare ("select cast(:value as text)"); St.Execute (True); pragma Assert (St.Get_Into_String (Pos) = "5.625"); end; declare St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos : SOCI.Into_Position; begin St.Use_Time ("value"); St.Set_Use_Time ("value", Ada.Calendar.Time_Of (2008, 7, 1, Ada.Calendar.Day_Duration (3723))); Pos := St.Into_String; St.Prepare ("select cast(:value as text)"); St.Execute (True); pragma Assert (St.Get_Into_String (Pos) = "2008-07-01 01:02:03"); end; declare St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos : SOCI.Into_Position; use type SOCI.Data_State; begin St.Use_Integer ("value"); St.Set_Use_State ("value", SOCI.Data_Null); Pos := St.Into_Integer; St.Prepare ("select cast(:value as integer)"); St.Execute (True); pragma Assert (St.Get_Into_State (Pos) = SOCI.Data_Null); end; end; end Test_9; procedure Test_10 (Connection_String : in String) is begin Ada.Text_IO.Put_Line ("testing vector use elements and row traversal with single into elements"); declare SQL : SOCI.Session := SOCI.Make_Session (Connection_String); Time_1 : constant Ada.Calendar.Time := Ada.Calendar.Time_Of (2008, 7, 1, Ada.Calendar.Day_Duration (1)); Time_2 : constant Ada.Calendar.Time := Ada.Calendar.Time_Of (2008, 7, 2, Ada.Calendar.Day_Duration (2)); Time_3 : constant Ada.Calendar.Time := Ada.Calendar.Time_Of (2008, 7, 3, Ada.Calendar.Day_Duration (3)); Time_4 : constant Ada.Calendar.Time := Ada.Calendar.Time_Of (2008, 7, 4, Ada.Calendar.Day_Duration (4)); Time_5 : constant Ada.Calendar.Time := Ada.Calendar.Time_Of (2008, 7, 5, Ada.Calendar.Day_Duration (5)); begin SQL.Execute ("create table soci_test (" & " id integer," & " str varchar (20)," & " ll bigint," & " lf double precision," & " tm timestamp" & ")"); declare St : SOCI.Statement := SOCI.Make_Statement (SQL); begin St.Use_Vector_Integer ("id"); St.Use_Vector_String ("str"); St.Use_Vector_Long_Long_Integer ("ll"); St.Use_Vector_Long_Float ("lf"); St.Use_Vector_Time ("tm"); St.Use_Vectors_Resize (6); St.Set_Use_Vector_Integer ("id", 0, 1); St.Set_Use_Vector_Integer ("id", 1, 2); St.Set_Use_Vector_Integer ("id", 2, 3); St.Set_Use_Vector_Integer ("id", 3, 4); St.Set_Use_Vector_Integer ("id", 4, 5); St.Set_Use_Vector_Integer ("id", 5, 6); St.Set_Use_Vector_String ("str", 0, "abc"); St.Set_Use_Vector_String ("str", 1, "def"); St.Set_Use_Vector_String ("str", 2, "ghi"); St.Set_Use_Vector_String ("str", 3, "jklm"); St.Set_Use_Vector_String ("str", 4, "no"); St.Set_Use_Vector_State ("str", 5, SOCI.Data_Null); St.Set_Use_Vector_Long_Long_Integer ("ll", 0, 10_000_000_000); St.Set_Use_Vector_Long_Long_Integer ("ll", 1, 10_000_000_001); St.Set_Use_Vector_Long_Long_Integer ("ll", 2, 10_000_000_002); St.Set_Use_Vector_Long_Long_Integer ("ll", 3, 10_000_000_003); St.Set_Use_Vector_Long_Long_Integer ("ll", 4, 10_000_000_004); St.Set_Use_Vector_State ("ll", 5, SOCI.Data_Null); St.Set_Use_Vector_Long_Float ("lf", 0, SOCI.DB_Long_Float (0.0)); St.Set_Use_Vector_Long_Float ("lf", 1, SOCI.DB_Long_Float (0.125)); St.Set_Use_Vector_Long_Float ("lf", 2, SOCI.DB_Long_Float (0.25)); St.Set_Use_Vector_Long_Float ("lf", 3, SOCI.DB_Long_Float (0.5)); St.Set_Use_Vector_Long_Float ("lf", 4, SOCI.DB_Long_Float (0.625)); St.Set_Use_Vector_State ("lf", 5, SOCI.Data_Null); St.Set_Use_Vector_Time ("tm", 0, Time_1); St.Set_Use_Vector_Time ("tm", 1, Time_2); St.Set_Use_Vector_Time ("tm", 2, Time_3); St.Set_Use_Vector_Time ("tm", 3, Time_4); St.Set_Use_Vector_Time ("tm", 4, Time_5); St.Set_Use_Vector_State ("tm", 5, SOCI.Data_Null); St.Prepare ("insert into soci_test (id, str, ll, lf, tm)" & " values (:id, :str, :ll, :lf, :tm)"); St.Execute (True); end; declare St : SOCI.Statement := SOCI.Make_Statement (SQL); Pos_Id : SOCI.Into_Position; Pos_Str : SOCI.Into_Position; Pos_LL : SOCI.Into_Position; Pos_LF : SOCI.Into_Position; Pos_TM : SOCI.Into_Position; Got_Data : Boolean; use type Ada.Calendar.Time; use type SOCI.Data_State; use type SOCI.DB_Integer; use type SOCI.DB_Long_Long_Integer; use type SOCI.DB_Long_Float; begin Pos_Id := St.Into_Integer; Pos_Str := St.Into_String; Pos_LL := St.Into_Long_Long_Integer; Pos_LF := St.Into_Long_Float; Pos_TM := St.Into_Time; St.Prepare ("select id, str, ll, lf, tm from soci_test order by id"); St.Execute; Got_Data := St.Fetch; pragma Assert (Got_Data); pragma Assert (St.Get_Into_Integer (Pos_Id) = 1); pragma Assert (St.Get_Into_String (Pos_Str) = "abc"); pragma Assert (St.Get_Into_Long_Long_Integer (Pos_LL) = 10_000_000_000); pragma Assert (St.Get_Into_Long_Float (Pos_LF) = SOCI.DB_Long_Float (0.0)); pragma Assert (St.Get_Into_Time (Pos_TM) = Time_1); Got_Data := St.Fetch; pragma Assert (Got_Data); pragma Assert (St.Get_Into_Integer (Pos_Id) = 2); pragma Assert (St.Get_Into_String (Pos_Str) = "def"); pragma Assert (St.Get_Into_Long_Long_Integer (Pos_LL) = 10_000_000_001); pragma Assert (St.Get_Into_Long_Float (Pos_LF) = SOCI.DB_Long_Float (0.125)); pragma Assert (St.Get_Into_Time (Pos_TM) = Time_2); Got_Data := St.Fetch; pragma Assert (Got_Data); pragma Assert (St.Get_Into_Integer (Pos_Id) = 3); pragma Assert (St.Get_Into_String (Pos_Str) = "ghi"); pragma Assert (St.Get_Into_Long_Long_Integer (Pos_LL) = 10_000_000_002); pragma Assert (St.Get_Into_Long_Float (Pos_LF) = SOCI.DB_Long_Float (0.25)); pragma Assert (St.Get_Into_Time (Pos_TM) = Time_3); Got_Data := St.Fetch; pragma Assert (Got_Data); pragma Assert (St.Get_Into_Integer (Pos_Id) = 4); pragma Assert (St.Get_Into_String (Pos_Str) = "jklm"); pragma Assert (St.Get_Into_Long_Long_Integer (Pos_LL) = 10_000_000_003); pragma Assert (St.Get_Into_Long_Float (Pos_LF) = SOCI.DB_Long_Float (0.5)); pragma Assert (St.Get_Into_Time (Pos_TM) = Time_4); Got_Data := St.Fetch; pragma Assert (Got_Data); pragma Assert (St.Get_Into_Integer (Pos_Id) = 5); pragma Assert (St.Get_Into_String (Pos_Str) = "no"); pragma Assert (St.Get_Into_Long_Long_Integer (Pos_LL) = 10_000_000_004); pragma Assert (St.Get_Into_Long_Float (Pos_LF) = SOCI.DB_Long_Float (0.625)); pragma Assert (St.Get_Into_Time (Pos_TM) = Time_5); Got_Data := St.Fetch; pragma Assert (Got_Data); pragma Assert (St.Get_Into_State (Pos_Id) = SOCI.Data_Not_Null); pragma Assert (St.Get_Into_Integer (Pos_Id) = 6); pragma Assert (St.Get_Into_State (Pos_Str) = SOCI.Data_Null); pragma Assert (St.Get_Into_State (Pos_LL) = SOCI.Data_Null); pragma Assert (St.Get_Into_State (Pos_LF) = SOCI.Data_Null); pragma Assert (St.Get_Into_State (Pos_TM) = SOCI.Data_Null); Got_Data := St.Fetch; pragma Assert (not Got_Data); end; SQL.Execute ("drop table soci_test"); end; end Test_10; procedure Test_11 (Connection_String : in String) is -- test parameters: Pool_Size : constant := 3; Number_Of_Tasks : constant := 10; Iterations_Per_Task : constant := 1000; type Small_Integer is mod 20; package My_Random is new Ada.Numerics.Discrete_Random (Small_Integer); Rand : My_Random.Generator; Pool : SOCI.Connection_Pool (Pool_Size); begin Ada.Text_IO.Put_Line ("testing connection pool"); My_Random.Reset (Rand); for I in 1 .. Pool_Size loop Pool.Open (I, Connection_String); end loop; declare SQL : SOCI.Session := SOCI.Make_Session (Connection_String); begin SQL.Execute ("create table soci_test ( id integer )"); end; declare task type Worker; task body Worker is begin for I in 1 .. Iterations_Per_Task loop declare SQL : SOCI.Session; V : Small_Integer; begin Pool.Lease (SQL); V := My_Random.Random (Rand); SQL.Execute ("insert into soci_test (id) values (" & Small_Integer'Image (V) & ")"); end; end loop; exception when others => Ada.Text_IO.Put_Line ("An exception occured in the worker task."); end Worker; W : array (1 .. Number_Of_Tasks) of Worker; begin Ada.Text_IO.Put_Line ("--> waiting for the tasks to complete (might take a while)"); end; declare SQL : SOCI.Session := SOCI.Make_Session (Connection_String); begin SQL.Execute ("drop table soci_test"); end; end Test_11; begin if Ada.Command_Line.Argument_Count /= 1 then Ada.Text_IO.Put_Line ("Expecting one argument: connection string"); return; end if; declare Connection_String : String := Ada.Command_Line.Argument (1); begin Ada.Text_IO.Put_Line ("testing with " & Connection_String); SOCI.PostgreSQL.Register_Factory_PostgreSQL; Test_1 (Connection_String); Test_2 (Connection_String); Test_3 (Connection_String); Test_4 (Connection_String); Test_5 (Connection_String); Test_6 (Connection_String); Test_7 (Connection_String); Test_8 (Connection_String); Test_9 (Connection_String); Test_10 (Connection_String); Test_11 (Connection_String); end; end PostgreSQL_Test; soci-3.2.3/languages/ada/std_cpp.gpr0000644000000000000000000000027712511362240016015 0ustar rootrootproject Std_Cpp is for Externally_Built use "true"; for Source_Dirs use (); for Library_Dir use "."; for Library_Name use "stdc++"; for Library_Kind use "static"; end Std_Cpp; soci-3.2.3/core/0000755000000000000000000000000012511401146012075 5ustar rootrootsoci-3.2.3/core/procedure.cpp0000644000000000000000000000150612511361676014610 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "procedure.h" #include "statement.h" #include "prepare-temp-type.h" using namespace soci; using namespace soci::details; procedure_impl::procedure_impl(prepare_temp_type const & prep) : statement_impl(prep.get_prepare_info()->session_), refCount_(1) { ref_counted_prepare_info * prepInfo = prep.get_prepare_info(); // take all bind/define info intos_.swap(prepInfo->intos_); uses_.swap(prepInfo->uses_); // allocate handle alloc(); // prepare the statement prepare(rewrite_for_procedure_call(prepInfo->get_query())); define_and_bind(); } soci-3.2.3/core/error.h0000644000000000000000000000102012511362240013371 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_ERROR_H_INCLUDED #define SOCI_ERROR_H_INCLUDED #include "soci-config.h" // std #include #include namespace soci { class SOCI_DECL soci_error : public std::runtime_error { public: explicit soci_error(std::string const & msg); }; } // namespace soci #endif // SOCI_ERROR_H_INCLUDED soci-3.2.3/core/use-type.cpp0000644000000000000000000000442312511361676014374 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "use-type.h" #include "statement.h" using namespace soci; using namespace soci::details; standard_use_type::~standard_use_type() { delete backEnd_; } void standard_use_type::bind(statement_impl & st, int & position) { if (backEnd_ == NULL) { backEnd_ = st.make_use_type_backend(); } if (name_.empty()) { backEnd_->bind_by_pos(position, data_, type_, readOnly_); } else { backEnd_->bind_by_name(name_, data_, type_, readOnly_); } } void standard_use_type::pre_use() { // Handle IN direction of parameters of SQL statements and procedures convert_to_base(); backEnd_->pre_use(ind_); } void standard_use_type::post_use(bool gotData) { // Handle OUT direction of IN/OUT parameters of stored procedures backEnd_->post_use(gotData, ind_); convert_from_base(); // IMPORTANT: // This treatment of input ("use") parameter as output data sink may be // confusing, but it is necessary to store OUT data back in the same // object as IN, of IN/OUT parameter. // As there is no symmetry for IN/OUT in SQL and there are no OUT/IN // we do not perform convert_to_base() for output ("into") parameter. // See conversion_use_type::convert_from_base() for more details. } void standard_use_type::clean_up() { if (backEnd_ != NULL) { backEnd_->clean_up(); } } vector_use_type::~vector_use_type() { delete backEnd_; } void vector_use_type::bind(statement_impl & st, int & position) { if (backEnd_ == NULL) { backEnd_ = st.make_vector_use_type_backend(); } if (name_.empty()) { backEnd_->bind_by_pos(position, data_, type_); } else { backEnd_->bind_by_name(name_, data_, type_); } } void vector_use_type::pre_use() { convert_to_base(); backEnd_->pre_use(ind_ ? &ind_->at(0) : NULL); } std::size_t vector_use_type::size() const { return backEnd_->size(); } void vector_use_type::clean_up() { if (backEnd_ != NULL) { backEnd_->clean_up(); } } soci-3.2.3/core/soci-platform.h0000644000000000000000000000252112511401146015025 0ustar rootroot// // Copyright (C) 2006-2008 Mateusz Loskot // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_PLATFORM_H_INCLUDED #define SOCI_PLATFORM_H_INCLUDED #if defined(_MSC_VER) || defined(__MINGW32__) #define LL_FMT_FLAGS "I64" #else #define LL_FMT_FLAGS "ll" #endif // Portability hacks for Microsoft Visual C++ compiler #ifdef _MSC_VER #include // Define if you have the vsnprintf variants. #if _MSC_VER < 1500 # define vsnprintf _vsnprintf #endif // Define if you have the snprintf variants. #define snprintf _snprintf // Define if you have the strtoll and strtoull variants. #if _MSC_VER < 1300 # error "Visual C++ versions prior 1300 don't support _strtoi64 and _strtoui64" #elif _MSC_VER >= 1300 && _MSC_VER < 1800 namespace std { inline long long strtoll(char const* str, char** str_end, int base) { return _strtoi64(str, str_end, base); } inline unsigned long long strtoull(char const* str, char** str_end, int base) { return _strtoui64(str, str_end, base); } } #endif // _MSC_VER < 1800 #endif // _MSC_VER #if defined(__CYGWIN__) || defined(__MINGW32__) #include namespace std { using ::strtoll; using ::strtoull; } #endif #endif // SOCI_PLATFORM_H_INCLUDED soci-3.2.3/core/prepare-temp-type.h0000644000000000000000000000265412511401144015633 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_PREPARE_TEMP_TYPE_INCLUDED #define SOCI_PREPARE_TEMP_TYPE_INCLUDED #include "into-type.h" #include "use-type.h" #include "use.h" #include "ref-counted-prepare-info.h" namespace soci { namespace details { // this needs to be lightweight and copyable class SOCI_DECL prepare_temp_type { public: prepare_temp_type(session &); prepare_temp_type(prepare_temp_type const &); prepare_temp_type & operator=(prepare_temp_type const &); ~prepare_temp_type(); template prepare_temp_type & operator<<(T const & t) { rcpi_->accumulate(t); return *this; } prepare_temp_type & operator,(into_type_ptr const & i); template prepare_temp_type &operator,(into_container const &ic) { rcpi_->exchange(ic); return *this; } template prepare_temp_type &operator,(use_container const &uc) { rcpi_->exchange(uc); return *this; } ref_counted_prepare_info * get_prepare_info() const { return rcpi_; } private: ref_counted_prepare_info * rcpi_; }; } // namespace details } // namespace soci #endif soci-3.2.3/core/values.cpp0000644000000000000000000000263112511361676014117 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "values.h" #include "row.h" #include #include #include #include using namespace soci; using namespace soci::details; indicator values::get_indicator(std::size_t pos) const { if (row_) { return row_->get_indicator(pos); } else { return *indicators_[pos]; } } indicator values::get_indicator(std::string const& name) const { if (row_) { return row_->get_indicator(name); } else { std::map::const_iterator it = index_.find(name); if (it == index_.end()) { std::ostringstream msg; msg << "Column '" << name << "' not found"; throw soci_error(msg.str()); } return *indicators_[it->second]; } } column_properties const& values::get_properties(std::size_t pos) const { if (row_) { return row_->get_properties(pos); } throw soci_error("Rowset is empty"); } column_properties const& values::get_properties(std::string const& name) const { if (row_) { return row_->get_properties(name); } throw soci_error("Rowset is empty"); } soci-3.2.3/core/ref-counted-statement.h0000644000000000000000000000365512511401146016474 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_REF_COUNTED_STATEMENT_H_INCLUDED #define SOCI_REF_COUNTED_STATEMENT_H_INCLUDED #include "statement.h" #include "into-type.h" #include "use-type.h" // std #include namespace soci { namespace details { // this class is a base for both "once" and "prepare" statements class SOCI_DECL ref_counted_statement_base { public: ref_counted_statement_base(session& s); virtual ~ref_counted_statement_base() {} virtual void final_action() = 0; void inc_ref() { ++refCount_; } void dec_ref() { if (--refCount_ == 0) { try { final_action(); } catch (...) { delete this; throw; } delete this; } } template void accumulate(T const & t) { get_query_stream() << t; } protected: // this function allows to break the circular dependenc // between session and this class std::ostringstream & get_query_stream(); int refCount_; session & session_; private: // noncopyable ref_counted_statement_base(ref_counted_statement_base const&); ref_counted_statement_base& operator=(ref_counted_statement_base const&); }; // this class is supposed to be a vehicle for the "once" statements // it executes the whole statement in its destructor class ref_counted_statement : public ref_counted_statement_base { public: ref_counted_statement(session & s) : ref_counted_statement_base(s), st_(s) {} virtual void final_action(); template void exchange(T &t) { st_.exchange(t); } private: statement st_; }; } // namespace details } // namespace soci #endif soci-3.2.3/core/connection-parameters.h0000644000000000000000000000374212511362240016555 0ustar rootroot// // Copyright (C) 2013 Vadim Zeitlin // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_CONNECTION_PARAMETERS_H_INCLUDED #define SOCI_CONNECTION_PARAMETERS_H_INCLUDED #include "soci-config.h" #include #include namespace soci { class backend_factory; // Simple container for the information used when opening a session. class SOCI_DECL connection_parameters { public: connection_parameters(); connection_parameters(backend_factory const & factory, std::string const & connectString); connection_parameters(std::string const & backendName, std::string const & connectString); explicit connection_parameters(std::string const & fullConnectString); // Default copy ctor, assignment operator and dtor are all OK for us. // Retrieve the backend and the connection strings specified in the ctor. backend_factory const * get_factory() const { return factory_; } std::string const & get_connect_string() const { return connectString_; } // Set the value of the given option, overwriting any previous value. void set_option(const char * name, std::string const & value) { options_[name] = value; } // Return true if the option with the given name was found and fill the // provided parameter with its value. bool get_option(const char * name, std::string & value) const { Options::const_iterator const it = options_.find(name); if (it == options_.end()) return false; value = it->second; return true; } private: // The backend and connection string specified in our ctor. backend_factory const * factory_; std::string connectString_; // We store all the values as strings for simplicity. typedef std::map Options; Options options_; }; } // namespace soci #endif // SOCI_CONNECTION_PARAMETERS_H_INCLUDED soci-3.2.3/core/into-type.h0000644000000000000000000001031612511362240014200 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_INTO_TYPE_H_INCLUDED #define SOCI_INTO_TYPE_H_INCLUDED #include "soci-backend.h" #include "type-ptr.h" #include "exchange-traits.h" // std #include #include namespace soci { class session; namespace details { class prepare_temp_type; class standard_into_type_backend; class vector_into_type_backend; class statement_impl; // this is intended to be a base class for all classes that deal with // defining output data class into_type_base { public: virtual ~into_type_base() {} virtual void define(statement_impl & st, int & position) = 0; virtual void pre_fetch() = 0; virtual void post_fetch(bool gotData, bool calledFromFetch) = 0; virtual void clean_up() = 0; virtual std::size_t size() const = 0; // returns the number of elements virtual void resize(std::size_t /* sz */) {} // used for vectors only }; typedef type_ptr into_type_ptr; // standard types class SOCI_DECL standard_into_type : public into_type_base { public: standard_into_type(void * data, exchange_type type) : data_(data), type_(type), ind_(NULL), backEnd_(NULL) {} standard_into_type(void * data, exchange_type type, indicator & ind) : data_(data), type_(type), ind_(&ind), backEnd_(NULL) {} virtual ~standard_into_type(); protected: virtual void post_fetch(bool gotData, bool calledFromFetch); private: virtual void define(statement_impl & st, int & position); virtual void pre_fetch(); virtual void clean_up(); virtual std::size_t size() const { return 1; } // conversion hook (from base type to arbitrary user type) virtual void convert_from_base() {} void * data_; exchange_type type_; indicator * ind_; standard_into_type_backend * backEnd_; }; // into type base class for vectors class SOCI_DECL vector_into_type : public into_type_base { public: vector_into_type(void * data, exchange_type type) : data_(data), type_(type), indVec_(NULL), backEnd_(NULL) {} vector_into_type(void * data, exchange_type type, std::vector & ind) : data_(data), type_(type), indVec_(&ind), backEnd_(NULL) {} ~vector_into_type(); protected: virtual void post_fetch(bool gotData, bool calledFromFetch); private: virtual void define(statement_impl & st, int & position); virtual void pre_fetch(); virtual void clean_up(); virtual void resize(std::size_t sz); virtual std::size_t size() const; void * data_; exchange_type type_; std::vector * indVec_; vector_into_type_backend * backEnd_; virtual void convert_from_base() {} }; // implementation for the basic types (those which are supported by the library // out of the box without user-provided conversions) template class into_type : public standard_into_type { public: into_type(T & t) : standard_into_type(&t, static_cast(exchange_traits::x_type)) {} into_type(T & t, indicator & ind) : standard_into_type(&t, static_cast(exchange_traits::x_type), ind) {} }; template class into_type > : public vector_into_type { public: into_type(std::vector & v) : vector_into_type(&v, static_cast(exchange_traits::x_type)) {} into_type(std::vector & v, std::vector & ind) : vector_into_type(&v, static_cast(exchange_traits::x_type), ind) {} }; // helper dispatchers for basic types template into_type_ptr do_into(T & t, basic_type_tag) { return into_type_ptr(new into_type(t)); } template into_type_ptr do_into(T & t, indicator & ind, basic_type_tag) { return into_type_ptr(new into_type(t, ind)); } template into_type_ptr do_into(T & t, std::vector & ind, basic_type_tag) { return into_type_ptr(new into_type(t, ind)); } } // namespace details } // namespace soci #endif // SOCI_INTO_TYPE_H_INCLUDED soci-3.2.3/core/prepare-temp-type.cpp0000644000000000000000000000200712511401144016156 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "prepare-temp-type.h" #include "ref-counted-prepare-info.h" #include "session.h" using namespace soci; using namespace soci::details; prepare_temp_type::prepare_temp_type(session & s) : rcpi_(new ref_counted_prepare_info(s)) { // this is the beginning of new query s.get_query_stream().str(""); } prepare_temp_type::prepare_temp_type(prepare_temp_type const & o) :rcpi_(o.rcpi_) { rcpi_->inc_ref(); } prepare_temp_type & prepare_temp_type::operator=(prepare_temp_type const & o) { o.rcpi_->inc_ref(); rcpi_->dec_ref(); rcpi_ = o.rcpi_; return *this; } prepare_temp_type::~prepare_temp_type() { rcpi_->dec_ref(); } prepare_temp_type & prepare_temp_type::operator,(into_type_ptr const & i) { rcpi_->exchange(i); return *this; } soci-3.2.3/core/once-temp-type.h0000644000000000000000000000446012511401144015116 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_ONCE_TEMP_TYPE_H_INCLUDED #define SOCI_ONCE_TEMP_TYPE_H_INCLUDED #include "ref-counted-statement.h" #include "prepare-temp-type.h" #if __cplusplus >= 201103L #define SOCI_ONCE_TEMP_TYPE_NOEXCEPT noexcept(false) #else #define SOCI_ONCE_TEMP_TYPE_NOEXCEPT #endif namespace soci { class session; namespace details { class ref_counted_statement; // this needs to be lightweight and copyable class SOCI_DECL once_temp_type { public: once_temp_type(session & s); once_temp_type(once_temp_type const & o); once_temp_type & operator=(once_temp_type const & o); ~once_temp_type() SOCI_ONCE_TEMP_TYPE_NOEXCEPT; template once_temp_type & operator<<(T const & t) { rcst_->accumulate(t); return *this; } once_temp_type & operator,(into_type_ptr const &); template once_temp_type &operator,(into_container const &ic) { rcst_->exchange(ic); return *this; } template once_temp_type &operator,(use_container const &uc) { rcst_->exchange(uc); return *this; } private: ref_counted_statement * rcst_; }; // this needs to be lightweight and copyable class once_type { public: once_type() : session_(NULL) {} once_type(session * s) : session_(s) {} void set_session(session * s) { session_ = s; } template once_temp_type operator<<(T const & t) { once_temp_type o(*session_); o << t; return o; } private: session * session_; }; // this needs to be lightweight and copyable class prepare_type { public: prepare_type() : session_(NULL) {} prepare_type(session * s) : session_(s) {} void set_session(session * s) { session_ = s; } template prepare_temp_type operator<<(T const & t) { prepare_temp_type p(*session_); p << t; return p; } private: session * session_; }; } // namespace details } // namespace soci #endif soci-3.2.3/core/soci-simple.cpp0000644000000000000000000015203412511361676015047 0ustar rootroot// // Copyright (C) 2008 Maciej Sobczak // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "soci-simple.h" #include "soci.h" #include #include #include #include #include #include #include using namespace soci; namespace // unnamed { struct session_wrapper { session sql; bool is_ok; std::string error_message; }; } // namespace unnamed SOCI_DECL session_handle soci_create_session(char const * connection_string) { session_wrapper * wrapper = NULL; try { wrapper = new session_wrapper(); } catch (...) { return NULL; } try { wrapper->sql.open(connection_string); wrapper->is_ok = true; } catch (std::exception const & e) { wrapper->is_ok = false; wrapper->error_message = e.what(); } return wrapper; } SOCI_DECL void soci_destroy_session(session_handle s) { session_wrapper * wrapper = static_cast(s); delete wrapper; } SOCI_DECL void soci_begin(session_handle s) { session_wrapper * wrapper = static_cast(s); try { wrapper->sql.begin(); wrapper->is_ok = true; } catch (std::exception const & e) { wrapper->is_ok = false; wrapper->error_message = e.what(); } } SOCI_DECL void soci_commit(session_handle s) { session_wrapper * wrapper = static_cast(s); try { wrapper->sql.commit(); wrapper->is_ok = true; } catch (std::exception const & e) { wrapper->is_ok = false; wrapper->error_message = e.what(); } } SOCI_DECL void soci_rollback(session_handle s) { session_wrapper * wrapper = static_cast(s); try { wrapper->sql.rollback(); wrapper->is_ok = true; } catch (std::exception const & e) { wrapper->is_ok = false; wrapper->error_message = e.what(); } } // this will not be needed until dynamic row is exposed // SOCI_DECL void soci_uppercase_column_names(session_handle s, bool forceToUpper) // { // session_wrapper * wrapper = static_cast(s); // wrapper->sql.uppercase_column_names(forceToUpper); // wrapper->is_ok = true; // } SOCI_DECL int soci_session_state(session_handle s) { session_wrapper * wrapper = static_cast(s); return wrapper->is_ok ? 1 : 0; } SOCI_DECL char const * soci_session_error_message(session_handle s) { session_wrapper * wrapper = static_cast(s); return wrapper->error_message.c_str(); } // statement namespace // unnamed { struct statement_wrapper { statement_wrapper(session & sql) : st(sql), statement_state(clean), into_kind(empty), use_kind(empty), next_position(0), is_ok(true) {} statement st; enum state { clean, defining, executing } statement_state; enum kind { empty, single, bulk } into_kind, use_kind; // into elements int next_position; std::vector into_types; // for both single and bulk std::vector into_indicators; std::map into_strings; std::map into_ints; std::map into_longlongs; std::map into_doubles; std::map into_dates; std::vector > into_indicators_v; std::map > into_strings_v; std::map > into_ints_v; std::map > into_longlongs_v; std::map > into_doubles_v; std::map > into_dates_v; // use elements std::map use_indicators; std::map use_strings; std::map use_ints; std::map use_longlongs; std::map use_doubles; std::map use_dates; std::map > use_indicators_v; std::map > use_strings_v; std::map > use_ints_v; std::map > use_longlongs_v; std::map > use_doubles_v; std::map > use_dates_v; // format is: "YYYY MM DD hh mm ss" char date_formatted[20]; bool is_ok; std::string error_message; }; // helper for checking if the attempt was made to add more into/use elements // after the statement was set for execution bool cannot_add_elements(statement_wrapper & wrapper, statement_wrapper::kind k, bool into) { if (wrapper.statement_state == statement_wrapper::executing) { wrapper.is_ok = false; wrapper.error_message = "Cannot add more data items."; return true; } if (into) { if (k == statement_wrapper::single && wrapper.into_kind == statement_wrapper::bulk) { wrapper.is_ok = false; wrapper.error_message = "Cannot add single into data items."; return true; } if (k == statement_wrapper::bulk && wrapper.into_kind == statement_wrapper::single) { wrapper.is_ok = false; wrapper.error_message = "Cannot add vector into data items."; return true; } } else { // trying to add use elements if (k == statement_wrapper::single && wrapper.use_kind == statement_wrapper::bulk) { wrapper.is_ok = false; wrapper.error_message = "Cannot add single use data items."; return true; } if (k == statement_wrapper::bulk && wrapper.use_kind == statement_wrapper::single) { wrapper.is_ok = false; wrapper.error_message = "Cannot add vector use data items."; return true; } } wrapper.is_ok = true; return false; } // helper for checking if the expected into element exists on the given position bool position_check_failed(statement_wrapper & wrapper, statement_wrapper::kind k, int position, data_type expected_type, char const * type_name) { if (position < 0 || position >= wrapper.next_position) { wrapper.is_ok = false; wrapper.error_message = "Invalid position."; return true; } if (wrapper.into_types[position] != expected_type) { wrapper.is_ok = false; wrapper.error_message = "No into "; if (k == statement_wrapper::bulk) { wrapper.error_message += "vector "; } wrapper.error_message += type_name; wrapper.error_message += " element at this position."; return true; } wrapper.is_ok = true; return false; } // helper for checking if the into element on the given position // is not null bool not_null_check_failed(statement_wrapper & wrapper, int position) { if (wrapper.into_indicators[position] == i_null) { wrapper.is_ok = false; wrapper.error_message = "Element is null."; return true; } wrapper.is_ok = true; return false; } // overloaded version for vectors bool not_null_check_failed(statement_wrapper & wrapper, int position, int index) { if (wrapper.into_indicators_v[position][index] == i_null) { wrapper.is_ok = false; wrapper.error_message = "Element is null."; return true; } wrapper.is_ok = true; return false; } // helper for checking the index value template bool index_check_failed(std::vector const & v, statement_wrapper & wrapper, int index) { if (index < 0 || index >= static_cast(v.size())) { wrapper.is_ok = false; wrapper.error_message = "Invalid index."; return true; } wrapper.is_ok = true; return false; } // helper for checking the uniqueness of the use element's name bool name_unique_check_failed(statement_wrapper & wrapper, statement_wrapper::kind k, char const * name) { bool is_unique; if (k == statement_wrapper::single) { typedef std::map::const_iterator iterator; iterator const it = wrapper.use_indicators.find(name); is_unique = it == wrapper.use_indicators.end(); } else { // vector version typedef std::map < std::string, std::vector >::const_iterator iterator; iterator const it = wrapper.use_indicators_v.find(name); is_unique = it == wrapper.use_indicators_v.end(); } if (is_unique) { wrapper.is_ok = true; return false; } else { wrapper.is_ok = false; wrapper.error_message = "Name of use element should be unique."; return true; } } // helper for checking if the use element with the given name exists bool name_exists_check_failed(statement_wrapper & wrapper, char const * name, data_type expected_type, statement_wrapper::kind k, char const * type_name) { bool name_exists = false; if (k == statement_wrapper::single) { switch (expected_type) { case dt_string: { typedef std::map < std::string, std::string >::const_iterator iterator; iterator const it = wrapper.use_strings.find(name); name_exists = (it != wrapper.use_strings.end()); } break; case dt_integer: { typedef std::map::const_iterator iterator; iterator const it = wrapper.use_ints.find(name); name_exists = (it != wrapper.use_ints.end()); } break; case dt_long_long: { typedef std::map::const_iterator iterator; iterator const it = wrapper.use_longlongs.find(name); name_exists = (it != wrapper.use_longlongs.end()); } break; case dt_double: { typedef std::map::const_iterator iterator; iterator const it = wrapper.use_doubles.find(name); name_exists = (it != wrapper.use_doubles.end()); } break; case dt_date: { typedef std::map::const_iterator iterator; iterator const it = wrapper.use_dates.find(name); name_exists = (it != wrapper.use_dates.end()); } break; default: assert(false); } } else { // vector version switch (expected_type) { case dt_string: { typedef std::map < std::string, std::vector >::const_iterator iterator; iterator const it = wrapper.use_strings_v.find(name); name_exists = (it != wrapper.use_strings_v.end()); } break; case dt_integer: { typedef std::map < std::string, std::vector >::const_iterator iterator; iterator const it = wrapper.use_ints_v.find(name); name_exists = (it != wrapper.use_ints_v.end()); } break; case dt_long_long: { typedef std::map < std::string, std::vector >::const_iterator iterator; iterator const it = wrapper.use_longlongs_v.find(name); name_exists = (it != wrapper.use_longlongs_v.end()); } break; case dt_double: { typedef std::map >::const_iterator iterator; iterator const it = wrapper.use_doubles_v.find(name); name_exists = (it != wrapper.use_doubles_v.end()); } break; case dt_date: { typedef std::map >::const_iterator iterator; iterator const it = wrapper.use_dates_v.find(name); name_exists = (it != wrapper.use_dates_v.end()); } break; default: assert(false); } } if (name_exists) { wrapper.is_ok = true; return false; } else { wrapper.is_ok = false; wrapper.error_message = "No use "; wrapper.error_message += type_name; wrapper.error_message += " element with this name."; return true; } } // helper function for resizing all vectors in the map template void resize_in_map(std::map > & m, int new_size) { typedef typename std::map >::iterator iterator; iterator it = m.begin(); iterator const end = m.end(); for ( ; it != end; ++it) { std::vector & v = it->second; v.resize(new_size); } } // helper for formatting date values char const * format_date(statement_wrapper & wrapper, std::tm const & d) { std::sprintf(wrapper.date_formatted, "%d %d %d %d %d %d", d.tm_year + 1900, d.tm_mon + 1, d.tm_mday, d.tm_hour, d.tm_min, d.tm_sec); return wrapper.date_formatted; } bool string_to_date(char const * val, std::tm & /* out */ dt, statement_wrapper & wrapper) { // format is: "YYYY MM DD hh mm ss" int year; int month; int day; int hour; int minute; int second; int const converted = std::sscanf(val, "%d %d %d %d %d %d", &year, &month, &day, &hour, &minute, &second); if (converted != 6) { wrapper.is_ok = false; wrapper.error_message = "Cannot convert date."; return false; } wrapper.is_ok = true; dt.tm_year = year - 1900; dt.tm_mon = month - 1; dt.tm_mday = day; dt.tm_hour = hour; dt.tm_min = minute; dt.tm_sec = second; return true; } } // namespace unnamed SOCI_DECL statement_handle soci_create_statement(session_handle s) { session_wrapper * session_w = static_cast(s); try { statement_wrapper * statement_w = new statement_wrapper(session_w->sql); return statement_w; } catch (std::exception const & e) { session_w->is_ok = false; session_w->error_message = e.what(); return NULL; } } SOCI_DECL void soci_destroy_statement(statement_handle st) { statement_wrapper * wrapper = static_cast(st); delete wrapper; } SOCI_DECL int soci_into_string(statement_handle st) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::single, true)) { return -1; } wrapper->statement_state = statement_wrapper::defining; wrapper->into_kind = statement_wrapper::single; wrapper->into_types.push_back(dt_string); wrapper->into_indicators.push_back(i_ok); wrapper->into_strings[wrapper->next_position]; // create new entry return wrapper->next_position++; } SOCI_DECL int soci_into_int(statement_handle st) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::single, true)) { return -1; } wrapper->statement_state = statement_wrapper::defining; wrapper->into_kind = statement_wrapper::single; wrapper->into_types.push_back(dt_integer); wrapper->into_indicators.push_back(i_ok); wrapper->into_ints[wrapper->next_position]; // create new entry return wrapper->next_position++; } SOCI_DECL int soci_into_long_long(statement_handle st) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::single, true)) { return -1; } wrapper->statement_state = statement_wrapper::defining; wrapper->into_kind = statement_wrapper::single; wrapper->into_types.push_back(dt_long_long); wrapper->into_indicators.push_back(i_ok); wrapper->into_longlongs[wrapper->next_position]; // create new entry return wrapper->next_position++; } SOCI_DECL int soci_into_double(statement_handle st) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::single, true)) { return -1; } wrapper->statement_state = statement_wrapper::defining; wrapper->into_kind = statement_wrapper::single; wrapper->into_types.push_back(dt_double); wrapper->into_indicators.push_back(i_ok); wrapper->into_doubles[wrapper->next_position]; // create new entry return wrapper->next_position++; } SOCI_DECL int soci_into_date(statement_handle st) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::single, true)) { return -1; } wrapper->statement_state = statement_wrapper::defining; wrapper->into_kind = statement_wrapper::single; wrapper->into_types.push_back(dt_date); wrapper->into_indicators.push_back(i_ok); wrapper->into_dates[wrapper->next_position]; // create new entry return wrapper->next_position++; } SOCI_DECL int soci_into_string_v(statement_handle st) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::bulk, true)) { return -1; } wrapper->statement_state = statement_wrapper::defining; wrapper->into_kind = statement_wrapper::bulk; wrapper->into_types.push_back(dt_string); wrapper->into_indicators_v.push_back(std::vector()); wrapper->into_strings_v[wrapper->next_position]; return wrapper->next_position++; } SOCI_DECL int soci_into_int_v(statement_handle st) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::bulk, true)) { return -1; } wrapper->statement_state = statement_wrapper::defining; wrapper->into_kind = statement_wrapper::bulk; wrapper->into_types.push_back(dt_integer); wrapper->into_indicators_v.push_back(std::vector()); wrapper->into_ints_v[wrapper->next_position]; return wrapper->next_position++; } SOCI_DECL int soci_into_long_long_v(statement_handle st) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::bulk, true)) { return -1; } wrapper->statement_state = statement_wrapper::defining; wrapper->into_kind = statement_wrapper::bulk; wrapper->into_types.push_back(dt_long_long); wrapper->into_indicators_v.push_back(std::vector()); wrapper->into_longlongs_v[wrapper->next_position]; return wrapper->next_position++; } SOCI_DECL int soci_into_double_v(statement_handle st) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::bulk, true)) { return -1; } wrapper->statement_state = statement_wrapper::defining; wrapper->into_kind = statement_wrapper::bulk; wrapper->into_types.push_back(dt_double); wrapper->into_indicators_v.push_back(std::vector()); wrapper->into_doubles_v[wrapper->next_position]; return wrapper->next_position++; } SOCI_DECL int soci_into_date_v(statement_handle st) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::bulk, true)) { return -1; } wrapper->statement_state = statement_wrapper::defining; wrapper->into_kind = statement_wrapper::bulk; wrapper->into_types.push_back(dt_date); wrapper->into_indicators_v.push_back(std::vector()); wrapper->into_dates_v[wrapper->next_position]; return wrapper->next_position++; } SOCI_DECL int soci_get_into_state(statement_handle st, int position) { statement_wrapper * wrapper = static_cast(st); if (position < 0 || position >= wrapper->next_position) { wrapper->is_ok = false; wrapper->error_message = "Invalid position."; return 0; } wrapper->is_ok = true; return wrapper->into_indicators[position] == i_ok ? 1 : 0; } SOCI_DECL char const * soci_get_into_string(statement_handle st, int position) { statement_wrapper * wrapper = static_cast(st); if (position_check_failed(*wrapper, statement_wrapper::single, position, dt_string, "string") || not_null_check_failed(*wrapper, position)) { return ""; } return wrapper->into_strings[position].c_str(); } SOCI_DECL int soci_get_into_int(statement_handle st, int position) { statement_wrapper * wrapper = static_cast(st); if (position_check_failed(*wrapper, statement_wrapper::single, position, dt_integer, "int") || not_null_check_failed(*wrapper, position)) { return 0; } return wrapper->into_ints[position]; } SOCI_DECL long long soci_get_into_long_long(statement_handle st, int position) { statement_wrapper * wrapper = static_cast(st); if (position_check_failed(*wrapper, statement_wrapper::single, position, dt_long_long, "long long") || not_null_check_failed(*wrapper, position)) { return 0LL; } return wrapper->into_longlongs[position]; } SOCI_DECL double soci_get_into_double(statement_handle st, int position) { statement_wrapper * wrapper = static_cast(st); if (position_check_failed(*wrapper, statement_wrapper::single, position, dt_double, "double") || not_null_check_failed(*wrapper, position)) { return 0.0; } return wrapper->into_doubles[position]; } SOCI_DECL char const * soci_get_into_date(statement_handle st, int position) { statement_wrapper * wrapper = static_cast(st); if (position_check_failed(*wrapper, statement_wrapper::single, position, dt_date, "date") || not_null_check_failed(*wrapper, position)) { return ""; } // format is: "YYYY MM DD hh mm ss" std::tm const & d = wrapper->into_dates[position]; return format_date(*wrapper, d); } SOCI_DECL int soci_into_get_size_v(statement_handle st) { statement_wrapper * wrapper = static_cast(st); if (wrapper->into_kind != statement_wrapper::bulk) { wrapper->is_ok = false; wrapper->error_message = "No vector into elements."; return -1; } return static_cast(wrapper->into_indicators_v[0].size()); } SOCI_DECL void soci_into_resize_v(statement_handle st, int new_size) { statement_wrapper * wrapper = static_cast(st); if (new_size <= 0) { wrapper->is_ok = false; wrapper->error_message = "Invalid size."; return; } if (wrapper->into_kind != statement_wrapper::bulk) { wrapper->is_ok = false; wrapper->error_message = "No vector into elements."; return; } for (int i = 0; i != wrapper->next_position; ++i) { wrapper->into_indicators_v[i].resize(new_size); switch (wrapper->into_types[i]) { case dt_string: wrapper->into_strings_v[i].resize(new_size); break; case dt_integer: wrapper->into_ints_v[i].resize(new_size); break; case dt_long_long: wrapper->into_longlongs_v[i].resize(new_size); break; case dt_double: wrapper->into_doubles_v[i].resize(new_size); break; case dt_date: wrapper->into_dates_v[i].resize(new_size); break; default: assert(false); } } wrapper->is_ok = true; } SOCI_DECL int soci_get_into_state_v(statement_handle st, int position, int index) { statement_wrapper * wrapper = static_cast(st); if (position < 0 || position >= wrapper->next_position) { wrapper->is_ok = false; wrapper->error_message = "Invalid position."; return 0; } std::vector const & v = wrapper->into_indicators_v[position]; if (index_check_failed(v, *wrapper, index)) { return 0; } return v[index] == i_ok ? 1 : 0; } SOCI_DECL char const * soci_get_into_string_v(statement_handle st, int position, int index) { statement_wrapper * wrapper = static_cast(st); if (position_check_failed(*wrapper, statement_wrapper::bulk, position, dt_string, "string")) { return ""; } std::vector const & v = wrapper->into_strings_v[position]; if (index_check_failed(v, *wrapper, index) || not_null_check_failed(*wrapper, position, index)) { return ""; } return v[index].c_str(); } SOCI_DECL int soci_get_into_int_v(statement_handle st, int position, int index) { statement_wrapper * wrapper = static_cast(st); if (position_check_failed(*wrapper, statement_wrapper::bulk, position, dt_integer, "int")) { return 0; } std::vector const & v = wrapper->into_ints_v[position]; if (index_check_failed(v, *wrapper, index) || not_null_check_failed(*wrapper, position, index)) { return 0; } return v[index]; } SOCI_DECL long long soci_get_into_long_long_v(statement_handle st, int position, int index) { statement_wrapper * wrapper = static_cast(st); if (position_check_failed(*wrapper, statement_wrapper::bulk, position, dt_long_long, "long long")) { return 0; } std::vector const & v = wrapper->into_longlongs_v[position]; if (index_check_failed(v, *wrapper, index) || not_null_check_failed(*wrapper, position, index)) { return 0; } return v[index]; } SOCI_DECL double soci_get_into_double_v(statement_handle st, int position, int index) { statement_wrapper * wrapper = static_cast(st); if (position_check_failed(*wrapper, statement_wrapper::bulk, position, dt_double, "double")) { return 0.0; } std::vector const & v = wrapper->into_doubles_v[position]; if (index_check_failed(v, *wrapper, index) || not_null_check_failed(*wrapper, position, index)) { return 0.0; } return v[index]; } SOCI_DECL char const * soci_get_into_date_v(statement_handle st, int position, int index) { statement_wrapper * wrapper = static_cast(st); if (position_check_failed(*wrapper, statement_wrapper::bulk, position, dt_date, "date")) { return ""; } std::vector const & v = wrapper->into_dates_v[position]; if (index_check_failed(v, *wrapper, index) || not_null_check_failed(*wrapper, position, index)) { return ""; } return format_date(*wrapper, v[index]); } SOCI_DECL void soci_use_string(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::single, false) || name_unique_check_failed(*wrapper, statement_wrapper::single, name)) { return; } wrapper->statement_state = statement_wrapper::defining; wrapper->use_kind = statement_wrapper::single; wrapper->use_indicators[name] = i_ok; // create new entry wrapper->use_strings[name]; // create new entry } SOCI_DECL void soci_use_int(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::single, false) || name_unique_check_failed(*wrapper, statement_wrapper::single, name)) { return; } wrapper->statement_state = statement_wrapper::defining; wrapper->use_kind = statement_wrapper::single; wrapper->use_indicators[name] = i_ok; // create new entry wrapper->use_ints[name]; // create new entry } SOCI_DECL void soci_use_long_long(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::single, false) || name_unique_check_failed(*wrapper, statement_wrapper::single, name)) { return; } wrapper->statement_state = statement_wrapper::defining; wrapper->use_kind = statement_wrapper::single; wrapper->use_indicators[name] = i_ok; // create new entry wrapper->use_longlongs[name]; // create new entry } SOCI_DECL void soci_use_double(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::single, false) || name_unique_check_failed(*wrapper, statement_wrapper::single, name)) { return; } wrapper->statement_state = statement_wrapper::defining; wrapper->use_kind = statement_wrapper::single; wrapper->use_indicators[name] = i_ok; // create new entry wrapper->use_doubles[name]; // create new entry } SOCI_DECL void soci_use_date(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::single, false) || name_unique_check_failed(*wrapper, statement_wrapper::single, name)) { return; } wrapper->statement_state = statement_wrapper::defining; wrapper->use_kind = statement_wrapper::single; wrapper->use_indicators[name] = i_ok; // create new entry wrapper->use_dates[name]; // create new entry } SOCI_DECL void soci_use_string_v(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::bulk, false) || name_unique_check_failed(*wrapper, statement_wrapper::bulk, name)) { return; } wrapper->statement_state = statement_wrapper::defining; wrapper->use_kind = statement_wrapper::bulk; wrapper->use_indicators_v[name]; // create new entry wrapper->use_strings_v[name]; // create new entry } SOCI_DECL void soci_use_int_v(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::bulk, false) || name_unique_check_failed(*wrapper, statement_wrapper::bulk, name)) { return; } wrapper->statement_state = statement_wrapper::defining; wrapper->use_kind = statement_wrapper::bulk; wrapper->use_indicators_v[name]; // create new entry wrapper->use_ints_v[name]; // create new entry } SOCI_DECL void soci_use_long_long_v(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::bulk, false) || name_unique_check_failed(*wrapper, statement_wrapper::bulk, name)) { return; } wrapper->statement_state = statement_wrapper::defining; wrapper->use_kind = statement_wrapper::bulk; wrapper->use_indicators_v[name]; // create new entry wrapper->use_longlongs_v[name]; // create new entry } SOCI_DECL void soci_use_double_v(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::bulk, false) || name_unique_check_failed(*wrapper, statement_wrapper::bulk, name)) { return; } wrapper->statement_state = statement_wrapper::defining; wrapper->use_kind = statement_wrapper::bulk; wrapper->use_indicators_v[name]; // create new entry wrapper->use_doubles_v[name]; // create new entry } SOCI_DECL void soci_use_date_v(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (cannot_add_elements(*wrapper, statement_wrapper::bulk, false) || name_unique_check_failed(*wrapper, statement_wrapper::bulk, name)) { return; } wrapper->statement_state = statement_wrapper::defining; wrapper->use_kind = statement_wrapper::bulk; wrapper->use_indicators_v[name]; // create new entry wrapper->use_dates_v[name]; // create new entry } SOCI_DECL void soci_set_use_state(statement_handle st, char const * name, int state) { statement_wrapper * wrapper = static_cast(st); typedef std::map::const_iterator iterator; iterator const it = wrapper->use_indicators.find(name); if (it == wrapper->use_indicators.end()) { wrapper->is_ok = false; wrapper->error_message = "Invalid name."; return; } wrapper->is_ok = true; wrapper->use_indicators[name] = (state != 0 ? i_ok : i_null); } SOCI_DECL void soci_set_use_string(statement_handle st, char const * name, char const * val) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_string, statement_wrapper::single, "string")) { return; } wrapper->use_indicators[name] = i_ok; wrapper->use_strings[name] = val; } SOCI_DECL void soci_set_use_int(statement_handle st, char const * name, int val) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_integer, statement_wrapper::single, "int")) { return; } wrapper->use_indicators[name] = i_ok; wrapper->use_ints[name] = val; } SOCI_DECL void soci_set_use_long_long(statement_handle st, char const * name, long long val) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_long_long, statement_wrapper::single, "long long")) { return; } wrapper->use_indicators[name] = i_ok; wrapper->use_longlongs[name] = val; } SOCI_DECL void soci_set_use_double(statement_handle st, char const * name, double val) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_double, statement_wrapper::single, "double")) { return; } wrapper->use_indicators[name] = i_ok; wrapper->use_doubles[name] = val; } SOCI_DECL void soci_set_use_date(statement_handle st, char const * name, char const * val) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_date, statement_wrapper::single, "date")) { return; } std::tm dt; bool const converted = string_to_date(val, dt, *wrapper); if (converted == false) { return; } wrapper->use_indicators[name] = i_ok; wrapper->use_dates[name] = dt; } SOCI_DECL int soci_use_get_size_v(statement_handle st) { statement_wrapper * wrapper = static_cast(st); if (wrapper->use_kind != statement_wrapper::bulk) { wrapper->is_ok = false; wrapper->error_message = "No vector use elements."; return -1; } typedef std::map >::const_iterator iterator; iterator const any_element = wrapper->use_indicators_v.begin(); assert(any_element != wrapper->use_indicators_v.end()); return static_cast(any_element->second.size()); } SOCI_DECL void soci_use_resize_v(statement_handle st, int new_size) { statement_wrapper * wrapper = static_cast(st); if (new_size <= 0) { wrapper->is_ok = false; wrapper->error_message = "Invalid size."; return; } if (wrapper->use_kind != statement_wrapper::bulk) { wrapper->is_ok = false; wrapper->error_message = "No vector use elements."; return; } resize_in_map(wrapper->use_indicators_v, new_size); resize_in_map(wrapper->use_strings_v, new_size); resize_in_map(wrapper->use_ints_v, new_size); resize_in_map(wrapper->use_longlongs_v, new_size); resize_in_map(wrapper->use_doubles_v, new_size); resize_in_map(wrapper->use_dates_v, new_size); wrapper->is_ok = true; } SOCI_DECL void soci_set_use_state_v(statement_handle st, char const * name, int index, int state) { statement_wrapper * wrapper = static_cast(st); typedef std::map >::iterator iterator; iterator const it = wrapper->use_indicators_v.find(name); if (it == wrapper->use_indicators_v.end()) { wrapper->is_ok = false; wrapper->error_message = "Invalid name."; return; } std::vector & v = it->second; if (index_check_failed(v, *wrapper, index)) { return; } v[index] = (state != 0 ? i_ok : i_null); } SOCI_DECL void soci_set_use_string_v(statement_handle st, char const * name, int index, char const * val) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_string, statement_wrapper::bulk, "vector string")) { return; } std::vector & v = wrapper->use_strings_v[name]; if (index_check_failed(v, *wrapper, index)) { return; } wrapper->use_indicators_v[name][index] = i_ok; v[index] = val; } SOCI_DECL void soci_set_use_int_v(statement_handle st, char const * name, int index, int val) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_integer, statement_wrapper::bulk, "vector int")) { return; } std::vector & v = wrapper->use_ints_v[name]; if (index_check_failed(v, *wrapper, index)) { return; } wrapper->use_indicators_v[name][index] = i_ok; v[index] = val; } SOCI_DECL void soci_set_use_long_long_v(statement_handle st, char const * name, int index, long long val) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_long_long, statement_wrapper::bulk, "vector long long")) { return; } std::vector & v = wrapper->use_longlongs_v[name]; if (index_check_failed(v, *wrapper, index)) { return; } wrapper->use_indicators_v[name][index] = i_ok; v[index] = val; } SOCI_DECL void soci_set_use_double_v(statement_handle st, char const * name, int index, double val) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_double, statement_wrapper::bulk, "vector double")) { return; } std::vector & v = wrapper->use_doubles_v[name]; if (index_check_failed(v, *wrapper, index)) { return; } wrapper->use_indicators_v[name][index] = i_ok; v[index] = val; } SOCI_DECL void soci_set_use_date_v(statement_handle st, char const * name, int index, char const * val) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_date, statement_wrapper::bulk, "vector date")) { return; } std::vector & v = wrapper->use_dates_v[name]; if (index_check_failed(v, *wrapper, index)) { return; } std::tm dt; bool const converted = string_to_date(val, dt, *wrapper); if (converted == false) { return; } wrapper->use_indicators_v[name][index] = i_ok; v[index] = dt; } SOCI_DECL int soci_get_use_state(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); typedef std::map::const_iterator iterator; iterator const it = wrapper->use_indicators.find(name); if (it == wrapper->use_indicators.end()) { wrapper->is_ok = false; wrapper->error_message = "Invalid name."; return 0; } wrapper->is_ok = true; return wrapper->use_indicators[name] == i_ok ? 1 : 0; } SOCI_DECL char const * soci_get_use_string(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_string, statement_wrapper::bulk, "string")) { return ""; } return wrapper->use_strings[name].c_str(); } SOCI_DECL int soci_get_use_int(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_integer, statement_wrapper::bulk, "int")) { return 0; } return wrapper->use_ints[name]; } SOCI_DECL long long soci_get_use_long_long(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_long_long, statement_wrapper::bulk, "long long")) { return 0LL; } return wrapper->use_longlongs[name]; } SOCI_DECL double soci_get_use_double(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_double, statement_wrapper::bulk, "double")) { return 0.0; } return wrapper->use_doubles[name]; } SOCI_DECL char const * soci_get_use_date(statement_handle st, char const * name) { statement_wrapper * wrapper = static_cast(st); if (name_exists_check_failed(*wrapper, name, dt_date, statement_wrapper::bulk, "date")) { return ""; } // format is: "YYYY MM DD hh mm ss" std::tm const & d = wrapper->use_dates[name]; std::sprintf(wrapper->date_formatted, "%d %d %d %d %d %d", d.tm_year + 1900, d.tm_mon + 1, d.tm_mday, d.tm_hour, d.tm_min, d.tm_sec); return wrapper->date_formatted; } SOCI_DECL void soci_prepare(statement_handle st, char const * query) { statement_wrapper * wrapper = static_cast(st); try { wrapper->statement_state = statement_wrapper::executing; // bind all into elements int const into_elements = static_cast(wrapper->into_types.size()); if (wrapper->into_kind == statement_wrapper::single) { for (int i = 0; i != into_elements; ++i) { switch (wrapper->into_types[i]) { case dt_string: wrapper->st.exchange( into(wrapper->into_strings[i], wrapper->into_indicators[i])); break; case dt_integer: wrapper->st.exchange( into(wrapper->into_ints[i], wrapper->into_indicators[i])); break; case dt_long_long: wrapper->st.exchange( into(wrapper->into_longlongs[i], wrapper->into_indicators[i])); break; case dt_double: wrapper->st.exchange( into(wrapper->into_doubles[i], wrapper->into_indicators[i])); break; case dt_date: wrapper->st.exchange( into(wrapper->into_dates[i], wrapper->into_indicators[i])); break; default: assert(false); } } } else { // vector elements for (int i = 0; i != into_elements; ++i) { switch (wrapper->into_types[i]) { case dt_string: wrapper->st.exchange( into(wrapper->into_strings_v[i], wrapper->into_indicators_v[i])); break; case dt_integer: wrapper->st.exchange( into(wrapper->into_ints_v[i], wrapper->into_indicators_v[i])); break; case dt_long_long: wrapper->st.exchange( into(wrapper->into_longlongs_v[i], wrapper->into_indicators_v[i])); break; case dt_double: wrapper->st.exchange( into(wrapper->into_doubles_v[i], wrapper->into_indicators_v[i])); break; case dt_date: wrapper->st.exchange( into(wrapper->into_dates_v[i], wrapper->into_indicators_v[i])); break; default: assert(false); } } } // bind all use elements { // strings typedef std::map::iterator iterator; iterator uit = wrapper->use_strings.begin(); iterator const uend = wrapper->use_strings.end(); for ( ; uit != uend; ++uit) { std::string const & use_name = uit->first; std::string & use_string = uit->second; indicator & use_ind = wrapper->use_indicators[use_name]; wrapper->st.exchange(use(use_string, use_ind, use_name)); } } { // ints typedef std::map::iterator iterator; iterator uit = wrapper->use_ints.begin(); iterator const uend = wrapper->use_ints.end(); for ( ; uit != uend; ++uit) { std::string const & use_name = uit->first; int & use_int = uit->second; indicator & use_ind = wrapper->use_indicators[use_name]; wrapper->st.exchange(use(use_int, use_ind, use_name)); } } { // longlongs typedef std::map::iterator iterator; iterator uit = wrapper->use_longlongs.begin(); iterator const uend = wrapper->use_longlongs.end(); for ( ; uit != uend; ++uit) { std::string const & use_name = uit->first; long long & use_longlong = uit->second; indicator & use_ind = wrapper->use_indicators[use_name]; wrapper->st.exchange(use(use_longlong, use_ind, use_name)); } } { // doubles typedef std::map::iterator iterator; iterator uit = wrapper->use_doubles.begin(); iterator const uend = wrapper->use_doubles.end(); for ( ; uit != uend; ++uit) { std::string const & use_name = uit->first; double & use_double = uit->second; indicator & use_ind = wrapper->use_indicators[use_name]; wrapper->st.exchange(use(use_double, use_ind, use_name)); } } { // dates typedef std::map::iterator iterator; iterator uit = wrapper->use_dates.begin(); iterator const uend = wrapper->use_dates.end(); for ( ; uit != uend; ++uit) { std::string const & use_name = uit->first; std::tm & use_date = uit->second; indicator & use_ind = wrapper->use_indicators[use_name]; wrapper->st.exchange(use(use_date, use_ind, use_name)); } } // bind all use vecctor elements { // strings typedef std::map >::iterator iterator; iterator uit = wrapper->use_strings_v.begin(); iterator const uend = wrapper->use_strings_v.end(); for ( ; uit != uend; ++uit) { std::string const & use_name = uit->first; std::vector & use_string = uit->second; std::vector & use_ind = wrapper->use_indicators_v[use_name]; wrapper->st.exchange(use(use_string, use_ind, use_name)); } } { // ints typedef std::map >::iterator iterator; iterator uit = wrapper->use_ints_v.begin(); iterator const uend = wrapper->use_ints_v.end(); for ( ; uit != uend; ++uit) { std::string const & use_name = uit->first; std::vector & use_int = uit->second; std::vector & use_ind = wrapper->use_indicators_v[use_name]; wrapper->st.exchange(use(use_int, use_ind, use_name)); } } { // longlongs typedef std::map >::iterator iterator; iterator uit = wrapper->use_longlongs_v.begin(); iterator const uend = wrapper->use_longlongs_v.end(); for ( ; uit != uend; ++uit) { std::string const & use_name = uit->first; std::vector & use_longlong = uit->second; std::vector & use_ind = wrapper->use_indicators_v[use_name]; wrapper->st.exchange(use(use_longlong, use_ind, use_name)); } } { // doubles typedef std::map >::iterator iterator; iterator uit = wrapper->use_doubles_v.begin(); iterator const uend = wrapper->use_doubles_v.end(); for ( ; uit != uend; ++uit) { std::string const & use_name = uit->first; std::vector & use_double = uit->second; std::vector & use_ind = wrapper->use_indicators_v[use_name]; wrapper->st.exchange(use(use_double, use_ind, use_name)); } } { // dates typedef std::map >::iterator iterator; iterator uit = wrapper->use_dates_v.begin(); iterator const uend = wrapper->use_dates_v.end(); for ( ; uit != uend; ++uit) { std::string const & use_name = uit->first; std::vector & use_date = uit->second; std::vector & use_ind = wrapper->use_indicators_v[use_name]; wrapper->st.exchange(use(use_date, use_ind, use_name)); } } wrapper->st.alloc(); wrapper->st.prepare(query); wrapper->st.define_and_bind(); wrapper->is_ok = true; } catch (std::exception const & e) { wrapper->is_ok = false; wrapper->error_message = e.what(); } } SOCI_DECL int soci_execute(statement_handle st, int withDataExchange) { statement_wrapper * wrapper = static_cast(st); try { bool const gotData = wrapper->st.execute(withDataExchange != 0); wrapper->is_ok = true; return gotData ? 1 : 0; } catch (std::exception const & e) { wrapper->is_ok = false; wrapper->error_message = e.what(); return 0; } } SOCI_DECL long long soci_get_affected_rows(statement_handle st) { statement_wrapper * wrapper = static_cast(st); return wrapper->st.get_affected_rows(); } SOCI_DECL int soci_fetch(statement_handle st) { statement_wrapper * wrapper = static_cast(st); try { bool const gotData = wrapper->st.fetch(); wrapper->is_ok = true; return gotData ? 1 : 0; } catch (std::exception const & e) { wrapper->is_ok = false; wrapper->error_message = e.what(); return 0; } } SOCI_DECL int soci_got_data(statement_handle st) { statement_wrapper * wrapper = static_cast(st); return wrapper->st.got_data() ? 1 : 0; } SOCI_DECL int soci_statement_state(statement_handle st) { statement_wrapper * wrapper = static_cast(st); return wrapper->is_ok ? 1 : 0; } SOCI_DECL char const * soci_statement_error_message(statement_handle st) { statement_wrapper * wrapper = static_cast(st); return wrapper->error_message.c_str(); } soci-3.2.3/core/rowid.h0000644000000000000000000000121312511362240013370 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_ROWID_H_INCLUDED #define SOCI_ROWID_H_INCLUDED #include "soci-config.h" namespace soci { class session; namespace details { class rowid_backend; } // namespace details // ROWID support class SOCI_DECL rowid { public: explicit rowid(session & s); ~rowid(); details::rowid_backend * get_backend() { return backEnd_; } private: details::rowid_backend *backEnd_; }; } // namespace soci #endif soci-3.2.3/core/transaction.cpp0000644000000000000000000000161612511361676015147 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "transaction.h" #include "error.h" using namespace soci; transaction::transaction(session& sql) : handled_(false), sql_(sql) { sql_.begin(); } transaction::~transaction() { if (handled_ == false) { try { rollback(); } catch (...) {} } } void transaction::commit() { if (handled_) { throw soci_error("The transaction object cannot be handled twice."); } sql_.commit(); handled_ = true; } void transaction::rollback() { if (handled_) { throw soci_error("The transaction object cannot be handled twice."); } sql_.rollback(); handled_ = true; } soci-3.2.3/core/backend-loader.h0000644000000000000000000000202512511362240015101 0ustar rootroot// // Copyright (C) 2008 Maciej Sobczak with contributions from Artyom Tonkikh // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_BACKEND_LOADER_H_INCLUDED #define SOCI_BACKEND_LOADER_H_INCLUDED #include "soci-backend.h" // std #include #include namespace soci { namespace dynamic_backends { // used internally by session backend_factory const & get(std::string const & name); // provided for advanced user-level management SOCI_DECL std::vector & search_paths(); SOCI_DECL void register_backend(std::string const & name, std::string const & shared_object = std::string()); SOCI_DECL void register_backend(std::string const & name, backend_factory const & factory); SOCI_DECL std::vector list_all(); SOCI_DECL void unload(std::string const & name); SOCI_DECL void unload_all(); } // namespace dynamic_backends } // namespace soci #endif // SOCI_BACKEND_LOADER_H_INCLUDED soci-3.2.3/core/session.h0000644000000000000000000001022312511362240013730 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_SESSION_H_INCLUDED #define SOCI_SESSION_H_INCLUDED #include "once-temp-type.h" #include "query_transformation.h" #include "connection-parameters.h" // std #include #include #include #include #include namespace soci { class values; class backend_factory; namespace details { class session_backend; class statement_backend; class rowid_backend; class blob_backend; } // namespace details class connection_pool; class SOCI_DECL session { private: void set_query_transformation_(std::auto_ptr qtf); public: session(); explicit session(connection_parameters const & parameters); session(backend_factory const & factory, std::string const & connectString); session(std::string const & backendName, std::string const & connectString); explicit session(std::string const & connectString); explicit session(connection_pool & pool); ~session(); void open(connection_parameters const & parameters); void open(backend_factory const & factory, std::string const & connectString); void open(std::string const & backendName, std::string const & connectString); void open(std::string const & connectString); void close(); void reconnect(); void begin(); void commit(); void rollback(); // once and prepare are for syntax sugar only details::once_type once; details::prepare_type prepare; // even more sugar template details::once_temp_type operator<<(T const & t) { return once << t; } std::ostringstream & get_query_stream(); std::string get_query() const; template void set_query_transformation(T callback) { std::auto_ptr qtf(new details::query_transformation(callback)); set_query_transformation_(qtf); assert(qtf.get() == NULL); } // support for basic logging void set_log_stream(std::ostream * s); std::ostream * get_log_stream() const; void log_query(std::string const & query); std::string get_last_query() const; void set_got_data(bool gotData); bool got_data() const; void uppercase_column_names(bool forceToUpper); bool get_uppercase_column_names() const; // Functions for dealing with sequence/auto-increment values. // If true is returned, value is filled with the next value from the given // sequence. Otherwise either the sequence is invalid (doesn't exist) or // the current backend doesn't support sequences. If you use sequences for // automatically generating primary key values, you should use // get_last_insert_id() after the insertion in this case. bool get_next_sequence_value(std::string const & sequence, long & value); // If true is returned, value is filled with the last auto-generated value // for this table (although some backends ignore the table argument and // return the last value auto-generated in this session). bool get_last_insert_id(std::string const & table, long & value); // for diagnostics and advanced users // (downcast it to expected back-end session class) details::session_backend * get_backend() { return backEnd_; } std::string get_backend_name() const; details::statement_backend * make_statement_backend(); details::rowid_backend * make_rowid_backend(); details::blob_backend * make_blob_backend(); private: session(session const &); session& operator=(session const &); std::ostringstream query_stream_; details::query_transformation_function* query_transformation_; std::ostream * logStream_; std::string lastQuery_; connection_parameters lastConnectParameters_; bool uppercaseColumnNames_; details::session_backend * backEnd_; bool gotData_; bool isFromPool_; std::size_t poolPosition_; connection_pool * pool_; }; } // namespace soci #endif // SOCI_SESSION_H_INCLUDED soci-3.2.3/core/boost-fusion.h0000644000000000000000000000155612511401144014702 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_BOOST_FUSION_H_INCLUDED #define SOCI_BOOST_FUSION_H_INCLUDED #ifndef SOCI_MAX_FUSION_SEQUENCE_LENGTH #define SOCI_MAX_FUSION_SEQUENCE_LENGTH 10 #endif #include "values.h" #include "type-conversion-traits.h" // boost #include #include #include #include #include #include #include #include #endif // SOCI_BOOST_FUSION_H_INCLUDED soci-3.2.3/core/blob.cpp0000644000000000000000000000166212511361676013541 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "blob.h" #include "session.h" #include using namespace soci; blob::blob(session & s) { backEnd_ = s.make_blob_backend(); } blob::~blob() { delete backEnd_; } std::size_t blob::get_len() { return backEnd_->get_len(); } std::size_t blob::read(std::size_t offset, char *buf, std::size_t toRead) { return backEnd_->read(offset, buf, toRead); } std::size_t blob::write( std::size_t offset, char const * buf, std::size_t toWrite) { return backEnd_->write(offset, buf, toWrite); } std::size_t blob::append(char const * buf, std::size_t toWrite) { return backEnd_->append(buf, toWrite); } void blob::trim(std::size_t newLen) { backEnd_->trim(newLen); } soci-3.2.3/core/blob-exchange.h0000644000000000000000000000273212511362240014751 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_BLOB_EXCHANGE_H_INCLUDED #define SOCI_BLOB_EXCHANGE_H_INCLUDED #include "blob.h" #include "into-type.h" #include "use-type.h" // std #include namespace soci { namespace details { template <> class into_type : public standard_into_type { public: into_type(blob & b) : standard_into_type(&b, x_blob) {} into_type(blob & b, indicator & ind) : standard_into_type(&b, x_blob, ind) {} }; template <> class use_type : public standard_use_type { public: use_type(blob & b, std::string const & name = std::string()) : standard_use_type(&b, x_blob, false, name) {} use_type(blob const & b, std::string const & name = std::string()) : standard_use_type(const_cast(&b), x_blob, true, name) {} use_type(blob & b, indicator & ind, std::string const & name = std::string()) : standard_use_type(&b, x_blob, ind, false, name) {} use_type(blob const & b, indicator & ind, std::string const & name = std::string()) : standard_use_type(const_cast(&b), x_blob, ind, true, name) {} }; template <> struct exchange_traits { typedef basic_type_tag type_family; }; } // namespace details } // namespace soci #endif // SOCI_BLOB_EXCHANGE_H_INCLUDED soci-3.2.3/core/boost-optional.h0000644000000000000000000000231312511362240015217 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_BOOST_OPTIONAL_H_INCLUDED #define SOCI_BOOST_OPTIONAL_H_INCLUDED #include "type-conversion-traits.h" // boost #include namespace soci { // simple fall-back for boost::optional template struct type_conversion > { typedef typename type_conversion::base_type base_type; static void from_base(base_type const & in, indicator ind, boost::optional & out) { if (ind == i_null) { out.reset(); } else { T tmp; type_conversion::from_base(in, ind, tmp); out = tmp; } } static void to_base(boost::optional const & in, base_type & out, indicator & ind) { if (in.is_initialized()) { type_conversion::to_base(in.get(), out, ind); } else { ind = i_null; } } }; } // namespace soci #endif // SOCI_BOOST_OPTIONAL_H_INCLUDED soci-3.2.3/core/rowid-exchange.h0000644000000000000000000000304312511362240015153 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_ROWID_EXCHANGE_H_INCLUDED #define SOCI_ROWID_EXCHANGE_H_INCLUDED #include "rowid.h" #include "into-type.h" #include "use-type.h" #include "exchange-traits.h" // std #include namespace soci { namespace details { template <> class use_type : public standard_use_type { public: use_type(rowid & rid, std::string const & name = std::string()) : standard_use_type(&rid, x_rowid, false, name) {} use_type(rowid const & rid, std::string const & name = std::string()) : standard_use_type(const_cast(&rid), x_rowid, true, name) {} use_type(rowid & rid, indicator & ind, std::string const & name = std::string()) : standard_use_type(&rid, x_rowid, ind, false, name) {} use_type(rowid const & rid, indicator & ind, std::string const & name = std::string()) : standard_use_type(const_cast(&rid), x_rowid, ind, true, name) {} }; template <> class into_type : public standard_into_type { public: into_type(rowid & rid) : standard_into_type(&rid, x_rowid) {} into_type(rowid & rid, indicator & ind) :standard_into_type(&rid, x_rowid, ind) {} }; template <> struct exchange_traits { typedef basic_type_tag type_family; }; } // namespace details } // namespace soci #endif // SOCI_ROWID_EXCHANGE_H_INCLUDED soci-3.2.3/core/use-type.h0000644000000000000000000001512312511362240014024 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_USE_TYPE_H_INCLUDED #define SOCI_USE_TYPE_H_INCLUDED #include "soci-backend.h" #include "type-ptr.h" #include "exchange-traits.h" // std #include #include #include namespace soci { namespace details { class statement_impl; // this is intended to be a base class for all classes that deal with // binding input data (and OUT PL/SQL variables) class SOCI_DECL use_type_base { public: virtual ~use_type_base() {} virtual void bind(statement_impl & st, int & position) = 0; virtual void pre_use() = 0; virtual void post_use(bool gotData) = 0; virtual void clean_up() = 0; virtual std::size_t size() const = 0; // returns the number of elements }; typedef type_ptr use_type_ptr; class SOCI_DECL standard_use_type : public use_type_base { public: standard_use_type(void* data, exchange_type type, bool readOnly, std::string const& name = std::string()) : data_(data) , type_(type) , ind_(NULL) , readOnly_(readOnly) , name_(name) , backEnd_(NULL) { // FIXME: This was added with Ilia's patch // https://github.com/SOCI/soci/commit/c166625a28f7c907318134f625ff5acea7d9a1f8 // but it seems to be a troublemaker, causing duplicated conversions //convert_to_base(); } standard_use_type(void* data, exchange_type type, indicator& ind, bool readOnly, std::string const& name = std::string()) : data_(data) , type_(type) , ind_(&ind) , readOnly_(readOnly) , name_(name) , backEnd_(NULL) { // FIXME //convert_to_base(); } virtual ~standard_use_type(); virtual void bind(statement_impl & st, int & position); std::string get_name() const { return name_; } virtual void * get_data() { return data_; } // conversion hook (from arbitrary user type to base type) virtual void convert_to_base() {} virtual void convert_from_base() {} protected: virtual void pre_use(); private: virtual void post_use(bool gotData); virtual void clean_up(); virtual std::size_t size() const { return 1; } void* data_; exchange_type type_; indicator* ind_; bool readOnly_; std::string name_; standard_use_type_backend* backEnd_; }; class SOCI_DECL vector_use_type : public use_type_base { public: vector_use_type(void* data, exchange_type type, std::string const& name = std::string()) : data_(data) , type_(type) , ind_(NULL) , name_(name) , backEnd_(NULL) {} vector_use_type(void* data, exchange_type type, std::vector const& ind, std::string const& name = std::string()) : data_(data) , type_(type) , ind_(&ind) , name_(name) , backEnd_(NULL) {} ~vector_use_type(); private: virtual void bind(statement_impl& st, int & position); virtual void pre_use(); virtual void post_use(bool) { /* nothing to do */ } virtual void clean_up(); virtual std::size_t size() const; void* data_; exchange_type type_; std::vector const* ind_; std::string name_; vector_use_type_backend * backEnd_; virtual void convert_to_base() {} }; // implementation for the basic types (those which are supported by the library // out of the box without user-provided conversions) template class use_type : public standard_use_type { public: use_type(T& t, std::string const& name = std::string()) : standard_use_type(&t, static_cast(exchange_traits::x_type), false, name) {} use_type(T const& t, std::string const& name = std::string()) : standard_use_type(const_cast(&t), static_cast(exchange_traits::x_type), true, name) {} use_type(T& t, indicator& ind, std::string const& name = std::string()) : standard_use_type(&t, static_cast(exchange_traits::x_type), ind, false, name) {} use_type(T const& t, indicator& ind, std::string const& name = std::string()) : standard_use_type(const_cast(&t), static_cast(exchange_traits::x_type), ind, false, name) {} }; template class use_type > : public vector_use_type { public: use_type(std::vector& v, std::string const& name = std::string()) : vector_use_type(&v, static_cast(exchange_traits::x_type), name) {} use_type(std::vector const& v, std::string const& name = std::string()) : vector_use_type(const_cast*>(&v), static_cast(exchange_traits::x_type), name) {} use_type(std::vector& v, std::vector const& ind, std::string const& name = std::string()) : vector_use_type(&v, static_cast(exchange_traits::x_type), ind, name) {} use_type(std::vector const& v, std::vector const& ind, std::string const& name = std::string()) : vector_use_type(const_cast *>(&v), static_cast(exchange_traits::x_type), ind, name) {} }; // helper dispatchers for basic types template use_type_ptr do_use(T & t, std::string const & name, basic_type_tag) { return use_type_ptr(new use_type(t, name)); } template use_type_ptr do_use(T const & t, std::string const & name, basic_type_tag) { return use_type_ptr(new use_type(t, name)); } template use_type_ptr do_use(T & t, indicator & ind, std::string const & name, basic_type_tag) { return use_type_ptr(new use_type(t, ind, name)); } template use_type_ptr do_use(T const & t, indicator & ind, std::string const & name, basic_type_tag) { return use_type_ptr(new use_type(t, ind, name)); } template use_type_ptr do_use(T & t, std::vector & ind, std::string const & name, basic_type_tag) { return use_type_ptr(new use_type(t, ind, name)); } template use_type_ptr do_use(T const & t, std::vector & ind, std::string const & name, basic_type_tag) { return use_type_ptr(new use_type(t, ind, name)); } } // namespace details } // namesapce soci #endif // SOCI_USE_TYPE_H_INCLUDED soci-3.2.3/core/row.h0000644000000000000000000000650312511362240013062 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_ROW_H_INCLUDED #define SOCI_ROW_H_INCLUDED #include "type-holder.h" #include "soci-backend.h" #include "type-conversion.h" // std #include #include #include #include #include namespace soci { class SOCI_DECL column_properties { // use getters/setters in case we want to make some // of the getters lazy in the future public: std::string get_name() const { return name_; } data_type get_data_type() const { return dataType_; } void set_name(std::string const& name) { name_ = name; } void set_data_type(data_type dataType) { dataType_ = dataType; } private: std::string name_; data_type dataType_; }; class SOCI_DECL row { public: row(); ~row(); void uppercase_column_names(bool forceToUpper); void add_properties(column_properties const& cp); std::size_t size() const; void clean_up(); indicator get_indicator(std::size_t pos) const; indicator get_indicator(std::string const& name) const; template inline void add_holder(T* t, indicator* ind) { holders_.push_back(new details::type_holder(t)); indicators_.push_back(ind); } column_properties const& get_properties(std::size_t pos) const; column_properties const& get_properties(std::string const& name) const; template T get(std::size_t pos) const { assert(holders_.size() >= pos + 1); typedef typename type_conversion::base_type base_type; base_type const& baseVal = holders_[pos]->get(); T ret; type_conversion::from_base(baseVal, *indicators_[pos], ret); return ret; } template T get(std::size_t pos, T const &nullValue) const { assert(holders_.size() >= pos + 1); if (i_null == *indicators_[pos]) { return nullValue; } return get(pos); } template T get(std::string const &name) const { std::size_t const pos = find_column(name); return get(pos); } template T get(std::string const &name, T const &nullValue) const { std::size_t const pos = find_column(name); if (i_null == *indicators_[pos]) { return nullValue; } return get(pos); } template row const& operator>>(T& value) const { value = get(currentPos_); ++currentPos_; return *this; } void skip(std::size_t num = 1) const { currentPos_ += num; } void reset_get_counter() const { currentPos_ = 0; } private: // copy not supported row(row const &); void operator=(row const &); std::size_t find_column(std::string const& name) const; std::vector columns_; std::vector holders_; std::vector indicators_; std::map index_; bool uppercaseColumnNames_; mutable std::size_t currentPos_; }; } // namespace soci #endif // SOCI_ROW_H_INCLUDED soci-3.2.3/core/boost-gregorian-date.h0000644000000000000000000000213012511362240016257 0ustar rootroot// // Copyright (C) 2008 Maciej Sobczak // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_BOOST_GREGORIAN_DATE_H_INCLUDED #define SOCI_BOOST_GREGORIAN_DATE_H_INCLUDED #include "type-conversion-traits.h" // boost #include #include // std #include namespace soci { template<> struct type_conversion { typedef std::tm base_type; static void from_base( base_type const & in, indicator ind, boost::gregorian::date & out) { if (ind == i_null) { throw soci_error("Null value not allowed for this type"); } out = boost::gregorian::date_from_tm(in); } static void to_base( boost::gregorian::date const & in, base_type & out, indicator & ind) { out = boost::gregorian::to_tm(in); ind = i_ok; } }; } // namespace soci #endif // SOCI_BOOST_GREGORIAN_DATE_H_INCLUDED soci-3.2.3/core/connection-pool.cpp0000644000000000000000000001605412511362066015724 0ustar rootroot// // Copyright (C) 2008 Maciej Sobczak // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "connection-pool.h" #include "error.h" #include "session.h" #include #include #ifndef _WIN32 // POSIX implementation #include #include #include using namespace soci; struct connection_pool::connection_pool_impl { bool find_free(std::size_t & pos) { for (std::size_t i = 0; i != sessions_.size(); ++i) { if (sessions_[i].first) { pos = i; return true; } } return false; } // by convention, first == true means the entry is free (not used) std::vector > sessions_; pthread_mutex_t mtx_; pthread_cond_t cond_; }; connection_pool::connection_pool(std::size_t size) { if (size == 0) { throw soci_error("Invalid pool size"); } pimpl_ = new connection_pool_impl(); pimpl_->sessions_.resize(size); for (std::size_t i = 0; i != size; ++i) { pimpl_->sessions_[i] = std::make_pair(true, new session()); } int cc = pthread_mutex_init(&(pimpl_->mtx_), NULL); if (cc != 0) { throw soci_error("Synchronization error"); } cc = pthread_cond_init(&(pimpl_->cond_), NULL); if (cc != 0) { throw soci_error("Synchronization error"); } } connection_pool::~connection_pool() { for (std::size_t i = 0; i != pimpl_->sessions_.size(); ++i) { delete pimpl_->sessions_[i].second; } pthread_mutex_destroy(&(pimpl_->mtx_)); pthread_cond_destroy(&(pimpl_->cond_)); delete pimpl_; } session & connection_pool::at(std::size_t pos) { if (pos >= pimpl_->sessions_.size()) { throw soci_error("Invalid pool position"); } return *(pimpl_->sessions_[pos].second); } std::size_t connection_pool::lease() { std::size_t pos; // no timeout bool const success = try_lease(pos, -1); assert(success); return pos; } bool connection_pool::try_lease(std::size_t & pos, int timeout) { struct timespec tm; if (timeout >= 0) { // timeout is relative in milliseconds struct timeval tmv; gettimeofday(&tmv, NULL); tm.tv_sec = tmv.tv_sec + timeout / 1000; tm.tv_nsec = tmv.tv_usec * 1000 + (timeout % 1000) * 1000 * 1000; if (tm.tv_nsec >= 1000 * 1000 * 1000) { ++tm.tv_sec; tm.tv_nsec -= 1000 * 1000 * 1000; } } int cc = pthread_mutex_lock(&(pimpl_->mtx_)); if (cc != 0) { throw soci_error("Synchronization error"); } while (pimpl_->find_free(pos) == false) { if (timeout < 0) { // no timeout, allow unlimited blocking cc = pthread_cond_wait(&(pimpl_->cond_), &(pimpl_->mtx_)); } else { // wait with timeout cc = pthread_cond_timedwait( &(pimpl_->cond_), &(pimpl_->mtx_), &tm); } if (cc == ETIMEDOUT) { break; } } if (cc == 0) { pimpl_->sessions_[pos].first = false; } pthread_mutex_unlock(&(pimpl_->mtx_)); return cc == 0; } void connection_pool::give_back(std::size_t pos) { if (pos >= pimpl_->sessions_.size()) { throw soci_error("Invalid pool position"); } int cc = pthread_mutex_lock(&(pimpl_->mtx_)); if (cc != 0) { throw soci_error("Synchronization error"); } if (pimpl_->sessions_[pos].first) { pthread_mutex_unlock(&(pimpl_->mtx_)); throw soci_error("Cannot release pool entry (already free)"); } pimpl_->sessions_[pos].first = true; pthread_mutex_unlock(&(pimpl_->mtx_)); pthread_cond_signal(&(pimpl_->cond_)); } #else // Windows implementation #include using namespace soci; struct connection_pool::connection_pool_impl { bool find_free(std::size_t & pos) { for (std::size_t i = 0; i != sessions_.size(); ++i) { if (sessions_[i].first) { pos = i; return true; } } return false; } // by convention, first == true means the entry is free (not used) std::vector > sessions_; CRITICAL_SECTION mtx_; HANDLE sem_; }; connection_pool::connection_pool(std::size_t size) { if (size == 0) { throw soci_error("Invalid pool size"); } pimpl_ = new connection_pool_impl(); pimpl_->sessions_.resize(size); for (std::size_t i = 0; i != size; ++i) { pimpl_->sessions_[i] = std::make_pair(true, new session()); } InitializeCriticalSection(&(pimpl_->mtx_)); // initially all entries are available HANDLE s = CreateSemaphore(NULL, static_cast(size), static_cast(size), NULL); if (s == NULL) { throw soci_error("Synchronization error"); } pimpl_->sem_ = s; } connection_pool::~connection_pool() { for (std::size_t i = 0; i != pimpl_->sessions_.size(); ++i) { delete pimpl_->sessions_[i].second; } DeleteCriticalSection(&(pimpl_->mtx_)); CloseHandle(pimpl_->sem_); delete pimpl_; } session & connection_pool::at(std::size_t pos) { if (pos >= pimpl_->sessions_.size()) { throw soci_error("Invalid pool position"); } return *(pimpl_->sessions_[pos].second); } std::size_t connection_pool::lease() { std::size_t pos; // no timeout bool const success = try_lease(pos, -1); assert(success); if (!success) { // TODO: anything to report? --mloskot } return pos; } bool connection_pool::try_lease(std::size_t & pos, int timeout) { DWORD cc = WaitForSingleObject(pimpl_->sem_, timeout >= 0 ? static_cast(timeout) : INFINITE); if (cc == WAIT_OBJECT_0) { // semaphore acquired, there is (at least) one free entry EnterCriticalSection(&(pimpl_->mtx_)); bool const success = pimpl_->find_free(pos); assert(success); if (!success) { // TODO: anything to report? --mloskot } pimpl_->sessions_[pos].first = false; LeaveCriticalSection(&(pimpl_->mtx_)); return true; } else if (cc == WAIT_TIMEOUT) { return false; } else { throw soci_error("Synchronization error"); } } void connection_pool::give_back(std::size_t pos) { if (pos >= pimpl_->sessions_.size()) { throw soci_error("Invalid pool position"); } EnterCriticalSection(&(pimpl_->mtx_)); if (pimpl_->sessions_[pos].first) { LeaveCriticalSection(&(pimpl_->mtx_)); throw soci_error("Cannot release pool entry (already free)"); } pimpl_->sessions_[pos].first = true; LeaveCriticalSection(&(pimpl_->mtx_)); ReleaseSemaphore(pimpl_->sem_, 1, NULL); } #endif // _WIN32 soci-3.2.3/core/query_transformation.h0000644000000000000000000000264112511362240016545 0ustar rootroot// // Copyright (C) 2013 Mateusz Loskot // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_QUERY_TRANSFORMATION_H_INCLUDED #define SOCI_QUERY_TRANSFORMATION_H_INCLUDED #include "soci-config.h" #include #include namespace soci { namespace details { // Query transformation is a mechanism that enables user to apply // any string-to-string transformation to SQL statement just // before it is executed. // Transformation procedure is specified by user, // be it a function or an arbitrary type as long as it // defines operator() with the appropriate signature: // unary function takes any type converible-to std::string // and returns std::string. class query_transformation_function : public std::unary_function { public: virtual ~query_transformation_function() {} virtual result_type operator()(argument_type a) const = 0; }; template class query_transformation : public query_transformation_function { public: query_transformation(T callback) : callback_(callback) {} result_type operator()(argument_type query) const { return callback_(query); } private: T callback_; }; } // namespace details } // namespace soci #endif // SOCI_QUERY_TRANSFORMATION_H_INCLUDED soci-3.2.3/core/use.h0000644000000000000000000000417612511401146013052 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_USE_H_INCLUDED #define SOCI_USE_H_INCLUDED #include "soci-backend.h" namespace soci { namespace details { template struct use_container { use_container(T &_t, Indicator &_ind, const std::string &_name) : t(_t), ind(_ind), name(_name) {} T &t; Indicator &ind; const std::string &name; }; typedef void no_indicator; template struct use_container { use_container(T &_t, const std::string &_name) : t(_t), name(_name) {} T &t; const std::string &name; }; } // namespace details template details::use_container use(T &t, const std::string &name = std::string()) { return details::use_container(t, name); } template details::use_container use(T const &t, const std::string &name = std::string()) { return details::use_container(t, name); } template details::use_container use(T &t, indicator & ind, std::string const &name = std::string()) { return details::use_container(t, ind, name); } template details::use_container use(T const &t, indicator & ind, std::string const &name = std::string()) { return details::use_container(t, ind, name); } // vector containers template details::use_container > use(T &t, std::vector & ind, const std::string &name = std::string()) { return details::use_container >(t, ind, name); } template details::use_container, details::no_indicator > use(std::vector &t, const std::string &name = std::string()) { return details::use_container, details::no_indicator>(t, name); } } // namespace soci #endif // SOCI_USE_H_INCLUDED soci-3.2.3/core/soci-simple.h0000644000000000000000000001431312511362240014475 0ustar rootroot// // Copyright (C) 2008 Maciej Sobczak // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_SIMPLE_H_INCLUDED #define SOCI_SIMPLE_H_INCLUDED #include "soci-config.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus // session typedef void * session_handle; SOCI_DECL session_handle soci_create_session(char const * connectionString); SOCI_DECL void soci_destroy_session(session_handle s); SOCI_DECL void soci_begin(session_handle s); SOCI_DECL void soci_commit(session_handle s); SOCI_DECL void soci_rollback(session_handle s); SOCI_DECL int soci_session_state(session_handle s); SOCI_DECL char const * soci_session_error_message(session_handle s); // statement typedef void * statement_handle; SOCI_DECL statement_handle soci_create_statement(session_handle s); SOCI_DECL void soci_destroy_statement(statement_handle st); // positional bind of into elments (the functions return the position for convenience) SOCI_DECL int soci_into_string (statement_handle st); SOCI_DECL int soci_into_int (statement_handle st); SOCI_DECL int soci_into_long_long(statement_handle st); SOCI_DECL int soci_into_double (statement_handle st); SOCI_DECL int soci_into_date (statement_handle st); // vector versions SOCI_DECL int soci_into_string_v (statement_handle st); SOCI_DECL int soci_into_int_v (statement_handle st); SOCI_DECL int soci_into_long_long_v(statement_handle st); SOCI_DECL int soci_into_double_v (statement_handle st); SOCI_DECL int soci_into_date_v (statement_handle st); // positional read of into elements SOCI_DECL int soci_get_into_state (statement_handle st, int position); SOCI_DECL char const * soci_get_into_string (statement_handle st, int position); SOCI_DECL int soci_get_into_int (statement_handle st, int position); SOCI_DECL long long soci_get_into_long_long(statement_handle st, int position); SOCI_DECL double soci_get_into_double (statement_handle st, int position); SOCI_DECL char const * soci_get_into_date (statement_handle st, int position); // positional (re)size of vectors SOCI_DECL int soci_into_get_size_v(statement_handle st); SOCI_DECL void soci_into_resize_v (statement_handle st, int new_size); // positional read of vectors SOCI_DECL int soci_get_into_state_v (statement_handle st, int position, int index); SOCI_DECL char const * soci_get_into_string_v (statement_handle st, int position, int index); SOCI_DECL int soci_get_into_int_v (statement_handle st, int position, int index); SOCI_DECL long long soci_get_into_long_long_v(statement_handle st, int position, int index); SOCI_DECL double soci_get_into_double_v (statement_handle st, int position, int index); SOCI_DECL char const * soci_get_into_date_v (statement_handle st, int position, int index); // named bind of use elements SOCI_DECL void soci_use_string (statement_handle st, char const * name); SOCI_DECL void soci_use_int (statement_handle st, char const * name); SOCI_DECL void soci_use_long_long(statement_handle st, char const * name); SOCI_DECL void soci_use_double (statement_handle st, char const * name); SOCI_DECL void soci_use_date (statement_handle st, char const * name); // vector versions SOCI_DECL void soci_use_string_v (statement_handle st, char const * name); SOCI_DECL void soci_use_int_v (statement_handle st, char const * name); SOCI_DECL void soci_use_long_long_v(statement_handle st, char const * name); SOCI_DECL void soci_use_double_v (statement_handle st, char const * name); SOCI_DECL void soci_use_date_v (statement_handle st, char const * name); // named write of use elements SOCI_DECL void soci_set_use_state (statement_handle st, char const * name, int state); SOCI_DECL void soci_set_use_string (statement_handle st, char const * name, char const * val); SOCI_DECL void soci_set_use_int (statement_handle st, char const * name, int val); SOCI_DECL void soci_set_use_long_long(statement_handle st, char const * name, long long val); SOCI_DECL void soci_set_use_double (statement_handle st, char const * name, double val); SOCI_DECL void soci_set_use_date (statement_handle st, char const * name, char const * val); // positional (re)size of vectors SOCI_DECL int soci_use_get_size_v(statement_handle st); SOCI_DECL void soci_use_resize_v (statement_handle st, int new_size); // named write of use vectors SOCI_DECL void soci_set_use_state_v(statement_handle st, char const * name, int index, int state); SOCI_DECL void soci_set_use_string_v(statement_handle st, char const * name, int index, char const * val); SOCI_DECL void soci_set_use_int_v(statement_handle st, char const * name, int index, int val); SOCI_DECL void soci_set_use_long_long_v(statement_handle st, char const * name, int index, long long val); SOCI_DECL void soci_set_use_double_v(statement_handle st, char const * name, int index, double val); SOCI_DECL void soci_set_use_date_v(statement_handle st, char const * name, int index, char const * val); // named read of use elements (for modifiable use values) SOCI_DECL int soci_get_use_state (statement_handle st, char const * name); SOCI_DECL char const * soci_get_use_string (statement_handle st, char const * name); SOCI_DECL int soci_get_use_int (statement_handle st, char const * name); SOCI_DECL long long soci_get_use_long_long(statement_handle st, char const * name); SOCI_DECL double soci_get_use_double (statement_handle st, char const * name); SOCI_DECL char const * soci_get_use_date (statement_handle st, char const * name); // statement preparation and execution SOCI_DECL void soci_prepare(statement_handle st, char const * query); SOCI_DECL int soci_execute(statement_handle st, int withDataExchange); SOCI_DECL long long soci_get_affected_rows(statement_handle st); SOCI_DECL int soci_fetch(statement_handle st); SOCI_DECL int soci_got_data(statement_handle st); SOCI_DECL int soci_statement_state(statement_handle s); SOCI_DECL char const * soci_statement_error_message(statement_handle s); #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // SOCI_SIMPLE_H_INCLUDED soci-3.2.3/core/statement.cpp0000644000000000000000000004225112511401146014611 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "statement.h" #include "session.h" #include "into-type.h" #include "use-type.h" #include "values.h" #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; statement_impl::statement_impl(session & s) : session_(s), refCount_(1), row_(0), fetchSize_(1), initialFetchSize_(1), alreadyDescribed_(false) { backEnd_ = s.make_statement_backend(); } statement_impl::statement_impl(prepare_temp_type const & prep) : session_(prep.get_prepare_info()->session_), refCount_(1), row_(0), fetchSize_(1), alreadyDescribed_(false) { backEnd_ = session_.make_statement_backend(); ref_counted_prepare_info * prepInfo = prep.get_prepare_info(); // take all bind/define info intos_.swap(prepInfo->intos_); uses_.swap(prepInfo->uses_); // allocate handle alloc(); // prepare the statement query_ = prepInfo->get_query(); try { prepare(query_); } catch(...) { clean_up(); throw; } define_and_bind(); } statement_impl::~statement_impl() { clean_up(); } void statement_impl::alloc() { backEnd_->alloc(); } void statement_impl::bind(values & values) { std::size_t cnt = 0; try { for (std::vector::iterator it = values.uses_.begin(); it != values.uses_.end(); ++it) { // only bind those variables which are: // - either named and actually referenced in the statement, // - or positional std::string const& useName = (*it)->get_name(); if (useName.empty()) { // positional use element int position = static_cast(uses_.size()); (*it)->bind(*this, position); uses_.push_back(*it); indicators_.push_back(values.indicators_[cnt]); } else { // named use element - check if it is used std::string const placeholder = ":" + useName; std::size_t pos = query_.find(placeholder); while (pos != std::string::npos) { // Retrieve next char after placeholder // make sure we do not go out of range on the string const char nextChar = (pos + placeholder.size()) < query_.size() ? query_[pos + placeholder.size()] : '\0'; if (std::isalnum(nextChar)) { // We got a partial match only, // keep looking for the placeholder pos = query_.find(placeholder, pos + placeholder.size()); } else { int position = static_cast(uses_.size()); (*it)->bind(*this, position); uses_.push_back(*it); indicators_.push_back(values.indicators_[cnt]); // Ok we found it, done break; } } // In case we couldn't find the placeholder if (pos == std::string::npos) { values.add_unused(*it, values.indicators_[cnt]); } } cnt++; } } catch (...) { for (std::size_t i = ++cnt; i != values.uses_.size(); ++i) { values.add_unused(values.uses_[i], values.indicators_[i]); } throw; } } void statement_impl::clean_up() { // deallocate all bind and define objects std::size_t const isize = intos_.size(); for (std::size_t i = isize; i != 0; --i) { intos_[i - 1]->clean_up(); delete intos_[i - 1]; intos_.resize(i - 1); } std::size_t const ifrsize = intosForRow_.size(); for (std::size_t i = ifrsize; i != 0; --i) { intosForRow_[i - 1]->clean_up(); delete intosForRow_[i - 1]; intosForRow_.resize(i - 1); } std::size_t const usize = uses_.size(); for (std::size_t i = usize; i != 0; --i) { uses_[i - 1]->clean_up(); delete uses_[i - 1]; uses_.resize(i - 1); } std::size_t const indsize = indicators_.size(); for (std::size_t i = 0; i != indsize; ++i) { delete indicators_[i]; indicators_[i] = NULL; } if (backEnd_ != NULL) { backEnd_->clean_up(); delete backEnd_; backEnd_ = NULL; } } void statement_impl::prepare(std::string const & query, statement_type eType) { query_ = query; session_.log_query(query); backEnd_->prepare(query, eType); } void statement_impl::define_and_bind() { int definePosition = 1; std::size_t const isize = intos_.size(); for (std::size_t i = 0; i != isize; ++i) { intos_[i]->define(*this, definePosition); } // if there are some implicite into elements // injected by the row description process, // they should be defined in the later phase, // starting at the position where the above loop finished definePositionForRow_ = definePosition; int bindPosition = 1; std::size_t const usize = uses_.size(); for (std::size_t i = 0; i != usize; ++i) { uses_[i]->bind(*this, bindPosition); } } void statement_impl::define_for_row() { std::size_t const isize = intosForRow_.size(); for (std::size_t i = 0; i != isize; ++i) { intosForRow_[i]->define(*this, definePositionForRow_); } } void statement_impl::undefine_and_bind() { std::size_t const isize = intos_.size(); for (std::size_t i = isize; i != 0; --i) { intos_[i - 1]->clean_up(); } std::size_t const ifrsize = intosForRow_.size(); for (std::size_t i = ifrsize; i != 0; --i) { intosForRow_[i - 1]->clean_up(); } std::size_t const usize = uses_.size(); for (std::size_t i = usize; i != 0; --i) { uses_[i - 1]->clean_up(); } } bool statement_impl::execute(bool withDataExchange) { initialFetchSize_ = intos_size(); if (intos_.empty() == false && initialFetchSize_ == 0) { // this can happen only with into-vectors elements // and is not allowed when calling execute throw soci_error("Vectors of size 0 are not allowed."); } fetchSize_ = initialFetchSize_; // pre-use should be executed before inspecting the sizes of use // elements, as they can be resized in type conversion routines pre_use(); std::size_t const bindSize = uses_size(); if (bindSize > 1 && fetchSize_ > 1) { throw soci_error( "Bulk insert/update and bulk select not allowed in same query"); } // looks like a hack and it is - row description should happen // *after* the use elements were completely prepared // and *before* the into elements are touched, so that the row // description process can inject more into elements for // implicit data exchange if (row_ != NULL && alreadyDescribed_ == false) { describe(); define_for_row(); } int num = 0; if (withDataExchange) { num = 1; pre_fetch(); if (static_cast(fetchSize_) > num) { num = static_cast(fetchSize_); } if (static_cast(bindSize) > num) { num = static_cast(bindSize); } } statement_backend::exec_fetch_result res = backEnd_->execute(num); bool gotData = false; if (res == statement_backend::ef_success) { // the "success" means that the statement executed correctly // and for select statement this also means that some rows were read if (num > 0) { gotData = true; // ensure into vectors have correct size resize_intos(static_cast(num)); } } else // res == ef_no_data { // the "no data" means that the end-of-rowset condition was hit // but still some rows might have been read (the last bunch of rows) // it can also mean that the statement did not produce any results gotData = fetchSize_ > 1 ? resize_intos() : false; } if (num > 0) { post_fetch(gotData, false); } post_use(gotData); session_.set_got_data(gotData); return gotData; } long long statement_impl::get_affected_rows() { return backEnd_->get_affected_rows(); } bool statement_impl::fetch() { if (fetchSize_ == 0) { truncate_intos(); session_.set_got_data(false); return false; } bool gotData = false; // vectors might have been resized between fetches std::size_t const newFetchSize = intos_size(); if (newFetchSize > initialFetchSize_) { // this is not allowed, because most likely caused reallocation // of the vector - this would require complete re-bind throw soci_error( "Increasing the size of the output vector is not supported."); } else if (newFetchSize == 0) { session_.set_got_data(false); return false; } else { // the output vector was downsized or remains the same as before fetchSize_ = newFetchSize; } statement_backend::exec_fetch_result const res = backEnd_->fetch(static_cast(fetchSize_)); if (res == statement_backend::ef_success) { // the "success" means that some number of rows was read // and that it is not yet the end-of-rowset (there are more rows) gotData = true; // ensure into vectors have correct size resize_intos(fetchSize_); } else // res == ef_no_data { // end-of-rowset condition if (fetchSize_ > 1) { // but still the last bunch of rows might have been read gotData = resize_intos(); fetchSize_ = 0; } else { truncate_intos(); gotData = false; } } post_fetch(gotData, true); session_.set_got_data(gotData); return gotData; } std::size_t statement_impl::intos_size() { // this function does not need to take into account intosForRow_ elements, // since their sizes are always 1 (which is the same and the primary // into(row) element, which has injected them) std::size_t intos_size = 0; std::size_t const isize = intos_.size(); for (std::size_t i = 0; i != isize; ++i) { if (i==0) { intos_size = intos_[i]->size(); } else if (intos_size != intos_[i]->size()) { std::ostringstream msg; msg << "Bind variable size mismatch (into[" << static_cast(i) << "] has size " << static_cast(intos_[i]->size()) << ", into[0] has size " << static_cast(intos_size); throw soci_error(msg.str()); } } return intos_size; } std::size_t statement_impl::uses_size() { std::size_t usesSize = 0; std::size_t const usize = uses_.size(); for (std::size_t i = 0; i != usize; ++i) { if (i==0) { usesSize = uses_[i]->size(); if (usesSize == 0) { // this can happen only for vectors throw soci_error("Vectors of size 0 are not allowed."); } } else if (usesSize != uses_[i]->size()) { std::ostringstream msg; msg << "Bind variable size mismatch (use[" << static_cast(i) << "] has size " << static_cast(uses_[i]->size()) << ", use[0] has size " << static_cast(usesSize); throw soci_error(msg.str()); } } return usesSize; } bool statement_impl::resize_intos(std::size_t upperBound) { // this function does not need to take into account the intosForRow_ // elements, since they are never used for bulk operations int rows = backEnd_->get_number_of_rows(); if (rows < 0) { rows = 0; } if (upperBound != 0 && upperBound < static_cast(rows)) { rows = static_cast(upperBound); } std::size_t const isize = intos_.size(); for (std::size_t i = 0; i != isize; ++i) { intos_[i]->resize((std::size_t)rows); } return rows > 0 ? true : false; } void statement_impl::truncate_intos() { std::size_t const isize = intos_.size(); for (std::size_t i = 0; i != isize; ++i) { intos_[i]->resize(0); } } void statement_impl::pre_fetch() { std::size_t const isize = intos_.size(); for (std::size_t i = 0; i != isize; ++i) { intos_[i]->pre_fetch(); } std::size_t const ifrsize = intosForRow_.size(); for (std::size_t i = 0; i != ifrsize; ++i) { intosForRow_[i]->pre_fetch(); } } void statement_impl::pre_use() { std::size_t const usize = uses_.size(); for (std::size_t i = 0; i != usize; ++i) { uses_[i]->pre_use(); } } void statement_impl::post_fetch(bool gotData, bool calledFromFetch) { // first iterate over intosForRow_ elements, since the Row element // (which is among the intos_ elements) might depend on the // values of those implicitly injected elements std::size_t const ifrsize = intosForRow_.size(); for (std::size_t i = 0; i != ifrsize; ++i) { intosForRow_[i]->post_fetch(gotData, calledFromFetch); } std::size_t const isize = intos_.size(); for (std::size_t i = 0; i != isize; ++i) { intos_[i]->post_fetch(gotData, calledFromFetch); } } void statement_impl::post_use(bool gotData) { // iterate in reverse order here in case the first item // is an UseType (since it depends on the other UseTypes) for (std::size_t i = uses_.size(); i != 0; --i) { uses_[i-1]->post_use(gotData); } } namespace soci { namespace details { // Map data_types to stock types for dynamic result set support template<> void statement_impl::bind_into() { into_row(); } template<> void statement_impl::bind_into() { into_row(); } template<> void statement_impl::bind_into() { into_row(); } template<> void statement_impl::bind_into() { into_row(); } template<> void statement_impl::bind_into() { into_row(); } template<> void statement_impl::bind_into() { into_row(); } void statement_impl::describe() { row_->clean_up(); int const numcols = backEnd_->prepare_for_describe(); for (int i = 1; i <= numcols; ++i) { data_type dtype; std::string columnName; backEnd_->describe_column(i, dtype, columnName); column_properties props; props.set_name(columnName); props.set_data_type(dtype); switch (dtype) { case dt_string: bind_into(); break; case dt_double: bind_into(); break; case dt_integer: bind_into(); break; case dt_long_long: bind_into(); break; case dt_unsigned_long_long: bind_into(); break; case dt_date: bind_into(); break; default: std::ostringstream msg; msg << "db column type " << dtype <<" not supported for dynamic selects"<add_properties(props); } alreadyDescribed_ = true; } } // namespace details } // namespace soci void statement_impl::set_row(row * r) { if (row_ != NULL) { throw soci_error( "Only one Row element allowed in a single statement."); } row_ = r; row_->uppercase_column_names(session_.get_uppercase_column_names()); } std::string statement_impl::rewrite_for_procedure_call(std::string const & query) { return backEnd_->rewrite_for_procedure_call(query); } void statement_impl::inc_ref() { ++refCount_; } void statement_impl::dec_ref() { if (--refCount_ == 0) { delete this; } } standard_into_type_backend * statement_impl::make_into_type_backend() { return backEnd_->make_into_type_backend(); } standard_use_type_backend * statement_impl::make_use_type_backend() { return backEnd_->make_use_type_backend(); } vector_into_type_backend * statement_impl::make_vector_into_type_backend() { return backEnd_->make_vector_into_type_backend(); } vector_use_type_backend * statement_impl::make_vector_use_type_backend() { return backEnd_->make_vector_use_type_backend(); } soci-3.2.3/core/row.cpp0000644000000000000000000000461712511361676013435 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "row.h" #include #include #include #include using namespace soci; using namespace details; row::row() : uppercaseColumnNames_(false) , currentPos_(0) {} row::~row() { clean_up(); } void row::uppercase_column_names(bool forceToUpper) { uppercaseColumnNames_ = forceToUpper; } void row::add_properties(column_properties const &cp) { columns_.push_back(cp); std::string columnName; std::string const & originalName = cp.get_name(); if (uppercaseColumnNames_) { for (std::size_t i = 0; i != originalName.size(); ++i) { columnName.push_back(static_cast(std::toupper(originalName[i]))); } // rewrite the column name in the column_properties object // as well to retain consistent views columns_[columns_.size() - 1].set_name(columnName); } else { columnName = originalName; } index_[columnName] = columns_.size() - 1; } std::size_t row::size() const { return holders_.size(); } void row::clean_up() { std::size_t const hsize = holders_.size(); for (std::size_t i = 0; i != hsize; ++i) { delete holders_[i]; delete indicators_[i]; } columns_.clear(); holders_.clear(); indicators_.clear(); index_.clear(); } indicator row::get_indicator(std::size_t pos) const { assert(indicators_.size() >= static_cast(pos + 1)); return *indicators_[pos]; } indicator row::get_indicator(std::string const &name) const { return get_indicator(find_column(name)); } column_properties const & row::get_properties(std::size_t pos) const { assert(columns_.size() >= pos + 1); return columns_[pos]; } column_properties const & row::get_properties(std::string const &name) const { return get_properties(find_column(name)); } std::size_t row::find_column(std::string const &name) const { std::map::const_iterator it = index_.find(name); if (it == index_.end()) { std::ostringstream msg; msg << "Column '" << name << "' not found"; throw soci_error(msg.str()); } return it->second; } soci-3.2.3/core/connection-parameters.cpp0000644000000000000000000000316312511361676017121 0ustar rootroot// // Copyright (C) 2013 Vadim Zeitlin // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "connection-parameters.h" #include "soci-backend.h" #include "backend-loader.h" using namespace soci; namespace // anonymous { void parseConnectString(std::string const & connectString, std::string & backendName, std::string & connectionParameters) { std::string const protocolSeparator = "://"; std::string::size_type const p = connectString.find(protocolSeparator); if (p == std::string::npos) { throw soci_error("No backend name found in " + connectString); } backendName = connectString.substr(0, p); connectionParameters = connectString.substr(p + protocolSeparator.size()); } } // namespace anonymous connection_parameters::connection_parameters() : factory_(NULL) { } connection_parameters::connection_parameters(backend_factory const & factory, std::string const & connectString) : factory_(&factory), connectString_(connectString) { } connection_parameters::connection_parameters(std::string const & backendName, std::string const & connectString) : factory_(&dynamic_backends::get(backendName)), connectString_(connectString) { } connection_parameters::connection_parameters(std::string const & fullConnectString) { std::string backendName; std::string connectString; parseConnectString(fullConnectString, backendName, connectString); factory_ = &dynamic_backends::get(backendName); connectString_ = connectString; } soci-3.2.3/core/ref-counted-prepare-info.cpp0000644000000000000000000000142712511401144017403 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "ref-counted-prepare-info.h" #include "session.h" using namespace soci; using namespace soci::details; void ref_counted_prepare_info::final_action() { // deallocate all bind and define objects for (std::size_t i = intos_.size(); i > 0; --i) { delete intos_[i - 1]; intos_.resize(i - 1); } for (std::size_t i = uses_.size(); i > 0; --i) { delete uses_[i - 1]; uses_.resize(i - 1); } } std::string ref_counted_prepare_info::get_query() const { return session_.get_query(); } soci-3.2.3/core/type-ptr.h0000644000000000000000000000115512511362240014035 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_TYPE_PTR_H_INCLUDED #define SOCI_TYPE_PTR_H_INCLUDED namespace soci { namespace details { template class type_ptr { public: type_ptr(T * p) : p_(p) {} ~type_ptr() { delete p_; } T * get() const { return p_; } void release() const { p_ = 0; } private: mutable T * p_; }; } // namespace details } // namespace soci #endif // SOCI_TYPE_PTR_H_INCLUDED soci-3.2.3/core/soci_backends_config.h.in0000644000000000000000000000056612505151606017004 0ustar rootroot// // Copyright (C) 2011 Alex Ott // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_BACKENDS_CONFIG_H #define SOCI_BACKENDS_CONFIG_H #define DEFAULT_BACKENDS_PATH "@CMAKE_INSTALL_PREFIX@/@LIBDIR@" #endif // SOCI_BACKENDS_CONFIG_H soci-3.2.3/core/soci-config.h0000644000000000000000000000152712511362240014454 0ustar rootroot// // Copyright (C) 2006-2008 Mateusz Loskot // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_CONFIG_H_INCLUDED #define SOCI_CONFIG_H_INCLUDED // // On Windows platform, define SOCI_DECL depending on // static or dynamic (SOCI_DLL) linkage. // // For details, see // http://www.boost.org/more/separate_compilation.html // #ifdef _WIN32 # ifdef SOCI_DLL # ifdef SOCI_SOURCE # define SOCI_DECL __declspec(dllexport) # else # define SOCI_DECL __declspec(dllimport) # endif // SOCI_SOURCE # endif // SOCI_DLL #endif // _WIN32 // // If SOCI_DECL isn't defined yet define it now #ifndef SOCI_DECL # define SOCI_DECL #endif #ifdef _MSC_VER #pragma warning(disable:4251 4275) #endif // _MSC_VER #endif // SOCI_CONFIG_H_INCLUDED soci-3.2.3/core/into-type.cpp0000644000000000000000000000373512511361676014556 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "into-type.h" #include "statement.h" using namespace soci; using namespace soci::details; standard_into_type::~standard_into_type() { delete backEnd_; } void standard_into_type::define(statement_impl & st, int & position) { backEnd_ = st.make_into_type_backend(); backEnd_->define_by_pos(position, data_, type_); } void standard_into_type::pre_fetch() { backEnd_->pre_fetch(); } void standard_into_type::post_fetch(bool gotData, bool calledFromFetch) { backEnd_->post_fetch(gotData, calledFromFetch, ind_); if (gotData) { convert_from_base(); } } void standard_into_type::clean_up() { // backEnd_ might be NULL if IntoType was used if (backEnd_ != NULL) { backEnd_->clean_up(); } } vector_into_type::~vector_into_type() { delete backEnd_; } void vector_into_type::define(statement_impl & st, int & position) { backEnd_ = st.make_vector_into_type_backend(); backEnd_->define_by_pos(position, data_, type_); } void vector_into_type::pre_fetch() { backEnd_->pre_fetch(); } void vector_into_type::post_fetch(bool gotData, bool /* calledFromFetch */) { if (indVec_ != NULL && indVec_->empty() == false) { assert(indVec_->empty() == false); backEnd_->post_fetch(gotData, &(*indVec_)[0]); } else { backEnd_->post_fetch(gotData, NULL); } if (gotData) { convert_from_base(); } } void vector_into_type::resize(std::size_t sz) { if (indVec_ != NULL) { indVec_->resize(sz); } backEnd_->resize(sz); } std::size_t vector_into_type::size() const { return backEnd_->size(); } void vector_into_type::clean_up() { if (backEnd_ != NULL) { backEnd_->clean_up(); } } soci-3.2.3/core/version.h0000644000000000000000000000172012511362240013734 0ustar rootroot// SOCI version.hpp configuration header file // // Copyright (C) 2011 Mateusz Loskot // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_VERSION_HPP #define SOCI_VERSION_HPP // // Caution, this is the only SOCI header that is guarenteed // to change with every SOCI release, including this header // will cause a recompile every time a new SOCI version is // released. // // SOCI_VERSION % 100 is the patch level // SOCI_VERSION / 100 % 1000 is the minor version // SOCI_VERSION / 100000 is the major version #define SOCI_VERSION 300203 // // SOCI_LIB_VERSION must be defined to be the same as SOCI_VERSION // but as a *string* in the form "x_y[_z]" where x is the major version // number, y is the minor version number, and z is the patch level if not 0. #define SOCI_LIB_VERSION "3_2_3" #endif // SOCI_VERSION_HPP soci-3.2.3/core/.gitignore0000644000000000000000000000003212505151606014066 0ustar rootroot*.o *.la *.lo .deps .libs soci-3.2.3/core/session.cpp0000644000000000000000000002023012511361676014276 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "session.h" #include "connection-parameters.h" #include "connection-pool.h" #include "soci-backend.h" #include "query_transformation.h" #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; namespace // anonymous { void ensureConnected(session_backend * backEnd) { if (backEnd == NULL) { throw soci_error("Session is not connected."); } } } // namespace anonymous session::session() : once(this), prepare(this), query_transformation_(NULL), logStream_(NULL), uppercaseColumnNames_(false), backEnd_(NULL), isFromPool_(false), pool_(NULL) { } session::session(connection_parameters const & parameters) : once(this), prepare(this), query_transformation_(NULL), logStream_(NULL), lastConnectParameters_(parameters), uppercaseColumnNames_(false), backEnd_(NULL), isFromPool_(false), pool_(NULL) { open(lastConnectParameters_); } session::session(backend_factory const & factory, std::string const & connectString) : once(this), prepare(this), query_transformation_(NULL), logStream_(NULL), lastConnectParameters_(factory, connectString), uppercaseColumnNames_(false), backEnd_(NULL), isFromPool_(false), pool_(NULL) { open(lastConnectParameters_); } session::session(std::string const & backendName, std::string const & connectString) : once(this), prepare(this), query_transformation_(NULL), logStream_(NULL), lastConnectParameters_(backendName, connectString), uppercaseColumnNames_(false), backEnd_(NULL), isFromPool_(false), pool_(NULL) { open(lastConnectParameters_); } session::session(std::string const & connectString) : once(this), prepare(this), query_transformation_(NULL), logStream_(NULL), lastConnectParameters_(connectString), uppercaseColumnNames_(false), backEnd_(NULL), isFromPool_(false), pool_(NULL) { open(lastConnectParameters_); } session::session(connection_pool & pool) : query_transformation_(NULL), logStream_(NULL), isFromPool_(true), pool_(&pool) { poolPosition_ = pool.lease(); session & pooledSession = pool.at(poolPosition_); once.set_session(&pooledSession); prepare.set_session(&pooledSession); backEnd_ = pooledSession.get_backend(); } session::~session() { if (isFromPool_) { pool_->give_back(poolPosition_); } else { delete query_transformation_; delete backEnd_; } } void session::open(connection_parameters const & parameters) { if (isFromPool_) { pool_->at(poolPosition_).open(parameters); } else { if (backEnd_ != NULL) { throw soci_error("Cannot open already connected session."); } backend_factory const * const factory = parameters.get_factory(); if (factory == NULL) { throw soci_error("Cannot connect without a valid backend."); } backEnd_ = factory->make_session(parameters); lastConnectParameters_ = parameters; } } void session::open(backend_factory const & factory, std::string const & connectString) { open(connection_parameters(factory, connectString)); } void session::open(std::string const & backendName, std::string const & connectString) { open(connection_parameters(backendName, connectString)); } void session::open(std::string const & connectString) { open(connection_parameters(connectString)); } void session::close() { if (isFromPool_) { pool_->at(poolPosition_).close(); backEnd_ = NULL; } else { delete backEnd_; backEnd_ = NULL; } } void session::reconnect() { if (isFromPool_) { pool_->at(poolPosition_).reconnect(); backEnd_ = pool_->at(poolPosition_).get_backend(); } else { backend_factory const * const lastFactory = lastConnectParameters_.get_factory(); if (lastFactory == NULL) { throw soci_error("Cannot reconnect without previous connection."); } if (backEnd_ != NULL) { close(); } backEnd_ = lastFactory->make_session(lastConnectParameters_); } } void session::begin() { ensureConnected(backEnd_); backEnd_->begin(); } void session::commit() { ensureConnected(backEnd_); backEnd_->commit(); } void session::rollback() { ensureConnected(backEnd_); backEnd_->rollback(); } std::ostringstream & session::get_query_stream() { if (isFromPool_) { return pool_->at(poolPosition_).get_query_stream(); } else { return query_stream_; } } std::string session::get_query() const { if (isFromPool_) { return pool_->at(poolPosition_).get_query(); } else { // preserve logical constness of get_query, // stream used as read-only here, session* pthis = const_cast(this); // sole place where any user-defined query transformation is applied if (query_transformation_) { return (*query_transformation_)(pthis->get_query_stream().str()); } return pthis->get_query_stream().str(); } } void session::set_query_transformation_( std::auto_ptr qtf) { if (isFromPool_) { pool_->at(poolPosition_).set_query_transformation_(qtf); } else { delete query_transformation_; query_transformation_= qtf.release(); } } void session::set_log_stream(std::ostream * s) { if (isFromPool_) { pool_->at(poolPosition_).set_log_stream(s); } else { logStream_ = s; } } std::ostream * session::get_log_stream() const { if (isFromPool_) { return pool_->at(poolPosition_).get_log_stream(); } else { return logStream_; } } void session::log_query(std::string const & query) { if (isFromPool_) { pool_->at(poolPosition_).log_query(query); } else { if (logStream_ != NULL) { *logStream_ << query << '\n'; } lastQuery_ = query; } } std::string session::get_last_query() const { if (isFromPool_) { return pool_->at(poolPosition_).get_last_query(); } else { return lastQuery_; } } void session::set_got_data(bool gotData) { if (isFromPool_) { pool_->at(poolPosition_).set_got_data(gotData); } else { gotData_ = gotData; } } bool session::got_data() const { if (isFromPool_) { return pool_->at(poolPosition_).got_data(); } else { return gotData_; } } void session::uppercase_column_names(bool forceToUpper) { if (isFromPool_) { pool_->at(poolPosition_).uppercase_column_names(forceToUpper); } else { uppercaseColumnNames_ = forceToUpper; } } bool session::get_uppercase_column_names() const { if (isFromPool_) { return pool_->at(poolPosition_).get_uppercase_column_names(); } else { return uppercaseColumnNames_; } } bool session::get_next_sequence_value(std::string const & sequence, long & value) { ensureConnected(backEnd_); return backEnd_->get_next_sequence_value(*this, sequence, value); } bool session::get_last_insert_id(std::string const & sequence, long & value) { ensureConnected(backEnd_); return backEnd_->get_last_insert_id(*this, sequence, value); } std::string session::get_backend_name() const { ensureConnected(backEnd_); return backEnd_->get_backend_name(); } statement_backend * session::make_statement_backend() { ensureConnected(backEnd_); return backEnd_->make_statement_backend(); } rowid_backend * session::make_rowid_backend() { ensureConnected(backEnd_); return backEnd_->make_rowid_backend(); } blob_backend * session::make_blob_backend() { ensureConnected(backEnd_); return backEnd_->make_blob_backend(); } soci-3.2.3/core/Makefile.basic0000644000000000000000000000403212511361676014631 0ustar rootrootCOMPILER = g++ CXXFLAGS = -Wall -pedantic -Wno-long-long INCLUDEDIRS = BACKENDLOADERDEFS = -DSOCI_LIB_PREFIX=\"libsoci_\" -DSOCI_LIB_SUFFIX=\".so\" OBJS = session.o statement.o row.o values.o \ into-type.o use-type.o \ blob.o rowid.o procedure.o ref-counted-prepare-info.o ref-counted-statement.o \ once-temp-type.o prepare-temp-type.o error.o transaction.o backend-loader.o \ connection-pool.o soci-simple.o libsoci_core.a : ${OBJS} ar rv $@ $? rm *.o shared : ${OBJS} ${COMPILER} -fPIC -c $? ${CXXFLAGS} ${INCLUDEDIRS} ${COMPILER} -shared -o libsoci_core.so ${OBJS} rm *.o session.o : session.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} statement.o : statement.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} row.o : row.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} values.o : values.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} into-type.o : into-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} use-type.o : use-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} blob.o : blob.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} error.o : error.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} rowid.o : rowid.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} procedure.o : procedure.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} ref-counted-prepare-info.o : ref-counted-prepare-info.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} ref-counted-statement.o : ref-counted-statement.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} once-temp-type.o : once-temp-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} prepare-temp-type.o : prepare-temp-type.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} transaction.o : transaction.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} backend-loader.o : backend-loader.cpp ${COMPILER} -c $? ${CXXFLAGS} ${BACKENDLOADERDEFS} ${INCLUDEDIRS} connection-pool.o : connection-pool.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} soci-simple.o : soci-simple.cpp ${COMPILER} -c $? ${CXXFLAGS} ${INCLUDEDIRS} clean : rm -f libsoci_core.a libsoci_core.so soci-3.2.3/core/boost-tuple.h0000644000000000000000000000074012511401144014522 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_BOOST_TUPLE_H_INCLUDED #define SOCI_BOOST_TUPLE_H_INCLUDED #include "values.h" #include "type-conversion-traits.h" // boost #include #include #endif // SOCI_BOOST_TUPLE_H_INCLUDED soci-3.2.3/core/values-exchange.h0000644000000000000000000000462712511362240015337 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_VALUES_EXCHANGE_H_INCLUDED #define SOCI_VALUES_EXCHANGE_H_INCLUDED #include "values.h" #include "into-type.h" #include "use-type.h" #include "row-exchange.h" // std #include #include #include namespace soci { namespace details { template <> struct exchange_traits { typedef basic_type_tag type_family; // dummy value to satisfy the template engine, never used enum { x_type = 0 }; }; template <> class use_type : public use_type_base { public: use_type(values & v, std::string const & /*name*/ = std::string()) : v_(v) {} // we ignore the possibility to have the whole values as NULL use_type(values & v, indicator /*ind*/, std::string const & /*name*/ = std::string()) : v_(v) {} virtual void bind(details::statement_impl & st, int & /*position*/) { v_.uppercase_column_names(st.session_.get_uppercase_column_names()); convert_to_base(); st.bind(v_); } virtual void post_use(bool /*gotData*/) { v_.reset_get_counter(); convert_from_base(); } virtual void pre_use() {convert_to_base();} virtual void clean_up() {v_.clean_up();} virtual std::size_t size() const { return 1; } // these are used only to re-dispatch to derived class // (the derived class might be generated automatically by // user conversions) virtual void convert_to_base() {} virtual void convert_from_base() {} private: values & v_; }; // this is not supposed to be used - no support for bulk ORM template <> class use_type > { private: use_type(); }; template <> class into_type : public into_type { public: into_type(values & v) : into_type(v.get_row()), v_(v) {} into_type(values & v, indicator & ind) : into_type(v.get_row(), ind), v_(v) {} void clean_up() { v_.clean_up(); } private: values & v_; }; // this is not supposed to be used - no support for bulk ORM template <> class into_type > { private: into_type(); }; } // namespace details } // namespace soci #endif // SOCI_VALUES_EXCHANGE_H_INCLUDED soci-3.2.3/core/error.cpp0000644000000000000000000000056012511361676013750 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "error.h" using namespace soci; soci_error::soci_error(std::string const & msg) : std::runtime_error(msg) { } soci-3.2.3/core/soci-backend.h0000644000000000000000000001550612511362240014600 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_BACKEND_H_INCLUDED #define SOCI_BACKEND_H_INCLUDED #include "soci-config.h" #include "error.h" // std #include #include #include namespace soci { // data types, as seen by the user enum data_type { dt_string, dt_date, dt_double, dt_integer, dt_long_long, dt_unsigned_long_long }; // the enum type for indicator variables enum indicator { i_ok, i_null, i_truncated }; class session; namespace details { // data types, as used to describe exchange format enum exchange_type { x_char, x_stdstring, x_short, x_integer, x_long_long, x_unsigned_long_long, x_double, x_stdtm, x_statement, x_rowid, x_blob }; // type of statement (used for optimizing statement preparation) enum statement_type { st_one_time_query, st_repeatable_query }; // polymorphic into type backend class standard_into_type_backend { public: standard_into_type_backend() {} virtual ~standard_into_type_backend() {} virtual void define_by_pos(int& position, void* data, exchange_type type) = 0; virtual void pre_fetch() = 0; virtual void post_fetch(bool gotData, bool calledFromFetch, indicator* ind) = 0; virtual void clean_up() = 0; private: // noncopyable standard_into_type_backend(standard_into_type_backend const&); standard_into_type_backend& operator=(standard_into_type_backend const&); }; class vector_into_type_backend { public: vector_into_type_backend() {} virtual ~vector_into_type_backend() {} virtual void define_by_pos(int& position, void* data, exchange_type type) = 0; virtual void pre_fetch() = 0; virtual void post_fetch(bool gotData, indicator* ind) = 0; virtual void resize(std::size_t sz) = 0; virtual std::size_t size() = 0; virtual void clean_up() = 0; private: // noncopyable vector_into_type_backend(vector_into_type_backend const&); vector_into_type_backend& operator=(vector_into_type_backend const&); }; // polymorphic use type backend class standard_use_type_backend { public: standard_use_type_backend() {} virtual ~standard_use_type_backend() {} virtual void bind_by_pos(int& position, void* data, exchange_type type, bool readOnly) = 0; virtual void bind_by_name(std::string const& name, void* data, exchange_type type, bool readOnly) = 0; virtual void pre_use(indicator const* ind) = 0; virtual void post_use(bool gotData, indicator * ind) = 0; virtual void clean_up() = 0; private: // noncopyable standard_use_type_backend(standard_use_type_backend const&); standard_use_type_backend& operator=(standard_use_type_backend const&); }; class vector_use_type_backend { public: vector_use_type_backend() {} virtual ~vector_use_type_backend() {} virtual void bind_by_pos(int& position, void* data, exchange_type type) = 0; virtual void bind_by_name(std::string const& name, void* data, exchange_type type) = 0; virtual void pre_use(indicator const* ind) = 0; virtual std::size_t size() = 0; virtual void clean_up() = 0; private: // noncopyable vector_use_type_backend(vector_use_type_backend const&); vector_use_type_backend& operator=(vector_use_type_backend const&); }; // polymorphic statement backend class statement_backend { public: statement_backend() {} virtual ~statement_backend() {} virtual void alloc() = 0; virtual void clean_up() = 0; virtual void prepare(std::string const& query, statement_type eType) = 0; enum exec_fetch_result { ef_success, ef_no_data }; virtual exec_fetch_result execute(int number) = 0; virtual exec_fetch_result fetch(int number) = 0; virtual long long get_affected_rows() = 0; virtual int get_number_of_rows() = 0; virtual std::string rewrite_for_procedure_call(std::string const& query) = 0; virtual int prepare_for_describe() = 0; virtual void describe_column(int colNum, data_type& dtype, std::string& column_name) = 0; virtual standard_into_type_backend* make_into_type_backend() = 0; virtual standard_use_type_backend* make_use_type_backend() = 0; virtual vector_into_type_backend* make_vector_into_type_backend() = 0; virtual vector_use_type_backend* make_vector_use_type_backend() = 0; private: // noncopyable statement_backend(statement_backend const&); statement_backend& operator=(statement_backend const&); }; // polymorphic RowID backend class rowid_backend { public: virtual ~rowid_backend() {} }; // polymorphic blob backend class blob_backend { public: blob_backend() {} virtual ~blob_backend() {} virtual std::size_t get_len() = 0; virtual std::size_t read(std::size_t offset, char* buf, std::size_t toRead) = 0; virtual std::size_t write(std::size_t offset, char const* buf, std::size_t toWrite) = 0; virtual std::size_t append(char const* buf, std::size_t toWrite) = 0; virtual void trim(std::size_t newLen) = 0; private: // noncopyable blob_backend(blob_backend const&); blob_backend& operator=(blob_backend const&); }; // polymorphic session backend class session_backend { public: session_backend() {} virtual ~session_backend() {} virtual void begin() = 0; virtual void commit() = 0; virtual void rollback() = 0; // At least one of these functions is usually not implemented for any given // backend as RDBMS support either sequences or auto-generated values, so // we don't declare them as pure virtuals to avoid having to define trivial // versions of them in the derived classes. However every backend should // define at least one of them to allow the code using auto-generated values // to work. virtual bool get_next_sequence_value(session&, std::string const&, long&) { return false; } virtual bool get_last_insert_id(session&, std::string const&, long&) { return false; } virtual std::string get_backend_name() const = 0; virtual statement_backend* make_statement_backend() = 0; virtual rowid_backend* make_rowid_backend() = 0; virtual blob_backend* make_blob_backend() = 0; private: // noncopyable session_backend(session_backend const&); session_backend& operator=(session_backend const&); }; } // namespace details // simple base class for the session back-end factory class connection_parameters; class SOCI_DECL backend_factory { public: backend_factory() {} virtual ~backend_factory() {} virtual details::session_backend* make_session( connection_parameters const& parameters) const = 0; }; } // namespace soci #endif // SOCI_BACKEND_H_INCLUDED soci-3.2.3/core/once-temp-type.cpp0000644000000000000000000000176712511401144015460 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "once-temp-type.h" #include "ref-counted-statement.h" #include "session.h" using namespace soci; using namespace soci::details; once_temp_type::once_temp_type(session & s) : rcst_(new ref_counted_statement(s)) { // this is the beginning of new query s.get_query_stream().str(""); } once_temp_type::once_temp_type(once_temp_type const & o) :rcst_(o.rcst_) { rcst_->inc_ref(); } once_temp_type & once_temp_type::operator=(once_temp_type const & o) { o.rcst_->inc_ref(); rcst_->dec_ref(); rcst_ = o.rcst_; return *this; } once_temp_type::~once_temp_type() SOCI_ONCE_TEMP_TYPE_NOEXCEPT { rcst_->dec_ref(); } once_temp_type & once_temp_type::operator,(into_type_ptr const & i) { rcst_->exchange(i); return *this; } soci-3.2.3/core/transaction.h0000644000000000000000000000131312511362240014572 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_TRANSACTION_H_INCLUDED #define SOCI_TRANSACTION_H_INCLUDED #include "session.h" #include "soci-config.h" namespace soci { class SOCI_DECL transaction { public: explicit transaction(session& sql); ~transaction(); void commit(); void rollback(); private: bool handled_; session& sql_; // Disable copying transaction(transaction const& other); transaction& operator=(transaction const& other); }; } // namespace soci #endif // SOCI_TRANSACTION_H_INCLUDED soci-3.2.3/core/unsigned-types.h0000644000000000000000000000543212511362240015231 0ustar rootroot// // Copyright (C) 2010 Maciej Sobczak // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_UNSIGNED_TYPES_H_INCLUDED #define SOCI_UNSIGNED_TYPES_H_INCLUDED #include "type-conversion-traits.h" #include namespace soci { // simple fall-back for unsigned types template <> struct type_conversion { typedef long long base_type; static void from_base(base_type const & in, indicator ind, unsigned char & out) { if (ind == i_null) { throw soci_error("Null value not allowed for this type."); } const base_type max = (std::numeric_limits::max)(); const base_type min = (std::numeric_limits::min)(); if (in < min || in > max) { throw soci_error("Value outside of allowed range."); } out = static_cast(in); } static void to_base(unsigned char const & in, base_type & out, indicator & ind) { out = static_cast(in); ind = i_ok; } }; template <> struct type_conversion { typedef long long base_type; static void from_base(base_type const & in, indicator ind, unsigned short & out) { if (ind == i_null) { throw soci_error("Null value not allowed for this type."); } const long long max = (std::numeric_limits::max)(); const long long min = (std::numeric_limits::min)(); if (in < min || in > max) { throw soci_error("Value outside of allowed range."); } out = static_cast(in); } static void to_base(unsigned short const & in, base_type & out, indicator & ind) { out = static_cast(in); ind = i_ok; } }; template <> struct type_conversion { typedef long long base_type; static void from_base(base_type const & in, indicator ind, unsigned int & out) { if (ind == i_null) { throw soci_error("Null value not allowed for this type."); } const long long max = (std::numeric_limits::max)(); const long long min = (std::numeric_limits::min)(); if (in < min || in > max) { throw soci_error("Value outside of allowed range."); } out = static_cast(in); } static void to_base(unsigned int const & in, base_type & out, indicator & ind) { out = static_cast(in); ind = i_ok; } }; } // namespace soci #endif // SOCI_UNSIGNED_TYPES_H_INCLUDED soci-3.2.3/core/type-holder.h0000644000000000000000000000230512511362240014503 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_TYPE_HOLDER_H_INCLUDED #define SOCI_TYPE_HOLDER_H_INCLUDED // std #include namespace soci { namespace details { // Base class holder + derived class type_holder for storing type data // instances in a container of holder objects template class type_holder; class holder { public: holder() {} virtual ~holder() {} template T get() { type_holder* p = dynamic_cast *>(this); if (p) { return p->template value(); } else { throw std::bad_cast(); } } private: template T value(); }; template class type_holder : public holder { public: type_holder(T * t) : t_(t) {} ~type_holder() { delete t_; } template TypeValue value() const { return *t_; } private: T * t_; }; } // namespace details } // namespace soci #endif // SOCI_TYPE_HOLDER_H_INCLUDED soci-3.2.3/core/row-exchange.h0000644000000000000000000000310212511362240014632 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_INTO_ROW_H_INCLUDED #define SOCI_INTO_ROW_H_INCLUDED #include "into-type.h" #include "exchange-traits.h" #include "row.h" #include "statement.h" // std #include namespace soci { namespace details { // Support selecting into a row for dynamic queries template <> class into_type : public into_type_base // bypass the standard_into_type { public: into_type(row & r) : r_(r) {} into_type(row & r, indicator &) : r_(r) {} private: // special handling for Row virtual void define(statement_impl & st, int & /* position */) { st.set_row(&r_); // actual row description is performed // as part of the statement execute } virtual void pre_fetch() {} virtual void post_fetch(bool gotData, bool /* calledFromFetch */) { r_.reset_get_counter(); if (gotData) { // this is used only to re-dispatch to derived class, if any // (the derived class might be generated automatically by // user conversions) convert_from_base(); } } virtual void clean_up() {} virtual std::size_t size() const { return 1; } virtual void convert_from_base() {} row & r_; }; template <> struct exchange_traits { typedef basic_type_tag type_family; }; } // namespace details } // namespace soci #endif soci-3.2.3/core/test/0000755000000000000000000000000012511401146013054 5ustar rootrootsoci-3.2.3/core/test/common-tests.h0000644000000000000000000035126312511401146015667 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_COMMON_TESTS_H_INCLUDED #define SOCI_COMMON_TESTS_H_INCLUDED #include "soci.h" #include "soci-config.h" #ifdef HAVE_BOOST // explicitly pull conversions for Boost's optional, tuple and fusion: #include #include #include #include #if defined(BOOST_VERSION) && BOOST_VERSION >= 103500 #include #include #endif // BOOST_VERSION #endif // HAVE_BOOST #include #include #include #include #include #include // Objects used later in tests 14,15 struct PhonebookEntry { std::string name; std::string phone; }; struct PhonebookEntry2 : public PhonebookEntry { }; class PhonebookEntry3 { public: void setName(std::string const & n) { name_ = n; } std::string getName() const { return name_; } void setPhone(std::string const & p) { phone_ = p; } std::string getPhone() const { return phone_; } public: std::string name_; std::string phone_; }; // user-defined object for test26 and test28 class MyInt { public: MyInt() {} MyInt(int i) : i_(i) {} void set(int i) { i_ = i; } int get() const { return i_; } private: int i_; }; namespace soci { // basic type conversion for user-defined type with single base value template<> struct type_conversion { typedef int base_type; static void from_base(int i, indicator ind, MyInt &mi) { if (ind == i_ok) { mi.set(i); } } static void to_base(MyInt const &mi, int &i, indicator &ind) { i = mi.get(); ind = i_ok; } }; // basic type conversion on many values (ORM) template<> struct type_conversion { typedef soci::values base_type; static void from_base(values const &v, indicator /* ind */, PhonebookEntry &pe) { // here we ignore the possibility the the whole object might be NULL pe.name = v.get("NAME"); pe.phone = v.get("PHONE", ""); } static void to_base(PhonebookEntry const &pe, values &v, indicator &ind) { v.set("NAME", pe.name); v.set("PHONE", pe.phone, pe.phone.empty() ? i_null : i_ok); ind = i_ok; } }; // type conversion which directly calls values::get_indicator() template<> struct type_conversion { typedef soci::values base_type; static void from_base(values const &v, indicator /* ind */, PhonebookEntry2 &pe) { // here we ignore the possibility the the whole object might be NULL pe.name = v.get("NAME"); indicator ind = v.get_indicator("PHONE"); //another way to test for null pe.phone = ind == i_null ? "" : v.get("PHONE"); } static void to_base(PhonebookEntry2 const &pe, values &v, indicator &ind) { v.set("NAME", pe.name); v.set("PHONE", pe.phone, pe.phone.empty() ? i_null : i_ok); ind = i_ok; } }; template<> struct type_conversion { typedef soci::values base_type; static void from_base(values const &v, indicator /* ind */, PhonebookEntry3 &pe) { // here we ignore the possibility the the whole object might be NULL pe.setName(v.get("NAME")); pe.setPhone(v.get("PHONE", "")); } static void to_base(PhonebookEntry3 const &pe, values &v, indicator &ind) { v.set("NAME", pe.getName()); v.set("PHONE", pe.getPhone(), pe.getPhone().empty() ? i_null : i_ok); ind = i_ok; } }; } // namespace soci namespace soci { namespace tests { // ensure connection is checked, no crash occurs #define SOCI_TEST_ENSURE_CONNECTED(sql, method) { \ std::string msg; \ try { \ (sql.method)(); \ assert(!"exception expected"); \ } catch (soci_error const &e) { msg = e.what(); } \ assert(msg.empty() == false); } (void)sql #define SOCI_TEST_ENSURE_CONNECTED2(sql, method) { \ std::string msg; \ try { std::string seq; long v(0); \ (sql.method)(seq, v); \ assert(!"exception expected"); \ } catch (soci_error const &e) { msg = e.what(); } \ assert(msg.empty() == false); } (void)sql inline bool equal_approx(double const a, double const b) { // The formula taken from CATCH test framework // https://github.com/philsquared/Catch/ // Thanks to Richard Harris for his help refining this formula double const epsilon(std::numeric_limits::epsilon() * 100); double const scale(1.0); return std::fabs(a - b) < epsilon * (scale + (std::max)(std::fabs(a), std::fabs(b))); } // TODO: improve cleanup capabilities by subtypes, soci_test name may be omitted --mloskot // i.e. optional ctor param accepting custom table name class table_creator_base { public: table_creator_base(session& sql) : msession(sql) { drop(); } virtual ~table_creator_base() { drop();} private: void drop() { try { msession << "drop table soci_test"; } catch (soci_error const& e) { //std::cerr << e.what() << std::endl; e.what(); } } session& msession; }; class procedure_creator_base { public: procedure_creator_base(session& sql) : msession(sql) { drop(); } virtual ~procedure_creator_base() { drop();} private: void drop() { try { msession << "drop procedure soci_test"; } catch (soci_error&) {} } session& msession; }; class function_creator_base { public: function_creator_base(session& sql) : msession(sql) { drop(); } virtual ~function_creator_base() { drop();} protected: virtual std::string dropstatement() { return "drop function soci_test"; } private: void drop() { try { msession << dropstatement(); } catch (soci_error&) {} } session& msession; }; class test_context_base { public: test_context_base(backend_factory const &backEnd, std::string const &connectString) : backEndFactory_(backEnd), connectString_(connectString) {} backend_factory const & get_backend_factory() const { return backEndFactory_; } std::string get_connect_string() const { return connectString_; } virtual std::string to_date_time(std::string const &dateTime) const = 0; virtual table_creator_base* table_creator_1(session&) const = 0; virtual table_creator_base* table_creator_2(session&) const = 0; virtual table_creator_base* table_creator_3(session&) const = 0; virtual table_creator_base* table_creator_4(session&) const = 0; virtual ~test_context_base() {} // quiet the compiler private: backend_factory const &backEndFactory_; std::string const connectString_; }; class common_tests { public: common_tests(test_context_base const &tc) : tc_(tc), backEndFactory_(tc.get_backend_factory()), connectString_(tc.get_connect_string()) {} void run(bool dbSupportsTransactions = true) { std::cout<<"\nSOCI Common Tests:\n\n"; test0(); test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); if (dbSupportsTransactions) { test10(); } else { std::cout<<"skipping test 10 (database doesn't support transactions)\n"; } test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test_get_affected_rows(); test_query_transformation(); test_query_transformation_with_connection_pool(); test_pull5(); test_issue67(); test_prepared_insert_with_orm_type(); test_issue154(); test_placeholder_partial_matching_with_orm_type(); } private: test_context_base const & tc_; backend_factory const &backEndFactory_; std::string const connectString_; typedef std::auto_ptr auto_table_creator; void test0() { { soci::session sql; // no connection SOCI_TEST_ENSURE_CONNECTED(sql, begin); SOCI_TEST_ENSURE_CONNECTED(sql, commit); SOCI_TEST_ENSURE_CONNECTED(sql, rollback); SOCI_TEST_ENSURE_CONNECTED(sql, get_backend_name); SOCI_TEST_ENSURE_CONNECTED(sql, make_statement_backend); SOCI_TEST_ENSURE_CONNECTED(sql, make_rowid_backend); SOCI_TEST_ENSURE_CONNECTED(sql, make_blob_backend); SOCI_TEST_ENSURE_CONNECTED2(sql, get_next_sequence_value); SOCI_TEST_ENSURE_CONNECTED2(sql, get_last_insert_id); } std::cout << "test 0 passed\n"; } void test1() { session sql(backEndFactory_, connectString_); auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::string msg; try { // expected error sql << "drop table soci_test_nosuchtable"; assert(false); } catch (soci_error const &e) { msg = e.what(); } assert(msg.empty() == false); sql << "insert into soci_test (id) values (" << 123 << ")"; int id; sql << "select id from soci_test", into(id); assert(id == 123); std::cout << "test 1 passed\n"; } // "into" tests, type conversions, etc. void test2() { { session sql(backEndFactory_, connectString_); { auto_table_creator tableCreator(tc_.table_creator_1(sql)); char c('a'); sql << "insert into soci_test(c) values(:c)", use(c); sql << "select c from soci_test", into(c); assert(c == 'a'); } { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::string helloSOCI("Hello, SOCI!"); sql << "insert into soci_test(str) values(:s)", use(helloSOCI); std::string str; sql << "select str from soci_test", into(str); assert(str == "Hello, SOCI!"); } { auto_table_creator tableCreator(tc_.table_creator_1(sql)); short three(3); sql << "insert into soci_test(sh) values(:id)", use(three); short sh(0); sql << "select sh from soci_test", into(sh); assert(sh == 3); } { auto_table_creator tableCreator(tc_.table_creator_1(sql)); int five(5); sql << "insert into soci_test(id) values(:id)", use(five); int i(0); sql << "select id from soci_test", into(i); assert(i == 5); } { auto_table_creator tableCreator(tc_.table_creator_1(sql)); unsigned long seven(7); sql << "insert into soci_test(ul) values(:ul)", use(seven); unsigned long ul(0); sql << "select ul from soci_test", into(ul); assert(ul == 7); } { auto_table_creator tableCreator(tc_.table_creator_1(sql)); double pi(3.14159265); sql << "insert into soci_test(d) values(:d)", use(pi); double d(0.0); sql << "select d from soci_test", into(d); assert(equal_approx(d, 3.14159265)); } { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::tm nov15; nov15.tm_year = 105; nov15.tm_mon = 10; nov15.tm_mday = 15; nov15.tm_hour = 0; nov15.tm_min = 0; nov15.tm_sec = 0; sql << "insert into soci_test(tm) values(:tm)", use(nov15); std::tm t; sql << "select tm from soci_test", into(t); assert(t.tm_year == 105); assert(t.tm_mon == 10); assert(t.tm_mday == 15); assert(t.tm_hour == 0); assert(t.tm_min == 0); assert(t.tm_sec == 0); } { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::tm nov15; nov15.tm_year = 105; nov15.tm_mon = 10; nov15.tm_mday = 15; nov15.tm_hour = 22; nov15.tm_min = 14; nov15.tm_sec = 17; sql << "insert into soci_test(tm) values(:tm)", use(nov15); std::tm t; sql << "select tm from soci_test", into(t); assert(t.tm_year == 105); assert(t.tm_mon == 10); assert(t.tm_mday == 15); assert(t.tm_hour == 22); assert(t.tm_min == 14); assert(t.tm_sec == 17); } // test indicators { auto_table_creator tableCreator(tc_.table_creator_1(sql)); int id(1); std::string str("Hello"); sql << "insert into soci_test(id, str) values(:id, :str)", use(id), use(str); int i; indicator ind; sql << "select id from soci_test", into(i, ind); assert(ind == i_ok); } // more indicator tests, NULL values { auto_table_creator tableCreator(tc_.table_creator_1(sql)); sql << "insert into soci_test(id,tm) values(NULL,NULL)"; int i; indicator ind; sql << "select id from soci_test", into(i, ind); assert(ind == i_null); // additional test for NULL with std::tm std::tm t; sql << "select tm from soci_test", into(t, ind); assert(ind == i_null); try { // expect error sql << "select id from soci_test", into(i); assert(false); } catch (soci_error const &e) { std::string error = e.what(); assert(error == "Null value fetched and no indicator defined."); } sql << "select id from soci_test where id = 1000", into(i, ind); assert(sql.got_data() == false); // no data expected sql << "select id from soci_test where id = 1000", into(i); assert(sql.got_data() == false); // no data expected, test correct behaviour with use int id = 1000; sql << "select id from soci_test where id = :id", use(id), into(i); assert(sql.got_data() == false); } } std::cout << "test 2 passed" << std::endl; } // repeated fetch and bulk fetch void test3() { { session sql(backEndFactory_, connectString_); // repeated fetch and bulk fetch of char { // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); char c; for (c = 'a'; c <= 'z'; ++c) { sql << "insert into soci_test(c) values(\'" << c << "\')"; } int count; sql << "select count(*) from soci_test", into(count); assert(count == 'z' - 'a' + 1); { char c2 = 'a'; statement st = (sql.prepare << "select c from soci_test order by c", into(c)); st.execute(); while (st.fetch()) { assert(c == c2); ++c2; } assert(c2 == 'a' + count); } { char c2 = 'a'; std::vector vec(10); statement st = (sql.prepare << "select c from soci_test order by c", into(vec)); st.execute(); while (st.fetch()) { for (std::size_t i = 0; i != vec.size(); ++i) { assert(c2 == vec[i]); ++c2; } vec.resize(10); } assert(c2 == 'a' + count); } { // verify an exception is thrown when empty vector is used std::vector vec; try { sql << "select c from soci_test", into(vec); assert(false); } catch (soci_error const &e) { std::string msg = e.what(); assert(msg == "Vectors of size 0 are not allowed."); } } } // repeated fetch and bulk fetch of std::string { // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); int const rowsToTest = 10; for (int i = 0; i != rowsToTest; ++i) { std::ostringstream ss; ss << "Hello_" << i; sql << "insert into soci_test(str) values(\'" << ss.str() << "\')"; } int count; sql << "select count(*) from soci_test", into(count); assert(count == rowsToTest); { int i = 0; std::string s; statement st = (sql.prepare << "select str from soci_test order by str", into(s)); st.execute(); while (st.fetch()) { std::ostringstream ss; ss << "Hello_" << i; assert(s == ss.str()); ++i; } assert(i == rowsToTest); } { int i = 0; std::vector vec(4); statement st = (sql.prepare << "select str from soci_test order by str", into(vec)); st.execute(); while (st.fetch()) { for (std::size_t j = 0; j != vec.size(); ++j) { std::ostringstream ss; ss << "Hello_" << i; assert(ss.str() == vec[j]); ++i; } vec.resize(4); } assert(i == rowsToTest); } } // repeated fetch and bulk fetch of short { // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); short const rowsToTest = 100; short sh; for (sh = 0; sh != rowsToTest; ++sh) { sql << "insert into soci_test(sh) values(" << sh << ")"; } int count; sql << "select count(*) from soci_test", into(count); assert(count == rowsToTest); { short sh2 = 0; statement st = (sql.prepare << "select sh from soci_test order by sh", into(sh)); st.execute(); while (st.fetch()) { assert(sh == sh2); ++sh2; } assert(sh2 == rowsToTest); } { short sh2 = 0; std::vector vec(8); statement st = (sql.prepare << "select sh from soci_test order by sh", into(vec)); st.execute(); while (st.fetch()) { for (std::size_t i = 0; i != vec.size(); ++i) { assert(sh2 == vec[i]); ++sh2; } vec.resize(8); } assert(sh2 == rowsToTest); } } // repeated fetch and bulk fetch of int (4-bytes) { // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); int const rowsToTest = 100; int i; for (i = 0; i != rowsToTest; ++i) { sql << "insert into soci_test(id) values(" << i << ")"; } int count; sql << "select count(*) from soci_test", into(count); assert(count == rowsToTest); { int i2 = 0; statement st = (sql.prepare << "select id from soci_test order by id", into(i)); st.execute(); while (st.fetch()) { assert(i == i2); ++i2; } assert(i2 == rowsToTest); } { // additional test with the use element int i2 = 0; int cond = 0; // this condition is always true statement st = (sql.prepare << "select id from soci_test where id >= :cond order by id", use(cond), into(i)); st.execute(); while (st.fetch()) { assert(i == i2); ++i2; } assert(i2 == rowsToTest); } { int i2 = 0; std::vector vec(8); statement st = (sql.prepare << "select id from soci_test order by id", into(vec)); st.execute(); while (st.fetch()) { for (std::size_t i = 0; i != vec.size(); ++i) { assert(i2 == vec[i]); ++i2; } vec.resize(8); } assert(i2 == rowsToTest); } } // repeated fetch and bulk fetch of unsigned int (4-bytes) { // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); unsigned int const rowsToTest = 100; unsigned int ul; for (ul = 0; ul != rowsToTest; ++ul) { sql << "insert into soci_test(ul) values(" << ul << ")"; } int count; sql << "select count(*) from soci_test", into(count); assert(count == static_cast(rowsToTest)); { unsigned int ul2 = 0; statement st = (sql.prepare << "select ul from soci_test order by ul", into(ul)); st.execute(); while (st.fetch()) { assert(ul == ul2); ++ul2; } assert(ul2 == rowsToTest); } { unsigned int ul2 = 0; std::vector vec(8); statement st = (sql.prepare << "select ul from soci_test order by ul", into(vec)); st.execute(); while (st.fetch()) { for (std::size_t i = 0; i != vec.size(); ++i) { assert(ul2 == vec[i]); ++ul2; } vec.resize(8); } assert(ul2 == rowsToTest); } } // repeated fetch and bulk fetch of double { // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); int const rowsToTest = 100; double d = 0.0; for (int i = 0; i != rowsToTest; ++i) { sql << "insert into soci_test(d) values(" << d << ")"; d += 0.6; } int count; sql << "select count(*) from soci_test", into(count); assert(count == rowsToTest); { double d2 = 0.0; int i = 0; statement st = (sql.prepare << "select d from soci_test order by d", into(d)); st.execute(); while (st.fetch()) { assert(equal_approx(d, d2)); d2 += 0.6; ++i; } assert(i == rowsToTest); } { double d2 = 0.0; int i = 0; std::vector vec(8); statement st = (sql.prepare << "select d from soci_test order by d", into(vec)); st.execute(); while (st.fetch()) { for (std::size_t j = 0; j != vec.size(); ++j) { assert(equal_approx(d2, vec[j])); d2 += 0.6; ++i; } vec.resize(8); } assert(i == rowsToTest); } } // repeated fetch and bulk fetch of std::tm { // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); int const rowsToTest = 8; for (int i = 0; i != rowsToTest; ++i) { std::ostringstream ss; ss << 2000 + i << "-0" << 1 + i << '-' << 20 - i << ' ' << 15 + i << ':' << 50 - i << ':' << 40 + i; sql << "insert into soci_test(id, tm) values(" << i << ", " << tc_.to_date_time(ss.str()) << ")"; } int count; sql << "select count(*) from soci_test", into(count); assert(count == rowsToTest); { std::tm t; int i = 0; statement st = (sql.prepare << "select tm from soci_test order by id", into(t)); st.execute(); while (st.fetch()) { assert(t.tm_year + 1900 == 2000 + i); assert(t.tm_mon + 1 == 1 + i); assert(t.tm_mday == 20 - i); assert(t.tm_hour == 15 + i); assert(t.tm_min == 50 - i); assert(t.tm_sec == 40 + i); ++i; } assert(i == rowsToTest); } { int i = 0; std::vector vec(3); statement st = (sql.prepare << "select tm from soci_test order by id", into(vec)); st.execute(); while (st.fetch()) { for (std::size_t j = 0; j != vec.size(); ++j) { assert(vec[j].tm_year + 1900 == 2000 + i); assert(vec[j].tm_mon + 1 == 1 + i); assert(vec[j].tm_mday == 20 - i); assert(vec[j].tm_hour == 15 + i); assert(vec[j].tm_min == 50 - i); assert(vec[j].tm_sec == 40 + i); ++i; } vec.resize(3); } assert(i == rowsToTest); } } } std::cout << "test 3 passed" << std::endl; } // test for indicators (repeated fetch and bulk) void test4() { session sql(backEndFactory_, connectString_); // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); { sql << "insert into soci_test(id, val) values(1, 10)"; sql << "insert into soci_test(id, val) values(2, 11)"; sql << "insert into soci_test(id, val) values(3, NULL)"; sql << "insert into soci_test(id, val) values(4, NULL)"; sql << "insert into soci_test(id, val) values(5, 12)"; { int val; indicator ind; statement st = (sql.prepare << "select val from soci_test order by id", into(val, ind)); st.execute(); bool gotData = st.fetch(); assert(gotData); assert(ind == i_ok); assert(val == 10); gotData = st.fetch(); assert(gotData); assert(ind == i_ok); assert(val == 11); gotData = st.fetch(); assert(gotData); assert(ind == i_null); gotData = st.fetch(); assert(gotData); assert(ind == i_null); gotData = st.fetch(); assert(gotData); assert(ind == i_ok); assert(val == 12); gotData = st.fetch(); assert(gotData == false); } { std::vector vals(3); std::vector inds(3); statement st = (sql.prepare << "select val from soci_test order by id", into(vals, inds)); st.execute(); bool gotData = st.fetch(); assert(gotData); assert(vals.size() == 3); assert(inds.size() == 3); assert(inds[0] == i_ok); assert(vals[0] == 10); assert(inds[1] == i_ok); assert(vals[1] == 11); assert(inds[2] == i_null); gotData = st.fetch(); assert(gotData); assert(vals.size() == 2); assert(inds[0] == i_null); assert(inds[1] == i_ok); assert(vals[1] == 12); gotData = st.fetch(); assert(gotData == false); } // additional test for "no data" condition { std::vector vals(3); std::vector inds(3); statement st = (sql.prepare << "select val from soci_test where 0 = 1", into(vals, inds)); bool gotData = st.execute(true); assert(gotData == false); // for convenience, vectors should be truncated assert(vals.empty()); assert(inds.empty()); // for even more convenience, fetch should not fail // but just report end of rowset // (and vectors should be truncated) vals.resize(1); inds.resize(1); gotData = st.fetch(); assert(gotData == false); assert(vals.empty()); assert(inds.empty()); } // additional test for "no data" without prepared statement { std::vector vals(3); std::vector inds(3); sql << "select val from soci_test where 0 = 1", into(vals, inds); // vectors should be truncated assert(vals.empty()); assert(inds.empty()); } } std::cout << "test 4 passed" << std::endl; } // test for different sizes of data vector and indicators vector // (library should force ind. vector to have same size as data vector) void test5() { session sql(backEndFactory_, connectString_); // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); { sql << "insert into soci_test(id, val) values(1, 10)"; sql << "insert into soci_test(id, val) values(2, 11)"; sql << "insert into soci_test(id, val) values(3, NULL)"; sql << "insert into soci_test(id, val) values(4, NULL)"; sql << "insert into soci_test(id, val) values(5, 12)"; { std::vector vals(4); std::vector inds; statement st = (sql.prepare << "select val from soci_test order by id", into(vals, inds)); st.execute(); st.fetch(); assert(vals.size() == 4); assert(inds.size() == 4); vals.resize(3); st.fetch(); assert(vals.size() == 1); assert(inds.size() == 1); } } std::cout << "test 5 passed" << std::endl; } // "use" tests, type conversions, etc. void test6() { // Note: this functionality is not available with older PostgreSQL #ifndef SOCI_POSTGRESQL_NOPARAMS { session sql(backEndFactory_, connectString_); // test for char { auto_table_creator tableCreator(tc_.table_creator_1(sql)); char c('a'); sql << "insert into soci_test(c) values(:c)", use(c); c = 'b'; sql << "select c from soci_test", into(c); assert(c == 'a'); } // test for std::string { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::string s = "Hello SOCI!"; sql << "insert into soci_test(str) values(:s)", use(s); std::string str; sql << "select str from soci_test", into(str); assert(str == "Hello SOCI!"); } // test for short { auto_table_creator tableCreator(tc_.table_creator_1(sql)); short s = 123; sql << "insert into soci_test(id) values(:id)", use(s); short s2 = 0; sql << "select id from soci_test", into(s2); assert(s2 == 123); } // test for int { auto_table_creator tableCreator(tc_.table_creator_1(sql)); int i = -12345678; sql << "insert into soci_test(id) values(:i)", use(i); int i2 = 0; sql << "select id from soci_test", into(i2); assert(i2 == -12345678); } // test for unsigned long { auto_table_creator tableCreator(tc_.table_creator_1(sql)); unsigned long ul = 4000000000ul; sql << "insert into soci_test(ul) values(:num)", use(ul); unsigned long ul2 = 0; sql << "select ul from soci_test", into(ul2); assert(ul2 == 4000000000ul); } // test for double { auto_table_creator tableCreator(tc_.table_creator_1(sql)); double d = 3.14159265; sql << "insert into soci_test(d) values(:d)", use(d); double d2 = 0; sql << "select d from soci_test", into(d2); assert(equal_approx(d2, d)); } // test for std::tm { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::tm t; t.tm_year = 105; t.tm_mon = 10; t.tm_mday = 19; t.tm_hour = 21; t.tm_min = 39; t.tm_sec = 57; sql << "insert into soci_test(tm) values(:t)", use(t); std::tm t2; t2.tm_year = 0; t2.tm_mon = 0; t2.tm_mday = 0; t2.tm_hour = 0; t2.tm_min = 0; t2.tm_sec = 0; sql << "select tm from soci_test", into(t2); assert(t.tm_year == 105); assert(t.tm_mon == 10); assert(t.tm_mday == 19); assert(t.tm_hour == 21); assert(t.tm_min == 39); assert(t.tm_sec == 57); } // test for repeated use { auto_table_creator tableCreator(tc_.table_creator_1(sql)); int i; statement st = (sql.prepare << "insert into soci_test(id) values(:id)", use(i)); i = 5; st.execute(true); i = 6; st.execute(true); i = 7; st.execute(true); std::vector v(5); sql << "select id from soci_test order by id", into(v); assert(v.size() == 3); assert(v[0] == 5); assert(v[1] == 6); assert(v[2] == 7); } // tests for use of const objects // test for char { auto_table_creator tableCreator(tc_.table_creator_1(sql)); char const c('a'); sql << "insert into soci_test(c) values(:c)", use(c); char c2 = 'b'; sql << "select c from soci_test", into(c2); assert(c2 == 'a'); } // test for std::string { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::string const s = "Hello const SOCI!"; sql << "insert into soci_test(str) values(:s)", use(s); std::string str; sql << "select str from soci_test", into(str); assert(str == "Hello const SOCI!"); } // test for short { auto_table_creator tableCreator(tc_.table_creator_1(sql)); short const s = 123; sql << "insert into soci_test(id) values(:id)", use(s); short s2 = 0; sql << "select id from soci_test", into(s2); assert(s2 == 123); } // test for int { auto_table_creator tableCreator(tc_.table_creator_1(sql)); int const i = -12345678; sql << "insert into soci_test(id) values(:i)", use(i); int i2 = 0; sql << "select id from soci_test", into(i2); assert(i2 == -12345678); } // test for unsigned long { auto_table_creator tableCreator(tc_.table_creator_1(sql)); unsigned long const ul = 4000000000ul; sql << "insert into soci_test(ul) values(:num)", use(ul); unsigned long ul2 = 0; sql << "select ul from soci_test", into(ul2); assert(ul2 == 4000000000ul); } // test for double { auto_table_creator tableCreator(tc_.table_creator_1(sql)); double const d = 3.14159265; sql << "insert into soci_test(d) values(:d)", use(d); double d2 = 0; sql << "select d from soci_test", into(d2); assert(equal_approx(d2, d)); } // test for std::tm { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::tm t; t.tm_year = 105; t.tm_mon = 10; t.tm_mday = 19; t.tm_hour = 21; t.tm_min = 39; t.tm_sec = 57; std::tm const & ct = t; sql << "insert into soci_test(tm) values(:t)", use(ct); std::tm t2; t2.tm_year = 0; t2.tm_mon = 0; t2.tm_mday = 0; t2.tm_hour = 0; t2.tm_min = 0; t2.tm_sec = 0; sql << "select tm from soci_test", into(t2); assert(t.tm_year == 105); assert(t.tm_mon == 10); assert(t.tm_mday == 19); assert(t.tm_hour == 21); assert(t.tm_min == 39); assert(t.tm_sec == 57); } } std::cout << "test 6 passed" << std::endl; #endif // SOCI_POSTGRESQL_NOPARAMS } // test for multiple use (and into) elements void test7() { { session sql(backEndFactory_, connectString_); auto_table_creator tableCreator(tc_.table_creator_1(sql)); { int i1 = 5; int i2 = 6; int i3 = 7; #ifndef SOCI_POSTGRESQL_NOPARAMS sql << "insert into soci_test(i1, i2, i3) values(:i1, :i2, :i3)", use(i1), use(i2), use(i3); #else // Older PostgreSQL does not support use elements. sql << "insert into soci_test(i1, i2, i3) values(5, 6, 7)"; #endif // SOCI_POSTGRESQL_NOPARAMS i1 = 0; i2 = 0; i3 = 0; sql << "select i1, i2, i3 from soci_test", into(i1), into(i2), into(i3); assert(i1 == 5); assert(i2 == 6); assert(i3 == 7); // same for vectors sql << "delete from soci_test"; i1 = 0; i2 = 0; i3 = 0; #ifndef SOCI_POSTGRESQL_NOPARAMS statement st = (sql.prepare << "insert into soci_test(i1, i2, i3) values(:i1, :i2, :i3)", use(i1), use(i2), use(i3)); i1 = 1; i2 = 2; i3 = 3; st.execute(true); i1 = 4; i2 = 5; i3 = 6; st.execute(true); i1 = 7; i2 = 8; i3 = 9; st.execute(true); #else // Older PostgreSQL does not support use elements. sql << "insert into soci_test(i1, i2, i3) values(1, 2, 3)"; sql << "insert into soci_test(i1, i2, i3) values(4, 5, 6)"; sql << "insert into soci_test(i1, i2, i3) values(7, 8, 9)"; #endif // SOCI_POSTGRESQL_NOPARAMS std::vector v1(5); std::vector v2(5); std::vector v3(5); sql << "select i1, i2, i3 from soci_test order by i1", into(v1), into(v2), into(v3); assert(v1.size() == 3); assert(v2.size() == 3); assert(v3.size() == 3); assert(v1[0] == 1); assert(v1[1] == 4); assert(v1[2] == 7); assert(v2[0] == 2); assert(v2[1] == 5); assert(v2[2] == 8); assert(v3[0] == 3); assert(v3[1] == 6); assert(v3[2] == 9); } } std::cout << "test 7 passed" << std::endl; } // use vector elements void test8() { // Not supported with older PostgreSQL #ifndef SOCI_POSTGRESQL_NOPARAMS { session sql(backEndFactory_, connectString_); // test for char { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::vector v; v.push_back('a'); v.push_back('b'); v.push_back('c'); v.push_back('d'); sql << "insert into soci_test(c) values(:c)", use(v); std::vector v2(4); sql << "select c from soci_test order by c", into(v2); assert(v2.size() == 4); assert(v2[0] == 'a'); assert(v2[1] == 'b'); assert(v2[2] == 'c'); assert(v2[3] == 'd'); } // test for std::string { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::vector v; v.push_back("ala"); v.push_back("ma"); v.push_back("kota"); sql << "insert into soci_test(str) values(:s)", use(v); std::vector v2(4); sql << "select str from soci_test order by str", into(v2); assert(v2.size() == 3); assert(v2[0] == "ala"); assert(v2[1] == "kota"); assert(v2[2] == "ma"); } // test for short { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::vector v; v.push_back(-5); v.push_back(6); v.push_back(7); v.push_back(123); sql << "insert into soci_test(sh) values(:sh)", use(v); std::vector v2(4); sql << "select sh from soci_test order by sh", into(v2); assert(v2.size() == 4); assert(v2[0] == -5); assert(v2[1] == 6); assert(v2[2] == 7); assert(v2[3] == 123); } // test for int { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::vector v; v.push_back(-2000000000); v.push_back(0); v.push_back(1); v.push_back(2000000000); sql << "insert into soci_test(id) values(:i)", use(v); std::vector v2(4); sql << "select id from soci_test order by id", into(v2); assert(v2.size() == 4); assert(v2[0] == -2000000000); assert(v2[1] == 0); assert(v2[2] == 1); assert(v2[3] == 2000000000); } // test for unsigned int { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::vector v; v.push_back(0); v.push_back(1); v.push_back(123); v.push_back(1000); sql << "insert into soci_test(ul) values(:ul)", use(v); std::vector v2(4); sql << "select ul from soci_test order by ul", into(v2); assert(v2.size() == 4); assert(v2[0] == 0); assert(v2[1] == 1); assert(v2[2] == 123); assert(v2[3] == 1000); } // test for double { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::vector v; v.push_back(0); v.push_back(-0.0001); v.push_back(0.0001); v.push_back(3.1415926); sql << "insert into soci_test(d) values(:d)", use(v); std::vector v2(4); sql << "select d from soci_test order by d", into(v2); assert(v2.size() == 4); assert(equal_approx(v2[0],-0.0001)); assert(equal_approx(v2[1], 0)); assert(equal_approx(v2[2], 0.0001)); assert(equal_approx(v2[3], 3.1415926)); } // test for std::tm { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::vector v; std::tm t; t.tm_year = 105; t.tm_mon = 10; t.tm_mday = 26; t.tm_hour = 22; t.tm_min = 45; t.tm_sec = 17; v.push_back(t); t.tm_sec = 37; v.push_back(t); t.tm_mday = 25; v.push_back(t); sql << "insert into soci_test(tm) values(:t)", use(v); std::vector v2(4); sql << "select tm from soci_test order by tm", into(v2); assert(v2.size() == 3); assert(v2[0].tm_year == 105); assert(v2[0].tm_mon == 10); assert(v2[0].tm_mday == 25); assert(v2[0].tm_hour == 22); assert(v2[0].tm_min == 45); assert(v2[0].tm_sec == 37); assert(v2[1].tm_year == 105); assert(v2[1].tm_mon == 10); assert(v2[1].tm_mday == 26); assert(v2[1].tm_hour == 22); assert(v2[1].tm_min == 45); assert(v2[1].tm_sec == 17); assert(v2[2].tm_year == 105); assert(v2[2].tm_mon == 10); assert(v2[2].tm_mday == 26); assert(v2[2].tm_hour == 22); assert(v2[2].tm_min == 45); assert(v2[2].tm_sec == 37); } // additional test for int (use const vector) { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::vector v; v.push_back(-2000000000); v.push_back(0); v.push_back(1); v.push_back(2000000000); std::vector const & cv = v; sql << "insert into soci_test(id) values(:i)", use(cv); std::vector v2(4); sql << "select id from soci_test order by id", into(v2); assert(v2.size() == 4); assert(v2[0] == -2000000000); assert(v2[1] == 0); assert(v2[2] == 1); assert(v2[3] == 2000000000); } } std::cout << "test 8 passed" << std::endl; #endif // SOCI_POSTGRESQL_NOPARAMS } // test for named binding void test9() { // Not supported with older PostgreSQL #ifndef SOCI_POSTGRESQL_NOPARAMS { session sql(backEndFactory_, connectString_); { auto_table_creator tableCreator(tc_.table_creator_1(sql)); int i1 = 7; int i2 = 8; // verify the exception is thrown if both by position // and by name use elements are specified try { sql << "insert into soci_test(i1, i2) values(:i1, :i2)", use(i1, "i1"), use(i2); assert(false); } catch (soci_error const& e) { std::string what(e.what()); assert(what == "Binding for use elements must be either by position " "or by name."); } // normal test sql << "insert into soci_test(i1, i2) values(:i1, :i2)", use(i1, "i1"), use(i2, "i2"); i1 = 0; i2 = 0; sql << "select i1, i2 from soci_test", into(i1), into(i2); assert(i1 == 7); assert(i2 == 8); i2 = 0; sql << "select i2 from soci_test where i1 = :i1", into(i2), use(i1); assert(i2 == 8); sql << "delete from soci_test"; // test vectors std::vector v1; v1.push_back(1); v1.push_back(2); v1.push_back(3); std::vector v2; v2.push_back(4); v2.push_back(5); v2.push_back(6); sql << "insert into soci_test(i1, i2) values(:i1, :i2)", use(v1, "i1"), use(v2, "i2"); sql << "select i2, i1 from soci_test order by i1 desc", into(v1), into(v2); assert(v1.size() == 3); assert(v2.size() == 3); assert(v1[0] == 6); assert(v1[1] == 5); assert(v1[2] == 4); assert(v2[0] == 3); assert(v2[1] == 2); assert(v2[2] == 1); } } std::cout << "test 9 passed" << std::endl; #endif // SOCI_POSTGRESQL_NOPARAMS } // transaction test void test10() { { session sql(backEndFactory_, connectString_); auto_table_creator tableCreator(tc_.table_creator_1(sql)); int count; sql << "select count(*) from soci_test", into(count); assert(count == 0); { transaction tr(sql); sql << "insert into soci_test (id, name) values(1, 'John')"; sql << "insert into soci_test (id, name) values(2, 'Anna')"; sql << "insert into soci_test (id, name) values(3, 'Mike')"; tr.commit(); } { transaction tr(sql); sql << "select count(*) from soci_test", into(count); assert(count == 3); sql << "insert into soci_test (id, name) values(4, 'Stan')"; sql << "select count(*) from soci_test", into(count); assert(count == 4); tr.rollback(); sql << "select count(*) from soci_test", into(count); assert(count == 3); } { transaction tr(sql); sql << "delete from soci_test"; sql << "select count(*) from soci_test", into(count); assert(count == 0); tr.rollback(); sql << "select count(*) from soci_test", into(count); assert(count == 3); } { // additional test for detection of double commit transaction tr(sql); tr.commit(); try { tr.commit(); assert(false); } catch (soci_error const &e) { std::string msg = e.what(); assert(msg == "The transaction object cannot be handled twice."); } } } std::cout << "test 10 passed" << std::endl; } // test of use elements with indicators void test11() { #ifndef SOCI_POSTGRESQL_NOPARAMS { session sql(backEndFactory_, connectString_); auto_table_creator tableCreator(tc_.table_creator_1(sql)); indicator ind1 = i_ok; indicator ind2 = i_ok; int id = 1; int val = 10; sql << "insert into soci_test(id, val) values(:id, :val)", use(id, ind1), use(val, ind2); id = 2; val = 11; ind2 = i_null; sql << "insert into soci_test(id, val) values(:id, :val)", use(id, ind1), use(val, ind2); sql << "select val from soci_test where id = 1", into(val, ind2); assert(ind2 == i_ok); assert(val == 10); sql << "select val from soci_test where id = 2", into(val, ind2); assert(ind2 == i_null); std::vector ids; ids.push_back(3); ids.push_back(4); ids.push_back(5); std::vector vals; vals.push_back(12); vals.push_back(13); vals.push_back(14); std::vector inds; inds.push_back(i_ok); inds.push_back(i_null); inds.push_back(i_ok); sql << "insert into soci_test(id, val) values(:id, :val)", use(ids), use(vals, inds); ids.resize(5); vals.resize(5); sql << "select id, val from soci_test order by id desc", into(ids), into(vals, inds); assert(ids.size() == 5); assert(ids[0] == 5); assert(ids[1] == 4); assert(ids[2] == 3); assert(ids[3] == 2); assert(ids[4] == 1); assert(inds.size() == 5); assert(inds[0] == i_ok); assert(inds[1] == i_null); assert(inds[2] == i_ok); assert(inds[3] == i_null); assert(inds[4] == i_ok); assert(vals.size() == 5); assert(vals[0] == 14); assert(vals[2] == 12); assert(vals[4] == 10); } std::cout << "test 11 passed" << std::endl; #endif // SOCI_POSTGRESQL_NOPARAMS } // Dynamic binding to Row objects void test12() { { session sql(backEndFactory_, connectString_); sql.uppercase_column_names(true); auto_table_creator tableCreator(tc_.table_creator_2(sql)); row r; sql << "select * from soci_test", into(r); assert(sql.got_data() == false); sql << "insert into soci_test" " values(3.14, 123, \'Johny\'," << tc_.to_date_time("2005-12-19 22:14:17") << ", 'a')"; // select into a row { row r; statement st = (sql.prepare << "select * from soci_test", into(r)); st.execute(true); assert(r.size() == 5); assert(r.get_properties(0).get_data_type() == dt_double); assert(r.get_properties(1).get_data_type() == dt_integer); assert(r.get_properties(2).get_data_type() == dt_string); assert(r.get_properties(3).get_data_type() == dt_date); // type char is visible as string // - to comply with the implementation for Oracle assert(r.get_properties(4).get_data_type() == dt_string); assert(r.get_properties("NUM_INT").get_data_type() == dt_integer); assert(r.get_properties(0).get_name() == "NUM_FLOAT"); assert(r.get_properties(1).get_name() == "NUM_INT"); assert(r.get_properties(2).get_name() == "NAME"); assert(r.get_properties(3).get_name() == "SOMETIME"); assert(r.get_properties(4).get_name() == "CHR"); assert(equal_approx(r.get(0), 3.14)); assert(r.get(1) == 123); assert(r.get(2) == "Johny"); std::tm t = { 0 }; t = r.get(3); assert(t.tm_year == 105); // again, type char is visible as string assert(r.get(4) == "a"); assert(equal_approx(r.get("NUM_FLOAT"), 3.14)); assert(r.get("NUM_INT") == 123); assert(r.get("NAME") == "Johny"); assert(r.get("CHR") == "a"); assert(r.get_indicator(0) == i_ok); // verify exception thrown on invalid get<> bool caught = false; try { r.get(0); } catch (std::bad_cast const &) { caught = true; } assert(caught); // additional test for stream-like extraction { double d; int i; std::string s; std::tm t; std::string c; r >> d >> i >> s >> t >> c; assert(equal_approx(d, 3.14)); assert(i == 123); assert(s == "Johny"); assert(t.tm_year == 105); assert(t.tm_mon == 11); assert(t.tm_mday == 19); assert(t.tm_hour == 22); assert(t.tm_min == 14); assert(t.tm_sec == 17); assert(c == "a"); } } // additional test to check if the row object can be // reused between queries { row r; sql << "select * from soci_test", into(r); assert(r.size() == 5); assert(r.get_properties(0).get_data_type() == dt_double); assert(r.get_properties(1).get_data_type() == dt_integer); assert(r.get_properties(2).get_data_type() == dt_string); assert(r.get_properties(3).get_data_type() == dt_date); sql << "select name, num_int from soci_test", into(r); assert(r.size() == 2); assert(r.get_properties(0).get_data_type() == dt_string); assert(r.get_properties(1).get_data_type() == dt_integer); } } std::cout << "test 12 passed" << std::endl; } // more dynamic bindings void test13() { session sql(backEndFactory_, connectString_); auto_table_creator tableCreator(tc_.table_creator_1(sql)); sql << "insert into soci_test(id, val) values(1, 10)"; sql << "insert into soci_test(id, val) values(2, 20)"; sql << "insert into soci_test(id, val) values(3, 30)"; #ifndef SOCI_POSTGRESQL_NOPARAMS { int id = 2; row r; sql << "select val from soci_test where id = :id", use(id), into(r); assert(r.size() == 1); assert(r.get_properties(0).get_data_type() == dt_integer); assert(r.get(0) == 20); } { int id; row r; statement st = (sql.prepare << "select val from soci_test where id = :id", use(id), into(r)); id = 2; st.execute(true); assert(r.size() == 1); assert(r.get_properties(0).get_data_type() == dt_integer); assert(r.get(0) == 20); id = 3; st.execute(true); assert(r.size() == 1); assert(r.get_properties(0).get_data_type() == dt_integer); assert(r.get(0) == 30); id = 1; st.execute(true); assert(r.size() == 1); assert(r.get_properties(0).get_data_type() == dt_integer); assert(r.get(0) == 10); } #else { row r; sql << "select val from soci_test where id = 2", into(r); assert(r.size() == 1); assert(r.get_properties(0).get_data_type() == dt_integer); assert(r.get(0) == 20); } #endif // SOCI_POSTGRESQL_NOPARAMS std::cout << "test 13 passed" << std::endl; } // More Dynamic binding to row objects void test14() { { session sql(backEndFactory_, connectString_); sql.uppercase_column_names(true); auto_table_creator tableCreator(tc_.table_creator_3(sql)); row r1; sql << "select * from soci_test", into(r1); assert(sql.got_data() == false); sql << "insert into soci_test values('david', '(404)123-4567')"; sql << "insert into soci_test values('john', '(404)123-4567')"; sql << "insert into soci_test values('doe', '(404)123-4567')"; row r2; statement st = (sql.prepare << "select * from soci_test", into(r2)); st.execute(); assert(r2.size() == 2); int count = 0; while (st.fetch()) { ++count; assert(r2.get("PHONE") == "(404)123-4567"); } assert(count == 3); } std::cout << "test 14 passed" << std::endl; } // test15 is like test14 but with a type_conversion instead of a row void test15() { session sql(backEndFactory_, connectString_); sql.uppercase_column_names(true); // simple conversion (between single basic type and user type) { auto_table_creator tableCreator(tc_.table_creator_1(sql)); MyInt mi; mi.set(123); sql << "insert into soci_test(id) values(:id)", use(mi); int i; sql << "select id from soci_test", into(i); assert(i == 123); sql << "update soci_test set id = id + 1"; sql << "select id from soci_test", into(mi); assert(mi.get() == 124); } // simple conversion with use const { auto_table_creator tableCreator(tc_.table_creator_1(sql)); MyInt mi; mi.set(123); MyInt const & cmi = mi; sql << "insert into soci_test(id) values(:id)", use(cmi); int i; sql << "select id from soci_test", into(i); assert(i == 123); } // conversions based on values (many fields involved -> ORM) { auto_table_creator tableCreator(tc_.table_creator_3(sql)); PhonebookEntry p1; sql << "select * from soci_test", into(p1); assert(p1.name == ""); assert(p1.phone == ""); p1.name = "david"; // Note: uppercase column names are used here (and later on) // for consistency with how they can be read from database // (which means forced to uppercase on Oracle) and how they are // set/get in the type conversion routines for PhonebookEntry. // In short, IF the database is Oracle, // then all column names for binding should be uppercase. sql << "insert into soci_test values(:NAME, :PHONE)", use(p1); sql << "insert into soci_test values('john', '(404)123-4567')"; sql << "insert into soci_test values('doe', '(404)123-4567')"; PhonebookEntry p2; statement st = (sql.prepare << "select * from soci_test", into(p2)); st.execute(); int count = 0; while (st.fetch()) { ++count; if (p2.name == "david") { // see type_conversion assert(p2.phone ==""); } else { assert(p2.phone == "(404)123-4567"); } } assert(count == 3); } // conversions based on values with use const { auto_table_creator tableCreator(tc_.table_creator_3(sql)); PhonebookEntry p1; p1.name = "Joe Coder"; p1.phone = "123-456"; PhonebookEntry const & cp1 = p1; sql << "insert into soci_test values(:NAME, :PHONE)", use(cp1); PhonebookEntry p2; sql << "select * from soci_test", into(p2); assert(sql.got_data()); assert(p2.name == "Joe Coder"); assert(p2.phone == "123-456"); } // conversions based on accessor functions (as opposed to direct variable bindings) { auto_table_creator tableCreator(tc_.table_creator_3(sql)); PhonebookEntry3 p1; p1.setName("Joe Hacker"); p1.setPhone("10010110"); sql << "insert into soci_test values(:NAME, :PHONE)", use(p1); PhonebookEntry3 p2; sql << "select * from soci_test", into(p2); assert(sql.got_data()); assert(p2.getName() == "Joe Hacker"); assert(p2.getPhone() == "10010110"); } { // Use the PhonebookEntry2 type conversion, to test // calls to values::get_indicator() auto_table_creator tableCreator(tc_.table_creator_3(sql)); PhonebookEntry2 p1; sql << "select * from soci_test", into(p1); assert(p1.name == ""); assert(p1.phone == ""); p1.name = "david"; sql << "insert into soci_test values(:NAME, :PHONE)", use(p1); sql << "insert into soci_test values('john', '(404)123-4567')"; sql << "insert into soci_test values('doe', '(404)123-4567')"; PhonebookEntry2 p2; statement st = (sql.prepare << "select * from soci_test", into(p2)); st.execute(); int count = 0; while (st.fetch()) { ++count; if (p2.name == "david") { // see type_conversion assert(p2.phone ==""); } else { assert(p2.phone == "(404)123-4567"); } } assert(count == 3); } std::cout << "test 15 passed" << std::endl; } void test_prepared_insert_with_orm_type() { { session sql(backEndFactory_, connectString_); sql.uppercase_column_names(true); auto_table_creator tableCreator(tc_.table_creator_3(sql)); PhonebookEntry temp; PhonebookEntry e1 = { "name1", "phone1" }; PhonebookEntry e2 = { "name2", "phone2" }; //sql << "insert into soci_test values (:NAME, :PHONE)", use(temp); statement insertStatement = (sql.prepare << "insert into soci_test values (:NAME, :PHONE)", use(temp)); temp = e1; insertStatement.execute(true); temp = e2; insertStatement.execute(true); int count = 0; sql << "select count(*) from soci_test where NAME in ('name1', 'name2')", into(count); assert(count == 2); } std::cout << "test test_prepared_insert_with_orm_type passed" << std::endl; } void test_placeholder_partial_matching_with_orm_type() { { session sql(backEndFactory_, connectString_); sql.uppercase_column_names(true); auto_table_creator tableCreator(tc_.table_creator_3(sql)); PhonebookEntry in = { "name1", "phone1" }; std::string name = "nameA"; sql << "insert into soci_test values (:NAMED, :PHONE)", use(in), use(name, "NAMED"); PhonebookEntry out; sql << "select * from soci_test where PHONE = 'phone1'", into(out); assert(out.name == "nameA"); assert(out.phone == "phone1"); } std::cout << "test test_placeholder_partial_matching_with_orm_type passed" << std::endl; } // test for bulk fetch with single use void test16() { #ifndef SOCI_POSTGRESQL_NOPARAMS { session sql(backEndFactory_, connectString_); auto_table_creator tableCreator(tc_.table_creator_1(sql)); sql << "insert into soci_test(name, id) values('john', 1)"; sql << "insert into soci_test(name, id) values('george', 2)"; sql << "insert into soci_test(name, id) values('anthony', 1)"; sql << "insert into soci_test(name, id) values('marc', 3)"; sql << "insert into soci_test(name, id) values('julian', 1)"; int code = 1; std::vector names(10); sql << "select name from soci_test where id = :id order by name", into(names), use(code); assert(names.size() == 3); assert(names[0] == "anthony"); assert(names[1] == "john"); assert(names[2] == "julian"); } #endif // SOCI_POSTGRESQL_NOPARAMS std::cout << "test 16 passed" << std::endl; } // test for basic logging support void test17() { session sql(backEndFactory_, connectString_); std::ostringstream log; sql.set_log_stream(&log); try { sql << "drop table soci_test1"; } catch (...) {} assert(sql.get_last_query() == "drop table soci_test1"); sql.set_log_stream(NULL); try { sql << "drop table soci_test2"; } catch (...) {} assert(sql.get_last_query() == "drop table soci_test2"); sql.set_log_stream(&log); try { sql << "drop table soci_test3"; } catch (...) {} assert(sql.get_last_query() == "drop table soci_test3"); assert(log.str() == "drop table soci_test1\n" "drop table soci_test3\n"); std::cout << "test 17 passed\n"; } // test for rowset creation and copying void test18() { session sql(backEndFactory_, connectString_); // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); { // Open empty rowset rowset rs1 = (sql.prepare << "select * from soci_test"); assert(rs1.begin() == rs1.end()); } { // Copy construction rowset rs1 = (sql.prepare << "select * from soci_test"); rowset rs2(rs1); rowset rs3(rs1); rowset rs4(rs3); assert(rs1.begin() == rs2.begin()); assert(rs1.begin() == rs3.begin()); assert(rs1.end() == rs2.end()); assert(rs1.end() == rs3.end()); } { // Assignment rowset rs1 = (sql.prepare << "select * from soci_test"); rowset rs2 = (sql.prepare << "select * from soci_test"); rowset rs3 = (sql.prepare << "select * from soci_test"); rs1 = rs2; rs3 = rs2; assert(rs1.begin() == rs2.begin()); assert(rs1.begin() == rs3.begin()); assert(rs1.end() == rs2.end()); assert(rs1.end() == rs3.end()); } std::cout << "test 18 passed" << std::endl; } // test for simple iterating using rowset iterator (without reading data) void test19() { session sql(backEndFactory_, connectString_); // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); { sql << "insert into soci_test(id, val) values(1, 10)"; sql << "insert into soci_test(id, val) values(2, 11)"; sql << "insert into soci_test(id, val) values(3, NULL)"; sql << "insert into soci_test(id, val) values(4, NULL)"; sql << "insert into soci_test(id, val) values(5, 12)"; { rowset rs = (sql.prepare << "select * from soci_test"); assert(5 == std::distance(rs.begin(), rs.end())); } } std::cout << "test 19 passed" << std::endl; } // test for reading rowset using iterator void test20() { session sql(backEndFactory_, connectString_); sql.uppercase_column_names(true); // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_2(sql)); { { // Empty rowset rowset rs = (sql.prepare << "select * from soci_test"); assert(0 == std::distance(rs.begin(), rs.end())); } { // Non-empty rowset sql << "insert into soci_test values(3.14, 123, \'Johny\'," << tc_.to_date_time("2005-12-19 22:14:17") << ", 'a')"; sql << "insert into soci_test values(6.28, 246, \'Robert\'," << tc_.to_date_time("2004-10-01 18:44:10") << ", 'b')"; rowset rs = (sql.prepare << "select * from soci_test"); rowset::const_iterator it = rs.begin(); assert(it != rs.end()); // // First row // row const & r1 = (*it); // Properties assert(r1.size() == 5); assert(r1.get_properties(0).get_data_type() == dt_double); assert(r1.get_properties(1).get_data_type() == dt_integer); assert(r1.get_properties(2).get_data_type() == dt_string); assert(r1.get_properties(3).get_data_type() == dt_date); assert(r1.get_properties(4).get_data_type() == dt_string); assert(r1.get_properties("NUM_INT").get_data_type() == dt_integer); // Data // Since we didn't specify order by in the above query, // the 2 rows may be returned in either order // (If we specify order by, we can't do it in a cross db // compatible way, because the Oracle table for this has been // created with lower case column names) std::string name = r1.get(2); assert(name == "Johny" || name == "Robert"); if (name == "Johny") { assert(equal_approx(r1.get(0), 3.14)); assert(r1.get(1) == 123); assert(r1.get(2) == "Johny"); std::tm t1 = { 0 }; t1 = r1.get(3); assert(t1.tm_year == 105); assert(r1.get(4) == "a"); assert(equal_approx(r1.get("NUM_FLOAT"), 3.14)); assert(r1.get("NUM_INT") == 123); assert(r1.get("NAME") == "Johny"); assert(r1.get("CHR") == "a"); } else { assert(equal_approx(r1.get(0), 6.28)); assert(r1.get(1) == 246); assert(r1.get(2) == "Robert"); std::tm t1 = r1.get(3); assert(t1.tm_year == 104); assert(r1.get(4) == "b"); assert(equal_approx(r1.get("NUM_FLOAT"), 6.28)); assert(r1.get("NUM_INT") == 246); assert(r1.get("NAME") == "Robert"); assert(r1.get("CHR") == "b"); } // // Iterate to second row // ++it; assert(it != rs.end()); // // Second row // row const & r2 = (*it); // Properties assert(r2.size() == 5); assert(r2.get_properties(0).get_data_type() == dt_double); assert(r2.get_properties(1).get_data_type() == dt_integer); assert(r2.get_properties(2).get_data_type() == dt_string); assert(r2.get_properties(3).get_data_type() == dt_date); assert(r2.get_properties(4).get_data_type() == dt_string); assert(r2.get_properties("NUM_INT").get_data_type() == dt_integer); std::string newName = r2.get(2); assert(name != newName); assert(newName == "Johny" || newName == "Robert"); if (newName == "Johny") { assert(equal_approx(r2.get(0), 3.14)); assert(r2.get(1) == 123); assert(r2.get(2) == "Johny"); std::tm t2 = r2.get(3); assert(t2.tm_year == 105); assert(r2.get(4) == "a"); assert(equal_approx(r2.get("NUM_FLOAT"), 3.14)); assert(r2.get("NUM_INT") == 123); assert(r2.get("NAME") == "Johny"); assert(r2.get("CHR") == "a"); } else { assert(equal_approx(r2.get(0), 6.28)); assert(r2.get(1) == 246); assert(r2.get(2) == "Robert"); std::tm t2 = r2.get(3); assert(t2.tm_year == 104); assert(r2.get(4) == "b"); assert(equal_approx(r2.get("NUM_FLOAT"), 6.28)); assert(r2.get("NUM_INT") == 246); assert(r2.get("NAME") == "Robert"); assert(r2.get("CHR") == "b"); } } { // Non-empty rowset with NULL values sql << "insert into soci_test " << "(num_int, num_float , name, sometime, chr) " << "values (0, NULL, NULL, NULL, NULL)"; rowset rs = (sql.prepare << "select num_int, num_float, name, sometime, chr " << "from soci_test where num_int = 0"); rowset::const_iterator it = rs.begin(); assert(it != rs.end()); // // First row // row const& r1 = (*it); // Properties assert(r1.size() == 5); assert(r1.get_properties(0).get_data_type() == dt_integer); assert(r1.get_properties(1).get_data_type() == dt_double); assert(r1.get_properties(2).get_data_type() == dt_string); assert(r1.get_properties(3).get_data_type() == dt_date); assert(r1.get_properties(4).get_data_type() == dt_string); // Data assert(r1.get_indicator(0) == soci::i_ok); assert(r1.get(0) == 0); assert(r1.get_indicator(1) == soci::i_null); assert(r1.get_indicator(2) == soci::i_null); assert(r1.get_indicator(3) == soci::i_null); assert(r1.get_indicator(4) == soci::i_null); } } std::cout << "test 20 passed" << std::endl; } // test for reading rowset using iterator void test21() { session sql(backEndFactory_, connectString_); // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); { sql << "insert into soci_test(id) values(1)"; sql << "insert into soci_test(id) values(2)"; sql << "insert into soci_test(id) values(3)"; sql << "insert into soci_test(id) values(4)"; sql << "insert into soci_test(id) values(5)"; { rowset rs = (sql.prepare << "select id from soci_test order by id asc"); // 1st row rowset::const_iterator pos = rs.begin(); assert(1 == (*pos)); // 3rd row std::advance(pos, 2); assert(3 == (*pos)); // 5th row std::advance(pos, 2); assert(5 == (*pos)); // The End ++pos; assert(pos == rs.end()); } } std::cout << "test 21 passed" << std::endl; } // test for handling 'use' and reading rowset using iterator void test22() { session sql(backEndFactory_, connectString_); // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); { sql << "insert into soci_test(str) values('abc')"; sql << "insert into soci_test(str) values('def')"; sql << "insert into soci_test(str) values('ghi')"; sql << "insert into soci_test(str) values('jkl')"; { // Expected result in numbers std::string idle("def"); rowset rs1 = (sql.prepare << "select str from soci_test where str = :idle", use(idle)); assert(1 == std::distance(rs1.begin(), rs1.end())); // Expected result in value idle = "jkl"; rowset rs2 = (sql.prepare << "select str from soci_test where str = :idle", use(idle)); assert(idle == *(rs2.begin())); } } std::cout << "test 22 passed" << std::endl; } // test for handling troublemaker void test23() { session sql(backEndFactory_, connectString_); // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); { sql << "insert into soci_test(str) values('abc')"; { // verify exception thrown bool caught = false; try { std::string troublemaker; rowset rs1 = (sql.prepare << "select str from soci_test", into(troublemaker)); } catch (soci_error const&) { caught = true; } assert(caught); } std::cout << "test 23 passed" << std::endl; } } // test for handling NULL values with expected exception: // "Null value fetched and no indicator defined." void test24() { session sql(backEndFactory_, connectString_); // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); { sql << "insert into soci_test(val) values(1)"; sql << "insert into soci_test(val) values(2)"; sql << "insert into soci_test(val) values(NULL)"; sql << "insert into soci_test(val) values(3)"; { // verify exception thrown bool caught = false; try { rowset rs = (sql.prepare << "select val from soci_test order by val asc"); int tester = 0; for (rowset::const_iterator it = rs.begin(); it != rs.end(); ++it) { tester = *it; } (void)tester; // Never should get here assert(false); } catch (soci_error const&) { caught = true; } assert(caught); } std::cout << "test 24 passed" << std::endl; } } // test25 is like test15 but with rowset and iterators use void test25() { session sql(backEndFactory_, connectString_); sql.uppercase_column_names(true); { auto_table_creator tableCreator(tc_.table_creator_3(sql)); PhonebookEntry p1; sql << "select * from soci_test", into(p1); assert(p1.name == ""); assert(p1.phone == ""); p1.name = "david"; sql << "insert into soci_test values(:NAME, :PHONE)", use(p1); sql << "insert into soci_test values('john', '(404)123-4567')"; sql << "insert into soci_test values('doe', '(404)123-4567')"; rowset rs = (sql.prepare << "select * from soci_test"); int count = 0; for (rowset::const_iterator it = rs.begin(); it != rs.end(); ++it) { ++count; PhonebookEntry const& p2 = (*it); if (p2.name == "david") { // see type_conversion assert(p2.phone ==""); } else { assert(p2.phone == "(404)123-4567"); } } assert(3 == count); } std::cout << "test 25 passed" << std::endl; } // test for handling NULL values with boost::optional // (both into and use) void test26() { #ifdef HAVE_BOOST session sql(backEndFactory_, connectString_); // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); { sql << "insert into soci_test(val) values(7)"; { // verify non-null value is fetched correctly boost::optional opt; sql << "select val from soci_test", into(opt); assert(opt.is_initialized()); assert(opt.get() == 7); // indicators can be used with optional // (although that's just a consequence of implementation, // not an intended feature - but let's test it anyway) indicator ind; opt.reset(); sql << "select val from soci_test", into(opt, ind); assert(opt.is_initialized()); assert(opt.get() == 7); assert(ind == i_ok); // verify null value is fetched correctly sql << "select i1 from soci_test", into(opt); assert(opt.is_initialized() == false); // and with indicator opt = 5; sql << "select i1 from soci_test", into(opt, ind); assert(opt.is_initialized() == false); assert(ind == i_null); // verify non-null is inserted correctly opt = 3; sql << "update soci_test set val = :v", use(opt); int j = 0; sql << "select val from soci_test", into(j); assert(j == 3); // verify null is inserted correctly opt.reset(); sql << "update soci_test set val = :v", use(opt); ind = i_ok; sql << "select val from soci_test", into(j, ind); assert(ind == i_null); } // vector tests (select) { sql << "delete from soci_test"; // simple readout of non-null data sql << "insert into soci_test(id, val, str) values(1, 5, \'abc\')"; sql << "insert into soci_test(id, val, str) values(2, 6, \'def\')"; sql << "insert into soci_test(id, val, str) values(3, 7, \'ghi\')"; sql << "insert into soci_test(id, val, str) values(4, 8, null)"; sql << "insert into soci_test(id, val, str) values(5, 9, \'mno\')"; std::vector > v(10); sql << "select val from soci_test order by val", into(v); assert(v.size() == 5); assert(v[0].is_initialized()); assert(v[0].get() == 5); assert(v[1].is_initialized()); assert(v[1].get() == 6); assert(v[2].is_initialized()); assert(v[2].get() == 7); assert(v[3].is_initialized()); assert(v[3].get() == 8); assert(v[4].is_initialized()); assert(v[4].get() == 9); // readout of nulls sql << "update soci_test set val = null where id = 2 or id = 4"; std::vector ids(5); sql << "select id, val from soci_test order by id", into(ids), into(v); assert(v.size() == 5); assert(ids.size() == 5); assert(v[0].is_initialized()); assert(v[0].get() == 5); assert(v[1].is_initialized() == false); assert(v[2].is_initialized()); assert(v[2].get() == 7); assert(v[3].is_initialized() == false); assert(v[4].is_initialized()); assert(v[4].get() == 9); // readout with statement preparation int id = 1; ids.resize(3); v.resize(3); statement st = (sql.prepare << "select id, val from soci_test order by id", into(ids), into(v)); st.execute(); while (st.fetch()) { for (std::size_t i = 0; i != v.size(); ++i) { assert(id == ids[i]); if (id == 2 || id == 4) { assert(v[i].is_initialized() == false); } else { assert(v[i].is_initialized() && v[i].get() == id + 4); } ++id; } ids.resize(3); v.resize(3); } assert(id == 6); } // and why not stress iterators and the dynamic binding, too! { rowset rs = (sql.prepare << "select id, val, str from soci_test order by id"); rowset::const_iterator it = rs.begin(); assert(it != rs.end()); row const& r1 = (*it); assert(r1.size() == 3); // Note: for the reason of differences between number(x,y) type and // binary representation of integers, the following commented assertions // do not work for Oracle. // The problem is that for this single table the data type used in Oracle // table creator for the id column is number(10,0), // which allows to insert all int values. // On the other hand, the column description scheme used in the Oracle // backend figures out that the natural type for such a column // is eUnsignedInt - this makes the following assertions fail. // Other database backends (like PostgreSQL) use other types like int // and this not only allows to insert all int values (obviously), // but is also recognized as int (obviously). // There is a similar problem with stream-like extraction, // where internally get is called and the type mismatch is detected // for the id column - that's why the code below skips this column // and tests the remaining column only. //assert(r1.get_properties(0).get_data_type() == dt_integer); assert(r1.get_properties(1).get_data_type() == dt_integer); assert(r1.get_properties(2).get_data_type() == dt_string); //assert(r1.get(0) == 1); assert(r1.get(1) == 5); assert(r1.get(2) == "abc"); assert(r1.get >(1).is_initialized()); assert(r1.get >(1).get() == 5); assert(r1.get >(2).is_initialized()); assert(r1.get >(2).get() == "abc"); ++it; row const& r2 = (*it); assert(r2.size() == 3); // assert(r2.get_properties(0).get_data_type() == dt_integer); assert(r2.get_properties(1).get_data_type() == dt_integer); assert(r2.get_properties(2).get_data_type() == dt_string); //assert(r2.get(0) == 2); try { // expect exception here, this is NULL value (void)r1.get(1); assert(false); } catch (soci_error const &) {} // but we can read it as optional assert(r2.get >(1).is_initialized() == false); // stream-like data extraction ++it; row const &r3 = (*it); boost::optional io; boost::optional so; r3.skip(); // move to val and str columns r3 >> io >> so; assert(io.is_initialized() && io.get() == 7); assert(so.is_initialized() && so.get() == "ghi"); ++it; row const &r4 = (*it); r3.skip(); // move to val and str columns r4 >> io >> so; assert(io.is_initialized() == false); assert(so.is_initialized() == false); } // bulk inserts of non-null data { sql << "delete from soci_test"; std::vector ids; std::vector > v; ids.push_back(10); v.push_back(20); ids.push_back(11); v.push_back(21); ids.push_back(12); v.push_back(22); ids.push_back(13); v.push_back(23); sql << "insert into soci_test(id, val) values(:id, :val)", use(ids, "id"), use(v, "val"); int sum; sql << "select sum(val) from soci_test", into(sum); assert(sum == 86); // bulk inserts of some-null data sql << "delete from soci_test"; v[2].reset(); v[3].reset(); sql << "insert into soci_test(id, val) values(:id, :val)", use(ids, "id"), use(v, "val"); sql << "select sum(val) from soci_test", into(sum); assert(sum == 41); } // composability with user conversions { sql << "delete from soci_test"; boost::optional omi1; boost::optional omi2; omi1 = MyInt(125); omi2.reset(); sql << "insert into soci_test(id, val) values(:id, :val)", use(omi1), use(omi2); sql << "select id, val from soci_test", into(omi2), into(omi1); assert(omi1.is_initialized() == false); assert(omi2.is_initialized() && omi2.get().get() == 125); } // use with const optional and user conversions { sql << "delete from soci_test"; boost::optional omi1; boost::optional omi2; omi1 = MyInt(125); omi2.reset(); boost::optional const & comi1 = omi1; boost::optional const & comi2 = omi2; sql << "insert into soci_test(id, val) values(:id, :val)", use(comi1), use(comi2); sql << "select id, val from soci_test", into(omi2), into(omi1); assert(omi1.is_initialized() == false); assert(omi2.is_initialized() && omi2.get().get() == 125); } // use with rowset and table containing null values { auto_table_creator tableCreator(tc_.table_creator_1(sql)); sql << "insert into soci_test(id, val) values(1, 10)"; sql << "insert into soci_test(id, val) values(2, 11)"; sql << "insert into soci_test(id, val) values(3, NULL)"; sql << "insert into soci_test(id, val) values(4, 13)"; rowset > rs = (sql.prepare << "select val from soci_test order by id asc"); // 1st row rowset >::const_iterator pos = rs.begin(); assert((*pos).is_initialized()); assert(10 == (*pos).get()); // 2nd row ++pos; assert((*pos).is_initialized()); assert(11 == (*pos).get()); // 3rd row ++pos; assert((*pos).is_initialized() == false); // 4th row ++pos; assert((*pos).is_initialized()); assert(13 == (*pos).get()); } } std::cout << "test 26 passed" << std::endl; #else std::cout << "test 26 skipped (no Boost)" << std::endl; #endif // HAVE_BOOST } // connection and reconnection tests void test27() { { // empty session session sql; // idempotent: sql.close(); try { sql.reconnect(); assert(false); } catch (soci_error const &e) { assert(e.what() == std::string( "Cannot reconnect without previous connection.")); } // open from empty session sql.open(backEndFactory_, connectString_); sql.close(); // reconnecting from closed session sql.reconnect(); // opening already connected session try { sql.open(backEndFactory_, connectString_); assert(false); } catch (soci_error const &e) { assert(e.what() == std::string( "Cannot open already connected session.")); } sql.close(); // open from closed sql.open(backEndFactory_, connectString_); // reconnect from already connected session sql.reconnect(); } { session sql; try { sql << "this statement cannot execute"; assert(false); } catch (soci_error const &e) { assert(e.what() == std::string("Session is not connected.")); } } std::cout << "test 27 passed" << std::endl; } void test28() { #ifdef HAVE_BOOST session sql(backEndFactory_, connectString_); auto_table_creator tableCreator(tc_.table_creator_2(sql)); { boost::tuple t1(3.5, 7, "Joe Hacker"); assert(equal_approx(t1.get<0>(), 3.5)); assert(t1.get<1>() == 7); assert(t1.get<2>() == "Joe Hacker"); sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1); // basic query boost::tuple t2; sql << "select num_float, num_int, name from soci_test", into(t2); assert(equal_approx(t2.get<0>(), 3.5)); assert(t2.get<1>() == 7); assert(t2.get<2>() == "Joe Hacker"); sql << "delete from soci_test"; } { // composability with boost::optional // use: boost::tuple, std::string> t1( 3.5, boost::optional(7), "Joe Hacker"); assert(equal_approx(t1.get<0>(), 3.5)); assert(t1.get<1>().is_initialized()); assert(t1.get<1>().get() == 7); assert(t1.get<2>() == "Joe Hacker"); sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1); // into: boost::tuple, std::string> t2; sql << "select num_float, num_int, name from soci_test", into(t2); assert(equal_approx(t2.get<0>(), 3.5)); assert(t2.get<1>().is_initialized()); assert(t2.get<1>().get() == 7); assert(t2.get<2>() == "Joe Hacker"); sql << "delete from soci_test"; } { // composability with user-provided conversions // use: boost::tuple t1(3.5, 7, "Joe Hacker"); assert(equal_approx(t1.get<0>(), 3.5)); assert(t1.get<1>().get() == 7); assert(t1.get<2>() == "Joe Hacker"); sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1); // into: boost::tuple t2; sql << "select num_float, num_int, name from soci_test", into(t2); assert(equal_approx(t2.get<0>(), 3.5)); assert(t2.get<1>().get() == 7); assert(t2.get<2>() == "Joe Hacker"); sql << "delete from soci_test"; } { // let's have fun - composition of tuple, optional and user-defined type // use: boost::tuple, std::string> t1( 3.5, boost::optional(7), "Joe Hacker"); assert(equal_approx(t1.get<0>(), 3.5)); assert(t1.get<1>().is_initialized()); assert(t1.get<1>().get().get() == 7); assert(t1.get<2>() == "Joe Hacker"); sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1); // into: boost::tuple, std::string> t2; sql << "select num_float, num_int, name from soci_test", into(t2); assert(equal_approx(t2.get<0>(), 3.5)); assert(t2.get<1>().is_initialized()); assert(t2.get<1>().get().get() == 7); assert(t2.get<2>() == "Joe Hacker"); sql << "update soci_test set num_int = NULL"; sql << "select num_float, num_int, name from soci_test", into(t2); assert(equal_approx(t2.get<0>(), 3.5)); assert(t2.get<1>().is_initialized() == false); assert(t2.get<2>() == "Joe Hacker"); } { // rowset sql << "insert into soci_test(num_float, num_int, name) values(4.0, 8, 'Tony Coder')"; sql << "insert into soci_test(num_float, num_int, name) values(4.5, NULL, 'Cecile Sharp')"; sql << "insert into soci_test(num_float, num_int, name) values(5.0, 10, 'Djhava Ravaa')"; typedef boost::tuple, std::string> T; rowset rs = (sql.prepare << "select num_float, num_int, name from soci_test order by num_float asc"); rowset::const_iterator pos = rs.begin(); assert(equal_approx(pos->get<0>(), 3.5)); assert(pos->get<1>().is_initialized() == false); assert(pos->get<2>() == "Joe Hacker"); ++pos; assert(equal_approx(pos->get<0>(), 4.0)); assert(pos->get<1>().is_initialized()); assert(pos->get<1>().get() == 8); assert(pos->get<2>() == "Tony Coder"); ++pos; assert(equal_approx(pos->get<0>(), 4.5)); assert(pos->get<1>().is_initialized() == false); assert(pos->get<2>() == "Cecile Sharp"); ++pos; assert(equal_approx(pos->get<0>(), 5.0)); assert(pos->get<1>().is_initialized()); assert(pos->get<1>().get() == 10); assert(pos->get<2>() == "Djhava Ravaa"); ++pos; assert(pos == rs.end()); } std::cout << "test 28 passed" << std::endl; #else std::cout << "test 28 skipped (no Boost)" << std::endl; #endif // HAVE_BOOST } void test29() { #ifdef HAVE_BOOST #if defined(BOOST_VERSION) && BOOST_VERSION >= 103500 session sql(backEndFactory_, connectString_); auto_table_creator tableCreator(tc_.table_creator_2(sql)); { boost::fusion::vector t1(3.5, 7, "Joe Hacker"); assert(equal_approx(boost::fusion::at_c<0>(t1), 3.5)); assert(boost::fusion::at_c<1>(t1) == 7); assert(boost::fusion::at_c<2>(t1) == "Joe Hacker"); sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1); // basic query boost::fusion::vector t2; sql << "select num_float, num_int, name from soci_test", into(t2); assert(equal_approx(boost::fusion::at_c<0>(t2), 3.5)); assert(boost::fusion::at_c<1>(t2) == 7); assert(boost::fusion::at_c<2>(t2) == "Joe Hacker"); sql << "delete from soci_test"; } { // composability with boost::optional // use: boost::fusion::vector, std::string> t1( 3.5, boost::optional(7), "Joe Hacker"); assert(equal_approx(boost::fusion::at_c<0>(t1), 3.5)); assert(boost::fusion::at_c<1>(t1).is_initialized()); assert(boost::fusion::at_c<1>(t1).get() == 7); assert(boost::fusion::at_c<2>(t1) == "Joe Hacker"); sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1); // into: boost::fusion::vector, std::string> t2; sql << "select num_float, num_int, name from soci_test", into(t2); assert(equal_approx(boost::fusion::at_c<0>(t2), 3.5)); assert(boost::fusion::at_c<1>(t2).is_initialized()); assert(boost::fusion::at_c<1>(t2) == 7); assert(boost::fusion::at_c<2>(t2) == "Joe Hacker"); sql << "delete from soci_test"; } { // composability with user-provided conversions // use: boost::fusion::vector t1(3.5, 7, "Joe Hacker"); assert(equal_approx(boost::fusion::at_c<0>(t1), 3.5)); assert(boost::fusion::at_c<1>(t1).get() == 7); assert(boost::fusion::at_c<2>(t1) == "Joe Hacker"); sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1); // into: boost::fusion::vector t2; sql << "select num_float, num_int, name from soci_test", into(t2); assert(equal_approx(boost::fusion::at_c<0>(t2), 3.5)); assert(boost::fusion::at_c<1>(t2).get() == 7); assert(boost::fusion::at_c<2>(t2) == "Joe Hacker"); sql << "delete from soci_test"; } { // let's have fun - composition of tuple, optional and user-defined type // use: boost::fusion::vector, std::string> t1( 3.5, boost::optional(7), "Joe Hacker"); assert(equal_approx(boost::fusion::at_c<0>(t1), 3.5)); assert(boost::fusion::at_c<1>(t1).is_initialized()); assert(boost::fusion::at_c<1>(t1).get().get() == 7); assert(boost::fusion::at_c<2>(t1) == "Joe Hacker"); sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1); // into: boost::fusion::vector, std::string> t2; sql << "select num_float, num_int, name from soci_test", into(t2); assert(equal_approx(boost::fusion::at_c<0>(t2), 3.5)); assert(boost::fusion::at_c<1>(t2).is_initialized()); assert(boost::fusion::at_c<1>(t2).get().get() == 7); assert(boost::fusion::at_c<2>(t2) == "Joe Hacker"); sql << "update soci_test set num_int = NULL"; sql << "select num_float, num_int, name from soci_test", into(t2); assert(equal_approx(boost::fusion::at_c<0>(t2), 3.5)); assert(boost::fusion::at_c<1>(t2).is_initialized() == false); assert(boost::fusion::at_c<2>(t2) == "Joe Hacker"); } { // rowset sql << "insert into soci_test(num_float, num_int, name) values(4.0, 8, 'Tony Coder')"; sql << "insert into soci_test(num_float, num_int, name) values(4.5, NULL, 'Cecile Sharp')"; sql << "insert into soci_test(num_float, num_int, name) values(5.0, 10, 'Djhava Ravaa')"; typedef boost::fusion::vector, std::string> T; rowset rs = (sql.prepare << "select num_float, num_int, name from soci_test order by num_float asc"); rowset::const_iterator pos = rs.begin(); assert(equal_approx(boost::fusion::at_c<0>(*pos), 3.5)); assert(boost::fusion::at_c<1>(*pos).is_initialized() == false); assert(boost::fusion::at_c<2>(*pos) == "Joe Hacker"); ++pos; assert(equal_approx(boost::fusion::at_c<0>(*pos), 4.0)); assert(boost::fusion::at_c<1>(*pos).is_initialized()); assert(boost::fusion::at_c<1>(*pos).get() == 8); assert(boost::fusion::at_c<2>(*pos) == "Tony Coder"); ++pos; assert(equal_approx(boost::fusion::at_c<0>(*pos), 4.5)); assert(boost::fusion::at_c<1>(*pos).is_initialized() == false); assert(boost::fusion::at_c<2>(*pos) == "Cecile Sharp"); ++pos; assert(equal_approx(boost::fusion::at_c<0>(*pos), 5.0)); assert(boost::fusion::at_c<1>(*pos).is_initialized()); assert(boost::fusion::at_c<1>(*pos).get() == 10); assert(boost::fusion::at_c<2>(*pos) == "Djhava Ravaa"); ++pos; assert(pos == rs.end()); } std::cout << "test 29 passed" << std::endl; #else std::cout << "test 29 skipped (no boost::fusion)" << std::endl; #endif // BOOST_VERSION #else std::cout << "test 29 skipped (no Boost)" << std::endl; #endif // HAVE_BOOST } // test for boost::gregorian::date void test30() { #ifdef HAVE_BOOST session sql(backEndFactory_, connectString_); { auto_table_creator tableCreator(tc_.table_creator_1(sql)); std::tm nov15; nov15.tm_year = 105; nov15.tm_mon = 10; nov15.tm_mday = 15; nov15.tm_hour = 0; nov15.tm_min = 0; nov15.tm_sec = 0; sql << "insert into soci_test(tm) values(:tm)", use(nov15); boost::gregorian::date bgd; sql << "select tm from soci_test", into(bgd); assert(bgd.year() == 2005); assert(bgd.month() == 11); assert(bgd.day() == 15); sql << "update soci_test set tm = NULL"; try { sql << "select tm from soci_test", into(bgd); assert(false); } catch (soci_error const & e) { assert(e.what() == std::string("Null value not allowed for this type")); } } { auto_table_creator tableCreator(tc_.table_creator_1(sql)); boost::gregorian::date bgd(2008, boost::gregorian::May, 5); sql << "insert into soci_test(tm) values(:tm)", use(bgd); std::tm t; sql << "select tm from soci_test", into(t); assert(t.tm_year == 108); assert(t.tm_mon == 4); assert(t.tm_mday == 5); } std::cout << "test 30 passed" << std::endl; #else std::cout << "test 30 skipped (no Boost)" << std::endl; #endif // HAVE_BOOST } // connection pool - simple sequential test, no multiple threads void test31() { { // phase 1: preparation const size_t pool_size = 10; connection_pool pool(pool_size); for (std::size_t i = 0; i != pool_size; ++i) { session & sql = pool.at(i); sql.open(backEndFactory_, connectString_); } // phase 2: usage for (std::size_t i = 0; i != pool_size; ++i) { // poor man way to lease more than one connection session sql_unused1(pool); session sql(pool); session sql_unused2(pool); { auto_table_creator tableCreator(tc_.table_creator_1(sql)); char c('a'); sql << "insert into soci_test(c) values(:c)", use(c); sql << "select c from soci_test", into(c); assert(c == 'a'); } } } std::cout << "test 31 passed\n"; } // Issue 66 - test query transformation callback feature static std::string no_op_transform(std::string query) { return query; } static std::string lower_than_g(std::string query) { return query + " WHERE c < 'g'"; } struct where_condition : std::unary_function { where_condition(std::string const& where) : where_(where) {} result_type operator()(argument_type query) const { return query + " WHERE " + where_; } std::string where_; }; void run_query_transformation_test(session& sql) { // create and populate the test table auto_table_creator tableCreator(tc_.table_creator_1(sql)); for (char c = 'a'; c <= 'z'; ++c) { sql << "insert into soci_test(c) values(\'" << c << "\')"; } char const* query = "select count(*) from soci_test"; // free function, no-op { sql.set_query_transformation(no_op_transform); int count; sql << query, into(count); assert(count == 'z' - 'a' + 1); } // free function { sql.set_query_transformation(lower_than_g); int count; sql << query, into(count); assert(count == 'g' - 'a'); } // function object with state { sql.set_query_transformation(where_condition("c > 'g' AND c < 'j'")); int count = 0; sql << query, into(count); assert(count == 'j' - 'h'); count = 0; sql.set_query_transformation(where_condition("c > 's' AND c <= 'z'")); sql << query, into(count); assert(count == 'z' - 's'); } // Bug in Visual Studio __cplusplus still means C++03 // https://connect.microsoft.com/VisualStudio/feedback/details/763051/ #if defined _MSC_VER && _MSC_VER>=1600 #define SOCI_HAVE_CPP11 1 #elif __cplusplus >= 201103L #define SOCI_HAVE_CPP11 1 #else #undef SOCI_HAVE_CPP11 #endif #ifdef SOCI_HAVE_CPP11 // lambda { sql.set_query_transformation( [](std::string const& query) { return query + " WHERE c > 'g' AND c < 'j'"; }); int count = 0; sql << query, into(count); assert(count == 'j' - 'h'); } #endif #undef SOCI_HAVE_CPP11 // prepared statements // constant effect (pre-prepare set transformation) { // set transformation after statement is prepared sql.set_query_transformation(lower_than_g); // prepare statement int count; statement st = (sql.prepare << query, into(count)); // observe transformation effect st.execute(true); assert(count == 'g' - 'a'); // reset transformation sql.set_query_transformation(no_op_transform); // observe the same transformation, no-op set above has no effect count = 0; st.execute(true); assert(count == 'g' - 'a'); } // no effect (post-prepare set transformation) { // reset sql.set_query_transformation(no_op_transform); // prepare statement int count; statement st = (sql.prepare << query, into(count)); // set transformation after statement is prepared sql.set_query_transformation(lower_than_g); // observe no effect of WHERE clause injection st.execute(true); assert(count == 'z' - 'a' + 1); } } void test_query_transformation() { { session sql(backEndFactory_, connectString_); run_query_transformation_test(sql); } std::cout << "test query_transformation passed" << std::endl; } void test_query_transformation_with_connection_pool() { { // phase 1: preparation const size_t pool_size = 10; connection_pool pool(pool_size); for (std::size_t i = 0; i != pool_size; ++i) { session & sql = pool.at(i); sql.open(backEndFactory_, connectString_); } session sql(pool); run_query_transformation_test(sql); } std::cout << "test query_transformation with connection pool passed" << std::endl; } // Originally, submitted to SQLite3 backend and later moved to common test. // Test commit b394d039530f124802d06c3b1a969c3117683152 // Author: Mika Fischer // Date: Thu Nov 17 13:28:07 2011 +0100 // Implement get_affected_rows for SQLite3 backend void test_get_affected_rows() { { session sql(backEndFactory_, connectString_); auto_table_creator tableCreator(tc_.table_creator_4(sql)); if (!tableCreator.get()) { std::cout << "test get_affected_rows skipped (function not implemented)" << std::endl; return; } for (int i = 0; i != 10; i++) { sql << "insert into soci_test(val) values(:val)", use(i); } statement st1 = (sql.prepare << "update soci_test set val = val + 1"); st1.execute(true); assert(st1.get_affected_rows() == 10); statement st2 = (sql.prepare << "delete from soci_test where val <= 5"); st2.execute(true); assert(st2.get_affected_rows() == 5); statement st3 = (sql.prepare << "update soci_test set val = val + 1"); st3.execute(true); assert(st3.get_affected_rows() == 5); std::vector v(5, 0); for (std::size_t i = 0; i < v.size(); ++i) { v[i] = (7 + i); } // test affected rows for bulk operations. statement st4 = (sql.prepare << "delete from soci_test where val = :v", use(v)); st4.execute(true); assert(st4.get_affected_rows() == 5); std::vector w(2, "1"); w[1] = "a"; // this invalid value may cause an exception. statement st5 = (sql.prepare << "insert into soci_test(val) values(:val)", use(w)); try { st5.execute(true); } catch(...) {} // confirm the partial insertion. int val = 0; sql << "select count(val) from soci_test", into(val); if(val != 0) { // test the preserved 'number of rows // affected' after a potential failure. assert(st5.get_affected_rows() != 0); } } std::cout << "test get_affected_rows passed" << std::endl; } // test fix for: Backend is not set properly with connection pool (pull #5) void test_pull5() { { const size_t pool_size = 1; connection_pool pool(pool_size); for (std::size_t i = 0; i != pool_size; ++i) { session & sql = pool.at(i); sql.open(backEndFactory_, connectString_); } soci::session sql(pool); sql.reconnect(); sql.begin(); // no crash expected } std::cout << "test pull-5 passed\n"; } // issue 67 - Allocated statement backend memory leaks on exception // If the test runs under memory debugger and it passes, then // soci::details::statement_impl::backEnd_ must not leak void test_issue67() { session sql(backEndFactory_, connectString_); auto_table_creator tableCreator(tc_.table_creator_1(sql)); { try { rowset rs1 = (sql.prepare << "select * from soci_testX"); // TODO: On Linux, no exception thrown; neither from prepare, nor from execute? // soci_odbc_test_postgresql: // /home/travis/build/SOCI/soci/src/core/test/common-tests.h:3505: // void soci::tests::common_tests::test_issue67(): Assertion `!"exception expected"' failed. //assert(!"exception expected"); // relax temporarily } catch (soci_error const &e) { (void)e; assert("expected exception caught"); std::cout << "test issue-67 passed - check memory debugger output for leaks" << std::endl; } } } // issue 154 - Calling undefine_and_bind and then define_and_bind causes a leak. // If the test runs under memory debugger and it passes, then // soci::details::standard_use_type_backend and vector_use_type_backend must not leak void test_issue154() { session sql(backEndFactory_, connectString_); auto_table_creator tableCreator(tc_.table_creator_1(sql)); sql << "insert into soci_test(id) values (1)"; { int id = 1; int val = 0; statement st(sql); st.exchange(use(id)); st.alloc(); st.prepare("select id from soci_test where id = :1"); st.define_and_bind(); st.undefine_and_bind(); st.exchange(soci::into(val)); st.define_and_bind(); st.execute(true); assert(val == 1); } // vector variation { std::vector ids(1, 2); std::vector vals(1, 1); int val = 0; statement st(sql); st.exchange(use(ids)); st.alloc(); st.prepare("insert into soci_test(id, val) values (:1, :2)"); st.define_and_bind(); st.undefine_and_bind(); st.exchange(use(vals)); st.define_and_bind(); st.execute(true); sql << "select val from soci_test where id = 2", into(val); assert(val == 1); } std::cout << "test issue-154 passed - check memory debugger output for leaks" << std::endl; } }; // class common_tests } // namespace tests } // namespace soci #endif // SOCI_COMMON_TESTS_H_INCLUDED soci-3.2.3/core/backend-loader.cpp0000644000000000000000000001742612511361676015463 0ustar rootroot// // Copyright (C) 2008 Maciej Sobczak with contributions from Artyom Tonkikh // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "backend-loader.h" #include "error.h" #include #include #include #include #include #ifndef _MSC_VER #include #endif #include "soci_backends_config.h" using namespace soci; using namespace soci::dynamic_backends; #ifdef _WIN32 #include typedef CRITICAL_SECTION soci_mutex_t; typedef HMODULE soci_handler_t; #define LOCK(x) EnterCriticalSection(x) #define UNLOCK(x) LeaveCriticalSection(x) #define MUTEX_INIT(x) InitializeCriticalSection(x) #define MUTEX_DEST(x) DeleteCriticalSection(x) #ifdef _UNICODE #define DLOPEN(x) LoadLibraryA(x) #else #define DLOPEN(x) LoadLibrary(x) #endif #define DLCLOSE(x) FreeLibrary(x) #define DLSYM(x, y) GetProcAddress(x, y) #ifdef SOCI_ABI_VERSION #define LIBNAME(x) (SOCI_LIB_PREFIX + x + "_" SOCI_ABI_VERSION SOCI_LIB_SUFFIX) #else #define LIBNAME(x) (SOCI_LIB_PREFIX + x + SOCI_LIB_SUFFIX) #endif // SOCI_ABI_VERSION #else #include #include typedef pthread_mutex_t soci_mutex_t; typedef void * soci_handler_t; #define LOCK(x) pthread_mutex_lock(x) #define UNLOCK(x) pthread_mutex_unlock(x) #define MUTEX_INIT(x) pthread_mutex_init(x, NULL) #define MUTEX_DEST(x) pthread_mutex_destroy(x) #define DLOPEN(x) dlopen(x, RTLD_LAZY) #define DLCLOSE(x) dlclose(x) #define DLSYM(x, y) dlsym(x, y) #ifdef SOCI_ABI_VERSION #ifdef __APPLE__ #define LIBNAME(x) (SOCI_LIB_PREFIX + x + "." SOCI_ABI_VERSION SOCI_LIB_SUFFIX) #else #define LIBNAME(x) (SOCI_LIB_PREFIX + x + SOCI_LIB_SUFFIX "." SOCI_ABI_VERSION) #endif #else #define LIBNAME(x) (SOCI_LIB_PREFIX + x + SOCI_LIB_SUFFIX) #endif // SOCI_ABI_VERSION #endif // _WIN32 namespace // unnamed { struct info { soci_handler_t handler_; backend_factory const * factory_; info() : handler_(0), factory_(0) {} }; typedef std::map factory_map; factory_map factories_; std::vector search_paths_; soci_mutex_t mutex_; std::vector get_default_paths() { std::vector paths; // TODO: may be problem with finding getenv in std namespace in Visual C++ --mloskot char const* const penv = std::getenv("SOCI_BACKENDS_PATH"); if (0 == penv) { paths.push_back("."); paths.push_back(DEFAULT_BACKENDS_PATH); return paths; } std::string const env = penv; if (env.empty()) { paths.push_back("."); paths.push_back(DEFAULT_BACKENDS_PATH); return paths; } std::string::size_type searchFrom = 0; while (searchFrom != env.size()) { std::string::size_type const found = env.find(":", searchFrom); if (found == searchFrom) { ++searchFrom; } else if (std::string::npos != found) { std::string const path(env.substr(searchFrom, found - searchFrom)); paths.push_back(path); searchFrom = found + 1; } else // found == npos { std::string const path = env.substr(searchFrom); paths.push_back(path); searchFrom = env.size(); } } return paths; } // used to automatically initialize the global state struct static_state_mgr { static_state_mgr() { MUTEX_INIT(&mutex_); search_paths_ = get_default_paths(); } ~static_state_mgr() { unload_all(); MUTEX_DEST(&mutex_); } } static_state_mgr_; class scoped_lock { public: scoped_lock(soci_mutex_t * m) : mptr(m) { LOCK(m); }; ~scoped_lock() { UNLOCK(mptr); }; private: soci_mutex_t * mptr; }; // non-synchronized helper for the other functions void do_unload(std::string const & name) { factory_map::iterator i = factories_.find(name); if (i != factories_.end()) { soci_handler_t h = i->second.handler_; if (h != NULL) { DLCLOSE(h); } factories_.erase(i); } } // non-synchronized helper void do_register_backend(std::string const & name, std::string const & shared_object) { // The rules for backend search are as follows: // - if the shared_object is given, // it names the library file and the search paths are not used // - otherwise (shared_object not provided or empty): // - file named libsoci_NAME.so.SOVERSION is searched in the list of search paths soci_handler_t h = 0; if (shared_object.empty() == false) { h = DLOPEN(shared_object.c_str()); } else { // try system paths h = DLOPEN(LIBNAME(name).c_str()); if (0 == h) { // try all search paths for (std::size_t i = 0; i != search_paths_.size(); ++i) { std::string const fullFileName(search_paths_[i] + "/" + LIBNAME(name)); h = DLOPEN(fullFileName.c_str()); if (0 != h) { // already found break; } } } } if (0 == h) { throw soci_error("Failed to find shared library for backend " + name); } std::string symbol = "factory_" + name; typedef backend_factory const * bfc_ptr; typedef bfc_ptr (*get_t)(void); get_t entry; entry = reinterpret_cast( reinterpret_cast(DLSYM(h, symbol.c_str()))); if (0 == entry) { DLCLOSE(h); throw soci_error("Failed to resolve dynamic symbol: " + symbol); } // unload the existing handler if it's already loaded do_unload(name); backend_factory const* f = entry(); info new_entry; new_entry.factory_ = f; new_entry.handler_ = h; factories_[name] = new_entry; } } // unnamed namespace backend_factory const& dynamic_backends::get(std::string const& name) { scoped_lock lock(&mutex_); factory_map::iterator i = factories_.find(name); if (i != factories_.end()) { return *(i->second.factory_); } // no backend found with this name, try to register it first do_register_backend(name, std::string()); // second attempt, must succeed (the backend is already loaded) i = factories_.find(name); assert(i != factories_.end()); return *(i->second.factory_); } SOCI_DECL std::vector& search_paths() { return search_paths_; } SOCI_DECL void dynamic_backends::register_backend( std::string const& name, std::string const& shared_object) { scoped_lock lock(&mutex_); do_register_backend(name, shared_object); } SOCI_DECL void dynamic_backends::register_backend( std::string const& name, backend_factory const& factory) { scoped_lock lock(&mutex_); // unload the existing handler if it's already loaded do_unload(name); info new_entry; new_entry.factory_ = &factory; factories_[name] = new_entry; } SOCI_DECL std::vector dynamic_backends::list_all() { scoped_lock lock(&mutex_); std::vector ret; ret.reserve(factories_.size()); for (factory_map::iterator i = factories_.begin(); i != factories_.end(); ++i) { std::string const& name = i->first; ret.push_back(name); } return ret; } SOCI_DECL void dynamic_backends::unload(std::string const& name) { scoped_lock lock(&mutex_); do_unload(name); } SOCI_DECL void dynamic_backends::unload_all() { scoped_lock lock(&mutex_); for (factory_map::iterator i = factories_.begin(); i != factories_.end(); ++i) { soci_handler_t h = i->second.handler_; if (0 != h) { DLCLOSE(h); } } factories_.clear(); } soci-3.2.3/core/blob.h0000644000000000000000000000170512511362240013170 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_BLOB_H_INCLUDED #define SOCI_BLOB_H_INCLUDED #include "soci-config.h" // std #include namespace soci { // basic blob operations class session; namespace details { class blob_backend; } // namespace details class SOCI_DECL blob { public: explicit blob(session & s); ~blob(); std::size_t get_len(); std::size_t read(std::size_t offset, char * buf, std::size_t toRead); std::size_t write(std::size_t offset, char const * buf, std::size_t toWrite); std::size_t append(char const * buf, std::size_t toWrite); void trim(std::size_t newLen); details::blob_backend * get_backend() { return backEnd_; } private: details::blob_backend * backEnd_; }; } // namespace soci #endif soci-3.2.3/core/rowset.h0000644000000000000000000001061012511362240013570 0ustar rootroot// // Copyright (C) 2006-2008 Mateusz Loskot // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_ROWSET_H_INCLUDED #define SOCI_ROWSET_H_INCLUDED #include "statement.h" // std #include #include namespace soci { // // rowset iterator of input category. // template class rowset_iterator { public: // Standard iterator traits typedef std::input_iterator_tag iterator_category; typedef T value_type; typedef T * pointer; typedef T & reference; typedef ptrdiff_t difference_type; // Constructors rowset_iterator() : st_(0), define_(0) {} rowset_iterator(statement & st, T & define) : st_(&st), define_(&define) { assert(0 != st_); assert(0 != define_); assert(0 != st_->get_backend()); // Fetch first row to properly initialize iterator ++(*this); } // Access operators reference operator*() const { return (*define_); } pointer operator->() const { return &(operator*()); } // Iteration operators rowset_iterator & operator++() { // Fetch next row from dataset if (st_->fetch() == false) { // Set iterator to non-derefencable state (pass-the-end) st_ = 0; define_ = 0; } return (*this); } rowset_iterator operator++(int) { rowset_iterator tmp(*this); ++(*this); return tmp; } // Comparison operators bool operator==(rowset_iterator const & rhs) const { return (st_== rhs.st_ && define_ == rhs.define_); } bool operator!=(rowset_iterator const & rhs) const { return ((*this == rhs) == false); } private: statement * st_; T * define_; }; // class rowset_iterator namespace details { // // Implementation of rowset // template class rowset_impl { public: typedef rowset_iterator iterator; rowset_impl(details::prepare_temp_type const & prep) : refs_(1), st_(new statement(prep)), define_(new T()) { assert(0 != st_.get()); assert(0 != define_.get()); st_->exchange_for_rowset(into(*define_)); st_->execute(); } void incRef() { ++refs_; } void decRef() { if (--refs_ == 0) { delete this; } } iterator begin() const { // No ownership transfer occurs here return iterator(*st_, *define_); } iterator end() const { return iterator(); } private: unsigned int refs_; const std::auto_ptr st_; const std::auto_ptr define_; // Non-copyable rowset_impl(rowset_impl const &); rowset_impl & operator=(rowset_impl const &); }; // class rowset_impl } // namespace details // // rowset is a thin wrapper on statement and provides access to STL-like input iterator. // The rowset_iterator can be used to easily loop through statement results and // use STL algorithms accepting input iterators. // template class rowset { public: typedef T value_type; typedef rowset_iterator iterator; typedef rowset_iterator const_iterator; // this is a conversion constructor rowset(details::prepare_temp_type const& prep) : pimpl_(new details::rowset_impl(prep)) { assert(0 != pimpl_); } rowset(rowset const & other) : pimpl_(other.pimpl_) { assert(0 != pimpl_); pimpl_->incRef(); } ~rowset() { assert(0 != pimpl_); pimpl_->decRef(); } rowset& operator=(rowset const& rhs) { assert(0 != pimpl_); assert(0 != rhs.pimpl_); if (&rhs != this) { rhs.pimpl_->incRef(); pimpl_->decRef(); pimpl_ = rhs.pimpl_; } return *this; } const_iterator begin() const { assert(0 != pimpl_); return pimpl_->begin(); } const_iterator end() const { assert(0 != pimpl_); return pimpl_->end(); } private: // Pointer to implementation - the body details::rowset_impl* pimpl_; }; // class rowset } // namespace soci #endif // SOCI_ROWSET_H_INCLUDED soci-3.2.3/core/exchange-traits.h0000644000000000000000000000537612511362240015350 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_EXCHANGE_TRAITS_H_INCLUDED #define SOCI_EXCHANGE_TRAITS_H_INCLUDED #include "type-conversion-traits.h" #include "soci-backend.h" // std #include #include #include namespace soci { namespace details { struct basic_type_tag {}; struct user_type_tag {}; template struct exchange_traits { // this is used for tag-dispatch between implementations for basic types // and user-defined types typedef user_type_tag type_family; enum // anonymous { x_type = exchange_traits < typename type_conversion::base_type >::x_type }; }; template <> struct exchange_traits { typedef basic_type_tag type_family; enum { x_type = x_short }; }; template <> struct exchange_traits : exchange_traits { }; template <> struct exchange_traits { typedef basic_type_tag type_family; enum { x_type = x_integer }; }; template <> struct exchange_traits : exchange_traits { }; template <> struct exchange_traits { typedef basic_type_tag type_family; enum { x_type = x_char }; }; template <> struct exchange_traits { typedef basic_type_tag type_family; enum { x_type = x_long_long }; }; template <> struct exchange_traits { typedef basic_type_tag type_family; enum { x_type = x_unsigned_long_long }; }; // long must be mapped either to x_integer or x_long_long: template struct long_traits_helper; template<> struct long_traits_helper<4> { enum { x_type = x_integer }; }; template<> struct long_traits_helper<8> { enum { x_type = x_long_long }; }; template <> struct exchange_traits { typedef basic_type_tag type_family; enum { x_type = long_traits_helper::x_type }; }; template <> struct exchange_traits : exchange_traits { }; template <> struct exchange_traits { typedef basic_type_tag type_family; enum { x_type = x_double }; }; template <> struct exchange_traits { typedef basic_type_tag type_family; enum { x_type = x_stdstring }; }; template <> struct exchange_traits { typedef basic_type_tag type_family; enum { x_type = x_stdtm }; }; template struct exchange_traits > { typedef typename exchange_traits::type_family type_family; enum { x_type = exchange_traits::x_type }; }; } // namespace details } // namespace soci #endif // SOCI_EXCHANGE_TRAITS_H_INCLUDED soci-3.2.3/core/ref-counted-statement.cpp0000644000000000000000000000164312511361676017037 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "ref-counted-statement.h" #include "session.h" using namespace soci; using namespace soci::details; ref_counted_statement_base::ref_counted_statement_base(session& s) : refCount_(1) , session_(s) { } void ref_counted_statement::final_action() { try { st_.alloc(); st_.prepare(session_.get_query(), st_one_time_query); st_.define_and_bind(); const bool gotData = st_.execute(true); session_.set_got_data(gotData); } catch (...) { st_.clean_up(); throw; } st_.clean_up(); } std::ostringstream& ref_counted_statement_base::get_query_stream() { return session_.get_query_stream(); } soci-3.2.3/core/bind-values.h0000644000000000000000000001227012511401144014457 0ustar rootroot#ifndef SOCI_BIND_VALUES_H_INCLUDED #define SOCI_BIND_VALUES_H_INCLUDED #include "exchange-traits.h" #include "into-type.h" #include "into.h" #include "soci-backend.h" #include "use-type.h" #include "use.h" #ifdef HAVE_BOOST # include # include #endif // HAVE_BOOST #include namespace soci { namespace details { class use_type_vector: public std::vector { public: ~use_type_vector() { for(iterator iter = begin(), _end = end(); iter != _end; iter++) delete *iter; } void exchange(use_type_ptr const& u) { push_back(u.get()); u.release(); } template void exchange(use_container const &uc) { #ifdef HAVE_BOOST exchange_(uc, (typename boost::fusion::traits::is_sequence::type *)NULL); #else exchange_(uc, NULL); #endif // HAVE_BOOST } private: #ifdef HAVE_BOOST template struct use_sequence { use_sequence(use_type_vector &_p, Indicator &_ind) :p(_p), ind(_ind) {} template void operator()(T2 &t2) const { p.exchange(use(t2, ind)); } use_type_vector &p; Indicator &ind; }; template struct use_sequence { use_sequence(use_type_vector &_p) :p(_p) {} template void operator()(T2 &t2) const { p.exchange(use(t2)); } use_type_vector &p; }; template void exchange_(use_container const &uc, boost::mpl::true_ * /* fusion sequence */) { boost::fusion::for_each(uc.t, use_sequence(*this, uc.ind)); } template void exchange_(use_container const &uc, boost::mpl::true_ * /* fusion sequence */) { boost::fusion::for_each(uc.t, use_sequence(*this)); } #endif // HAVE_BOOST template void exchange_(use_container const &uc, ...) { exchange(do_use(uc.t, uc.ind, uc.name, typename details::exchange_traits::type_family())); } template void exchange_(use_container const &uc, ...) { exchange(do_use(uc.t, uc.name, typename details::exchange_traits::type_family())); } template void exchange_(use_container const &uc, ...) { exchange(do_use(uc.t, uc.ind, uc.name, typename details::exchange_traits::type_family())); } template void exchange_(use_container const &uc, ...) { exchange(do_use(uc.t, uc.name, typename details::exchange_traits::type_family())); } }; class into_type_vector: public std::vector { public: ~into_type_vector() { for(iterator iter = begin(), _end = end(); iter != _end; iter++) delete *iter; } void exchange(into_type_ptr const& i) { push_back(i.get()); i.release(); } template void exchange(into_container const &ic) { #ifdef HAVE_BOOST exchange_(ic, (typename boost::fusion::traits::is_sequence::type *)NULL); #else exchange_(ic, NULL); #endif // HAVE_BOOST } private: #ifdef HAVE_BOOST template struct into_sequence { into_sequence(into_type_vector &_p, Indicator &_ind) :p(_p), ind(_ind) {} template void operator()(T2 &t2) const { p.exchange(into(t2, ind)); } into_type_vector &p; Indicator &ind; }; template struct into_sequence { into_sequence(into_type_vector &_p) :p(_p) {} template void operator()(T2 &t2) const { p.exchange(into(t2)); } into_type_vector &p; }; template void exchange_(into_container const &ic, boost::mpl::true_ * /* fusion sequence */) { boost::fusion::for_each(ic.t, into_sequence(*this, ic.ind)); } template void exchange_(into_container const &ic, boost::mpl::true_ * /* fusion sequence */) { boost::fusion::for_each(ic.t, into_sequence(*this)); } #endif // HAVE_BOOST template void exchange_(into_container const &ic, ...) { exchange(do_into(ic.t, ic.ind, typename details::exchange_traits::type_family())); } template void exchange_(into_container const &ic, ...) { exchange(do_into(ic.t, typename details::exchange_traits::type_family())); } }; } // namespace details }// namespace soci #endif // SOCI_BIND_VALUES_H_INCLUDED soci-3.2.3/core/type-conversion-traits.h0000644000000000000000000000173712511362240016727 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_TYPE_CONVERSION_TRAITS_H_INCLUDED #define SOCI_TYPE_CONVERSION_TRAITS_H_INCLUDED #include "soci-backend.h" namespace soci { // default traits class type_conversion, acts as pass through for row::get() // when no actual conversion is needed. template struct type_conversion { typedef T base_type; static void from_base(base_type const & in, indicator ind, T & out) { if (ind == i_null) { throw soci_error("Null value not allowed for this type"); } out = in; } static void to_base(T const & in, base_type & out, indicator & ind) { out = in; ind = i_ok; } }; } // namespace soci #endif // SOCI_TYPE_CONVERSION_TRAITS_H_INCLUDED soci-3.2.3/core/values.h0000644000000000000000000002225112511362240013550 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_VALUES_H_INCLUDED #define SOCI_VALUES_H_INCLUDED #include "statement.h" #include "into-type.h" #include "use-type.h" // std #include #include #include #include #include #include namespace soci { namespace details { class copy_base { public: virtual ~copy_base() {} }; template struct copy_holder : public copy_base { copy_holder(T const & v) : value_(v) {} T value_; }; } // namespace details class SOCI_DECL values { friend class details::statement_impl; friend class details::into_type; friend class details::use_type; public: values() : row_(NULL), currentPos_(0), uppercaseColumnNames_(false) {} indicator get_indicator(std::size_t pos) const; indicator get_indicator(std::string const & name) const; template T get(std::size_t pos) const { if (row_ != NULL) { return row_->get(pos); } else if (*indicators_[pos] != i_null) { return get_from_uses(pos); } else { std::ostringstream msg; msg << "Column at position " << static_cast(pos) << " contains NULL value and no default was provided"; throw soci_error(msg.str()); } } template T get(std::size_t pos, T const & nullValue) const { if (row_ != NULL) { return row_->get(pos, nullValue); } else if (*indicators_[pos] == i_null) { return nullValue; } else { return get_from_uses(pos); } } template T get(std::string const & name) const { return row_ != NULL ? row_->get(name) : get_from_uses(name); } template T get(std::string const & name, T const & nullValue) const { return row_ != NULL ? row_->get(name, nullValue) : get_from_uses(name, nullValue); } template values const & operator>>(T & value) const { if (row_ != NULL) { // row maintains its own position counter // which is automatically reset when needed *row_ >> value; } else if (*indicators_[currentPos_] != i_null) { // if there is no row object, then the data can be // extracted from the locally stored use elements, // but for this the position counter has to be maintained // as well value = get_from_uses(currentPos_); ++currentPos_; } else { std::ostringstream msg; msg << "Column at position " << static_cast(currentPos_) << " contains NULL value and no default was provided"; throw soci_error(msg.str()); } return *this; } void skip(std::size_t num = 1) const { if (row_ != NULL) { row_->skip(num); } else { currentPos_ += num; } } void reset_get_counter() const { if (row_ != NULL) { row_->reset_get_counter(); } else { currentPos_ = 0; } } template void set(std::string const & name, T const & value, indicator indic = i_ok) { typedef typename type_conversion::base_type base_type; if(index_.find(name) == index_.end()) { index_.insert(std::make_pair(name, uses_.size())); indicator * pind = new indicator(indic); indicators_.push_back(pind); base_type baseValue; if (indic == i_ok) { type_conversion::to_base(value, baseValue, *pind); } details::copy_holder * pcopy = new details::copy_holder(baseValue); deepCopies_.push_back(pcopy); uses_.push_back(new details::use_type( pcopy->value_, *pind, name)); } else { size_t index = index_.find(name)->second; *indicators_[index] = indic; if (indic == i_ok) { type_conversion::to_base( value, static_cast*>(deepCopies_[index])->value_, *indicators_[index]); } } } template void set(const T & value, indicator indic = i_ok) { indicator * pind = new indicator(indic); indicators_.push_back(pind); typedef typename type_conversion::base_type base_type; base_type baseValue; type_conversion::to_base(value, baseValue, *pind); details::copy_holder * pcopy = new details::copy_holder(baseValue); deepCopies_.push_back(pcopy); uses_.push_back(new details::use_type( pcopy->value_, *pind)); } template values & operator<<(T const & value) { set(value); return *this; } void uppercase_column_names(bool forceToUpper) { uppercaseColumnNames_ = forceToUpper; } column_properties const& get_properties(std::size_t pos) const; column_properties const& get_properties(std::string const &name) const; private: //TODO To make values generally usable outside of type_conversion's, // these should be reference counted smart pointers row * row_; std::vector uses_; std::map unused_; std::vector indicators_; std::map index_; std::vector deepCopies_; mutable std::size_t currentPos_; bool uppercaseColumnNames_; // When type_conversion::to() is called, a values object is created // without an underlying row object. In that case, get_from_uses() // returns the underlying field values template T get_from_uses(std::string const & name, T const & nullValue) const { std::map::const_iterator pos = index_.find(name); if (pos != index_.end()) { if (*indicators_[pos->second] == i_null) { return nullValue; } return get_from_uses(pos->second); } throw soci_error("Value named " + name + " not found."); } template T get_from_uses(std::string const & name) const { std::map::const_iterator pos = index_.find(name); if (pos != index_.end()) { return get_from_uses(pos->second); } throw soci_error("Value named " + name + " not found."); } template T get_from_uses(std::size_t pos) const { details::standard_use_type* u = uses_[pos]; typedef typename type_conversion::base_type base_type; if (dynamic_cast *>(u)) { base_type const & baseValue = *static_cast(u->get_data()); T val; indicator ind = *indicators_[pos]; type_conversion::from_base(baseValue, ind, val); return val; } else { std::ostringstream msg; msg << "Value at position " << static_cast(pos) << " was set using a different type" " than the one passed to get()"; throw soci_error(msg.str()); } } row& get_row() { row_ = new row(); row_->uppercase_column_names(uppercaseColumnNames_); return * row_; } // this is called by Statement::bind(values) void add_unused(details::use_type_base * u, indicator * i) { static_cast(u)->convert_to_base(); unused_.insert(std::make_pair(u, i)); } // this is called by details::into_type::clean_up() // and use_type::clean_up() void clean_up() { delete row_; row_ = NULL; // delete any uses and indicators which were created by set() but // were not bound by the Statement // (bound uses and indicators are deleted in Statement::clean_up()) for (std::map::iterator pos = unused_.begin(); pos != unused_.end(); ++pos) { delete pos->first; delete pos->second; } for (std::size_t i = 0; i != deepCopies_.size(); ++i) { delete deepCopies_[i]; } } }; } // namespace soci #endif // SOCI_VALUES_H_INCLUDED soci-3.2.3/core/soci.h0000644000000000000000000000273112511362240013207 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_H_INCLUDED #define SOCI_H_INCLUDED #ifdef _MSC_VER #pragma warning(disable:4251 4512 4511) #endif // namespace soci #include "backend-loader.h" #include "blob.h" #include "blob-exchange.h" #include "connection-pool.h" #include "error.h" #include "exchange-traits.h" #include "into.h" #include "into-type.h" #include "once-temp-type.h" #include "prepare-temp-type.h" #include "procedure.h" #include "ref-counted-prepare-info.h" #include "ref-counted-statement.h" #include "row.h" #include "row-exchange.h" #include "rowid.h" #include "rowid-exchange.h" #include "rowset.h" #include "session.h" #include "soci-backend.h" #include "soci-config.h" #include "soci-platform.h" #include "statement.h" #include "transaction.h" #include "type-conversion.h" #include "type-conversion-traits.h" #include "type-holder.h" #include "type-ptr.h" #include "unsigned-types.h" #include "use.h" #include "use-type.h" #include "values.h" #include "values-exchange.h" // namespace boost #ifdef SOCI_USE_BOOST #include #if defined(BOOST_VERSION) && BOOST_VERSION >= 103500 #include "boost-fusion.h" #endif // BOOST_VERSION #include "boost-optional.h" #include "boost-tuple.h" #include "boost-gregorian-date.h" #endif // SOCI_USE_BOOST #endif // SOCI_H_INCLUDED soci-3.2.3/core/ref-counted-prepare-info.h0000644000000000000000000000277512511401146017061 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_REF_COUNTED_PREPARE_INFO_INCLUDED #define SOCI_REF_COUNTED_PREPARE_INFO_INCLUDED #include "bind-values.h" #include "ref-counted-statement.h" // std #include #include namespace soci { class session; namespace details { class procedure_impl; class statement_impl; class into_type_base; // this class conveys only the statement text and the bind/define info // it exists only to be passed to statement's constructor class ref_counted_prepare_info : public ref_counted_statement_base { public: ref_counted_prepare_info(session& s) : ref_counted_statement_base(s) , session_(s) {} void exchange(use_type_ptr const& u) { uses_.exchange(u); } template void exchange(use_container const &uc) { uses_.exchange(uc); } void exchange(into_type_ptr const& i) { intos_.exchange(i); } template void exchange(into_container const &ic) { intos_.exchange(ic); } void final_action(); private: friend class statement_impl; friend class procedure_impl; session& session_; into_type_vector intos_; use_type_vector uses_; std::string get_query() const; }; } // namespace details } // namespace soci #endif soci-3.2.3/core/CMakeLists.txt0000644000000000000000000001110312511362240014632 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2009-2010 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### colormsg(_HIBLUE_ "Configuring SOCI core library:") # Core dependencies set(SOCI_CORE_DEPENDENCIES) include(FindThreads) if(Threads_FOUND OR CMAKE_USE_WIN32_THREADS_INIT OR CMAKE_THREAD_LIBS_INIT) list(APPEND SOCI_CORE_DEPENDENCIES ${CMAKE_THREAD_LIBS_INIT}) else() message(FATAL_ERROR "No thread library found") endif() if(NOT MSVC) set(DL_FIND_QUIETLY TRUE) find_package(DL) if(DL_FOUND) list(APPEND SOCI_CORE_DEPENDENCIES ${DL_LIBRARY}) set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES ${DL_INCLUDE_DIR}) add_definitions(-DHAVE_DL=1) endif() endif() if(Boost_FOUND) get_property(SOCI_COMPILE_DEFINITIONS DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS) list(APPEND SOCI_COMPILE_DEFINITIONS "HAVE_BOOST=1") if(Boost_DATE_TIME_FOUND) list(APPEND SOCI_CORE_DEPENDENCIES ${Boost_DATE_TIME_LIBRARY}) list(APPEND SOCI_COMPILE_DEFINITIONS "HAVE_BOOST_DATE_TIME=1") endif() set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS ${SOCI_COMPILE_DEFINITIONS}) set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIRS}) set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIRS}) endif() # Core source files file(GLOB SOCI_CORE_HEADERS *.h) file(GLOB SOCI_CORE_SOURCES *.cpp) # Group source files for IDE source explorers (e.g. Visual Studio) source_group("Header Files" FILES ${SOCI_CORE_HEADERS}) source_group("Source Files" FILES ${SOCI_CORE_SOURCES}) source_group("CMake Files" FILES CMakeLists.txt) # Core targets configuration string(TOLOWER "${PROJECT_NAME}" PROJECTNAMEL) set(SOCI_CORE_TARGET ${PROJECTNAMEL}_core) soci_target_output_name(${SOCI_CORE_TARGET} SOCI_CORE_TARGET_OUTPUT_NAME) # Configure SOCI backend loader to also use default install directory. set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}) set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}) configure_file(soci_backends_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/soci_backends_config.h) # # Core shared library # if (SOCI_SHARED) add_library(${SOCI_CORE_TARGET} SHARED ${SOCI_CORE_HEADERS} ${SOCI_CORE_SOURCES}) target_link_libraries(${SOCI_CORE_TARGET} ${SOCI_CORE_DEPENDENCIES}) if(WIN32) set_target_properties(${SOCI_CORE_TARGET} PROPERTIES DEFINE_SYMBOL SOCI_DLL OUTPUT_NAME "${SOCI_CORE_TARGET_OUTPUT_NAME}" VERSION ${SOCI_VERSION} CLEAN_DIRECT_OUTPUT 1) else() set_target_properties(${SOCI_CORE_TARGET} PROPERTIES VERSION ${SOCI_VERSION} SOVERSION ${SOCI_SOVERSION} INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib CLEAN_DIRECT_OUTPUT 1) endif() endif() add_definitions(-DSOCI_LIB_PREFIX="${CMAKE_SHARED_LIBRARY_PREFIX}soci_" -DSOCI_LIB_SUFFIX="${CMAKE_SHARED_LIBRARY_SUFFIX}") # # Core static library # if (SOCI_STATIC) set(SOCI_CORE_TARGET_STATIC ${SOCI_CORE_TARGET}_static) add_library(${SOCI_CORE_TARGET_STATIC} STATIC ${SOCI_CORE_HEADERS} ${SOCI_CORE_SOURCES}) set_target_properties(${SOCI_CORE_TARGET_STATIC} PROPERTIES OUTPUT_NAME ${SOCI_CORE_TARGET_OUTPUT_NAME} PREFIX "lib" CLEAN_DIRECT_OUTPUT 1) endif() # # Core installation # install(FILES ${SOCI_CORE_HEADERS} DESTINATION ${INCLUDEDIR}/${PROJECTNAMEL}) if (SOCI_SHARED) install(TARGETS ${SOCI_CORE_TARGET} RUNTIME DESTINATION ${BINDIR} LIBRARY DESTINATION ${LIBDIR} ARCHIVE DESTINATION ${LIBDIR}) endif() if (SOCI_STATIC) install(TARGETS ${SOCI_CORE_TARGET_STATIC} RUNTIME DESTINATION ${BINDIR} LIBRARY DESTINATION ${LIBDIR} ARCHIVE DESTINATION ${LIBDIR}) endif() # # Core configuration summary # boost_report_value(SOCI_CORE_TARGET) boost_report_value(SOCI_CORE_TARGET_OUTPUT_NAME) boost_report_value(SOCI_CORE_DEPENDENCIES) boost_report_value(WITH_BOOST) soci_report_directory_property(COMPILE_DEFINITIONS) # Export core target name to make it visible by backends set(SOCI_CORE_TARGET ${SOCI_CORE_TARGET} PARENT_SCOPE) if (SOCI_STATIC) set(SOCI_CORE_TARGET_STATIC ${SOCI_CORE_TARGET_STATIC} PARENT_SCOPE) endif() set(SOCI_CORE_STATIC_DEPENDENCIES ${SOCI_CORE_DEPENDENCIES} PARENT_SCOPE) soci-3.2.3/core/rowid.cpp0000644000000000000000000000067712511361676013754 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define SOCI_SOURCE #include "rowid.h" #include "session.h" using namespace soci; using namespace soci::details; rowid::rowid(session & s) { backEnd_ = s.make_rowid_backend(); } rowid::~rowid() { delete backEnd_; } soci-3.2.3/core/into.h0000644000000000000000000000304412511401144013216 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_INTO_H_INCLUDED #define SOCI_INTO_H_INCLUDED #include "into-type.h" #include "exchange-traits.h" #include "type-conversion.h" // std #include #include namespace soci { // the into function is a helper for defining output variables // these helpers work with both basic and user-defined types thanks to // the tag-dispatching, as defined in exchange_traits template namespace details { template struct into_container { into_container(T &_t, Indicator &_ind) : t(_t), ind(_ind) {} T &t; Indicator &ind; }; typedef void no_indicator; template struct into_container { into_container(T &_t) : t(_t) {} T &t; }; } // namespace details template details::into_container into(T &t) { return details::into_container(t); } template details::into_container into(T &t, Indicator &ind) { return details::into_container(t, ind); } // for char buffer with run-time size information template details::into_type_ptr into(T & t, std::size_t bufSize) { return details::into_type_ptr(new details::into_type(t, bufSize)); } } // namespace soci #endif // SOCI_INTO_H_INCLUDED soci-3.2.3/core/type-conversion.h0000644000000000000000000002410612511362240015416 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_TYPE_CONVERSION_H_INCLUDED #define SOCI_TYPE_CONVERSION_H_INCLUDED #include "type-conversion-traits.h" #include "into-type.h" #include "use-type.h" // std #include #include #include #include namespace soci { namespace details { // this class is used to ensure correct order of construction // of into_type and use_type elements that use type_conversion template struct base_value_holder { typename type_conversion::base_type val_; }; // Automatically create into_type from a type_conversion template class conversion_into_type : private base_value_holder, public into_type::base_type> { public: typedef typename type_conversion::base_type base_type; conversion_into_type(T & value) : into_type(details::base_value_holder::val_, ownInd_) , value_(value) , ownInd_() , ind_(ownInd_) { assert(ownInd_ == ind_); } conversion_into_type(T & value, indicator & ind) : into_type(details::base_value_holder::val_, ind) , value_(value) , ownInd_(ind) // unused, just keep the pair of indicator(s) consistent , ind_(ind) { assert(ownInd_ == ind_); } private: void convert_from_base() { type_conversion::from_base( details::base_value_holder::val_, ind_, value_); } T & value_; indicator ownInd_; // ind_ refers to either ownInd_, or the one provided by the user // in any case, ind_ refers to some valid indicator // and can be used by conversion routines indicator & ind_; }; // Automatically create use_type from a type_conversion template class conversion_use_type : private details::base_value_holder, public use_type::base_type> { public: typedef typename type_conversion::base_type base_type; conversion_use_type(T & value, std::string const & name = std::string()) : use_type(details::base_value_holder::val_, ownInd_, name) , value_(value) , ownInd_() , ind_(ownInd_) , readOnly_(false) { assert(ownInd_ == ind_); // TODO: likely to be removed (SHA: c166625a28f7c907318134f625ff5acea7d9a1f8) //convert_to_base(); } conversion_use_type(T const & value, std::string const & name = std::string()) : use_type(details::base_value_holder::val_, ownInd_, name) , value_(const_cast(value)) , ownInd_() , ind_(ownInd_) , readOnly_(true) { assert(ownInd_ == ind_); // TODO: likely to be removed (SHA: c166625a28f7c907318134f625ff5acea7d9a1f8) //convert_to_base(); } conversion_use_type(T & value, indicator & ind, std::string const & name = std::string()) : use_type(details::base_value_holder::val_, ind, name) , value_(value) , ind_(ind) , readOnly_(false) { // TODO: likely to be removed (SHA: c166625a28f7c907318134f625ff5acea7d9a1f8) //convert_to_base(); } conversion_use_type(T const & value, indicator & ind, std::string const & name = std::string()) : use_type(details::base_value_holder::val_, ind, name) , value_(const_cast(value)) , ind_(ind) , readOnly_(true) { // TODO: likely to be removed (SHA: c166625a28f7c907318134f625ff5acea7d9a1f8) //convert_to_base(); } void convert_from_base() { // NOTE: // readOnly_ flag indicates that use_type object has been generated // based on non-const object passed by user as input argument. // For const objects, this is effectively no-op conversion. // See standard_use_type::post_use() for more details. if (readOnly_ == false) { type_conversion::from_base( details::base_value_holder::val_, ind_, value_); } } void convert_to_base() { type_conversion::to_base(value_, details::base_value_holder::val_, ind_); } private: T & value_; indicator ownInd_; // ind_ refers to either ownInd_, or the one provided by the user // in any case, ind_ refers to some valid indicator // and can be used by conversion routines indicator & ind_; bool readOnly_; }; // this class is used to ensure correct order of construction // of vector based into_type and use_type elements that use type_conversion template struct base_vector_holder { base_vector_holder(std::size_t sz = 0) : vec_(sz) {} mutable std::vector::base_type> vec_; }; // Automatically create a std::vector based into_type from a type_conversion template class conversion_into_type > : private details::base_vector_holder, public into_type::base_type> > { public: typedef typename std::vector < typename type_conversion::base_type > base_type; conversion_into_type(std::vector & value) : details::base_vector_holder(value.size()) , into_type(details::base_vector_holder::vec_, ownInd_) , value_(value) , ownInd_() , ind_(ownInd_) { assert(ownInd_ == ind_); } conversion_into_type(std::vector & value, std::vector & ind) : details::base_vector_holder(value.size()) , into_type(details::base_vector_holder::vec_, ind) , value_(value) , ind_(ind) {} virtual std::size_t size() const { // the user might have resized his vector in the meantime // -> synchronize the base-value mirror to have the same size std::size_t const userSize = value_.size(); details::base_vector_holder::vec_.resize(userSize); return userSize; } virtual void resize(std::size_t sz) { value_.resize(sz); ind_.resize(sz); details::base_vector_holder::vec_.resize(sz); } private: void convert_from_base() { std::size_t const sz = details::base_vector_holder::vec_.size(); for (std::size_t i = 0; i != sz; ++i) { type_conversion::from_base( details::base_vector_holder::vec_[i], ind_[i], value_[i]); } } std::vector & value_; std::vector ownInd_; // ind_ refers to either ownInd_, or the one provided by the user // in any case, ind_ refers to some valid vector of indicators // and can be used by conversion routines std::vector & ind_; }; // Automatically create a std::vector based use_type from a type_conversion template class conversion_use_type > : private details::base_vector_holder, public use_type::base_type> > { public: typedef typename std::vector < typename type_conversion::base_type > base_type; conversion_use_type(std::vector & value, std::string const & name=std::string()) : details::base_vector_holder(value.size()) , use_type( details::base_vector_holder::vec_, ownInd_, name) , value_(value) , ownInd_() , ind_(ownInd_) { assert(ownInd_ == ind_); } conversion_use_type(std::vector & value, std::vector & ind, std::string const & name = std::string()) : details::base_vector_holder(value.size()) , use_type( details::base_vector_holder::vec_, ind, name) , value_(value) , ind_(ind) {} private: void convert_from_base() { std::size_t const sz = details::base_vector_holder::vec_.size(); value_.resize(sz); ind_.resize(sz); for (std::size_t i = 0; i != sz; ++i) { type_conversion::from_base( details::base_vector_holder::vec_[i], value_[i], ind_[i]); } } void convert_to_base() { std::size_t const sz = value_.size(); details::base_vector_holder::vec_.resize(sz); ind_.resize(sz); for (std::size_t i = 0; i != sz; ++i) { type_conversion::to_base(value_[i], details::base_vector_holder::vec_[i], ind_[i]); } } std::vector & value_; std::vector ownInd_; // ind_ refers to either ownInd_, or the one provided by the user // in any case, ind_ refers to some valid vector of indicators // and can be used by conversion routines std::vector & ind_; }; template into_type_ptr do_into(T & t, user_type_tag) { return into_type_ptr(new conversion_into_type(t)); } template into_type_ptr do_into(T & t, indicator & ind, user_type_tag) { return into_type_ptr(new conversion_into_type(t, ind)); } template use_type_ptr do_use(T & t, std::string const & name, user_type_tag) { return use_type_ptr(new conversion_use_type(t, name)); } template use_type_ptr do_use(T const & t, std::string const & name, user_type_tag) { return use_type_ptr(new conversion_use_type(t, name)); } template use_type_ptr do_use(T & t, indicator & ind, std::string const & name, user_type_tag) { return use_type_ptr(new conversion_use_type(t, ind, name)); } template use_type_ptr do_use(T const & t, indicator & ind, std::string const & name, user_type_tag) { return use_type_ptr(new conversion_use_type(t, ind, name)); } } // namespace details } // namespace soci #endif // SOCI_TYPE_CONVERSION_H_INCLUDED soci-3.2.3/core/procedure.h0000644000000000000000000000330512511362240014240 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_PROCEDURE_H_INCLUDED #define SOCI_PROCEDURE_H_INCLUDED #include "statement.h" namespace soci { namespace details { class SOCI_DECL procedure_impl : public statement_impl { public: procedure_impl(session & s) : statement_impl(s), refCount_(1) {} procedure_impl(prepare_temp_type const & prep); void inc_ref() { ++refCount_; } void dec_ref() { if (--refCount_ == 0) { delete this; } } private: int refCount_; }; } // namespace details class SOCI_DECL procedure { public: // this is a conversion constructor procedure(details::prepare_temp_type const & prep) : impl_(new details::procedure_impl(prep)) {} ~procedure() { impl_->dec_ref(); } // copy is supported here procedure(procedure const & other) : impl_(other.impl_) { impl_->inc_ref(); } void operator=(procedure const & other) { other.impl_->inc_ref(); impl_->dec_ref(); impl_ = other.impl_; } // forwarders to procedure_impl // (or rather to its base interface from statement_impl) bool execute(bool withDataExchange = false) { gotData_ = impl_->execute(withDataExchange); return gotData_; } bool fetch() { gotData_ = impl_->fetch(); return gotData_; } bool got_data() const { return gotData_; } private: details::procedure_impl * impl_; bool gotData_; }; } // namespace soci #endif soci-3.2.3/core/statement.h0000644000000000000000000002074012511401146014255 0ustar rootroot// // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_STATEMENT_H_INCLUDED #define SOCI_STATEMENT_H_INCLUDED #include "bind-values.h" #include "into-type.h" #include "into.h" #include "use-type.h" #include "use.h" #include "soci-backend.h" #include "row.h" // std #include #include #include #include namespace soci { class session; class values; namespace details { class into_type_base; class use_type_base; class prepare_temp_type; class SOCI_DECL statement_impl { public: explicit statement_impl(session & s); explicit statement_impl(prepare_temp_type const & prep); ~statement_impl(); void alloc(); void bind(values & v); void exchange(into_type_ptr const & i) { intos_.exchange(i); } template void exchange(into_container const &ic) { intos_.exchange(ic); } void exchange(use_type_ptr const & u) { uses_.exchange(u); } template void exchange(use_container const &uc) { uses_.exchange(uc); } void clean_up(); void prepare(std::string const & query, statement_type eType = st_repeatable_query); void define_and_bind(); void undefine_and_bind(); bool execute(bool withDataExchange = false); long long get_affected_rows(); bool fetch(); void describe(); void set_row(row * r); void exchange_for_rowset(into_type_ptr const & i) { exchange_for_rowset_(i); } template void exchange_for_rowset(into_container const &ic) { exchange_for_rowset_(ic); } // for diagnostics and advanced users // (downcast it to expected back-end statement class) statement_backend * get_backend() { return backEnd_; } standard_into_type_backend * make_into_type_backend(); standard_use_type_backend * make_use_type_backend(); vector_into_type_backend * make_vector_into_type_backend(); vector_use_type_backend * make_vector_use_type_backend(); void inc_ref(); void dec_ref(); session & session_; std::string rewrite_for_procedure_call(std::string const & query); protected: into_type_vector intos_; use_type_vector uses_; std::vector indicators_; private: int refCount_; row * row_; std::size_t fetchSize_; std::size_t initialFetchSize_; std::string query_; std::map namedUses_; into_type_vector intosForRow_; int definePositionForRow_; template void exchange_for_rowset_(Into const &i) { if (intos_.empty() == false) { throw soci_error("Explicit into elements not allowed with rowset."); } intos_.exchange(i); int definePosition = 1; for(into_type_vector::iterator iter = intos_.begin(), end = intos_.end(); iter != end; iter++) { (*iter)->define(*this, definePosition); } definePositionForRow_ = definePosition; } template void exchange_for_row(into_container const &ic) { intosForRow_.exchange(ic); } void exchange_for_row(into_type_ptr const & i) { intosForRow_.exchange(i); } void define_for_row(); template void into_row() { T * t = new T(); indicator * ind = new indicator(i_ok); row_->add_holder(t, ind); exchange_for_row(into(*t, *ind)); } template void bind_into(); bool alreadyDescribed_; std::size_t intos_size(); std::size_t uses_size(); void pre_fetch(); void pre_use(); void post_fetch(bool gotData, bool calledFromFetch); void post_use(bool gotData); bool resize_intos(std::size_t upperBound = 0); void truncate_intos(); soci::details::statement_backend * backEnd_; // The type is noncopyable. statement_impl(statement_impl const &); statement_impl& operator=(statement_impl const &); }; } // namespace details // Statement is a handle class for statement_impl // (this provides copyability to otherwise non-copyable type) class SOCI_DECL statement { public: statement(session & s) : impl_(new details::statement_impl(s)) {} statement(details::prepare_temp_type const & prep) : impl_(new details::statement_impl(prep)) {} ~statement() { impl_->dec_ref(); } // copy is supported for this handle class statement(statement const & other) : impl_(other.impl_) { impl_->inc_ref(); } void operator=(statement const & other) { other.impl_->inc_ref(); impl_->dec_ref(); impl_ = other.impl_; } void alloc() { impl_->alloc(); } void bind(values & v) { impl_->bind(v); } void exchange(details::into_type_ptr const & i) { impl_->exchange(i); } template void exchange(details::into_container const &ic) { impl_->exchange(ic); } void exchange(details::use_type_ptr const & u) { impl_->exchange(u); } template void exchange(details::use_container const &uc) { impl_->exchange(uc); } void clean_up() { impl_->clean_up(); } void prepare(std::string const & query, details::statement_type eType = details::st_repeatable_query) { impl_->prepare(query, eType); } void define_and_bind() { impl_->define_and_bind(); } void undefine_and_bind() { impl_->undefine_and_bind(); } bool execute(bool withDataExchange = false) { gotData_ = impl_->execute(withDataExchange); return gotData_; } long long get_affected_rows() { return impl_->get_affected_rows(); } bool fetch() { gotData_ = impl_->fetch(); return gotData_; } bool got_data() const { return gotData_; } void describe() { impl_->describe(); } void set_row(row * r) { impl_->set_row(r); } template void exchange_for_rowset(details::into_container const & ic) { impl_->exchange_for_rowset(ic); } void exchange_for_rowset(details::into_type_ptr const & i) { impl_->exchange_for_rowset(i); } // for diagnostics and advanced users // (downcast it to expected back-end statement class) details::statement_backend * get_backend() { return impl_->get_backend(); } details::standard_into_type_backend * make_into_type_backend() { return impl_->make_into_type_backend(); } details::standard_use_type_backend * make_use_type_backend() { return impl_->make_use_type_backend(); } details::vector_into_type_backend * make_vector_into_type_backend() { return impl_->make_vector_into_type_backend(); } details::vector_use_type_backend * make_vector_use_type_backend() { return impl_->make_vector_use_type_backend(); } std::string rewrite_for_procedure_call(std::string const & query) { return impl_->rewrite_for_procedure_call(query); } private: details::statement_impl * impl_; bool gotData_; }; namespace details { // exchange_traits for statement template <> struct exchange_traits { typedef basic_type_tag type_family; enum { x_type = x_statement }; }; // into and use types for Statement (for nested statements and cursors) template <> class into_type : public standard_into_type { public: into_type(statement & s) : standard_into_type(&s, x_statement) {} into_type(statement & s, indicator & ind) : standard_into_type(&s, x_statement, ind) {} }; template <> class use_type : public standard_use_type { public: use_type(statement & s, std::string const & name = std::string()) : standard_use_type(&s, x_statement, false, name) {} use_type(statement & s, indicator & ind, std::string const & name = std::string()) : standard_use_type(&s, x_statement, ind, false, name) {} // Note: there is no const version of use for statement, // because most likely it would not make much sense anyway. }; } // namespace details } // namespace soci #endif // SOCI_STATEMENT_H_INCLUDED soci-3.2.3/core/connection-pool.h0000644000000000000000000000136712511362240015364 0ustar rootroot// // Copyright (C) 2008 Maciej Sobczak // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef SOCI_CONNECTION_POOL_H_INCLUDED #define SOCI_CONNECTION_POOL_H_INCLUDED #include "soci-config.h" // std #include namespace soci { class session; class SOCI_DECL connection_pool { public: explicit connection_pool(std::size_t size); ~connection_pool(); session & at(std::size_t pos); std::size_t lease(); bool try_lease(std::size_t & pos, int timeout); void give_back(std::size_t pos); private: struct connection_pool_impl; connection_pool_impl * pimpl_; }; } #endif // SOCI_CONNECTION_POOL_H_INCLUDED soci-3.2.3/CTestConfig.cmake0000644000000000000000000000101512511362240014315 0ustar rootroot## This file should be placed in the root directory of your project. ## Then modify the CMakeLists.txt file in the root directory of your ## project to incorporate the testing dashboard. ## # The following are required to uses Dart and the Cdash dashboard ## ENABLE_TESTING() ## INCLUDE(CTest) set(CTEST_PROJECT_NAME "SOCI") set(CTEST_NIGHTLY_START_TIME "00:00:00 EST") set(CTEST_DROP_METHOD "http") set(CTEST_DROP_SITE "my.cdash.org") set(CTEST_DROP_LOCATION "/submit.php?project=SOCI") set(CTEST_DROP_SITE_CDASH TRUE) soci-3.2.3/CMakeLists.txt0000644000000000000000000000742412511401144013712 0ustar rootroot############################################################################### # # This file is part of CMake configuration for SOCI library # # Copyright (C) 2009-2013 Mateusz Loskot # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # ############################################################################### # General settings ############################################################################### cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR) project(SOCI) ############################################################################### # SOCI CMake modules ############################################################################### # Path to additional CMake modules set(CMAKE_MODULE_PATH ${SOCI_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH ${SOCI_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH}) include(SociUtilities) colormsg(_HIBLUE_ "Configuring SOCI:") ############################################################################### # SOCI version information ############################################################################### include(SociVersion) soci_version(MAJOR 3 MINOR 2 PATCH 3) ############################################################################### # Build features and variants ############################################################################### include(SociSystemInfo) include(SociConfig) boost_report_value(SOCI_PLATFORM_NAME) boost_report_value(SOCI_COMPILER_NAME) option(SOCI_SHARED "Enable build of shared libraries" ON) boost_report_value(SOCI_SHARED) option(SOCI_STATIC "Enable build of static libraries" ON) boost_report_value(SOCI_STATIC) option(SOCI_TESTS "Enable build of collection of SOCI tests" ON) boost_report_value(SOCI_TESTS) # Put the libaries and binaries that get built into directories at the # top of the build tree rather than in hard-to-find leaf # directories. This simplifies manual testing and the use of the build # tree rather than installed Boost libraries. set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) ############################################################################### # Find SOCI dependencies ############################################################################### set(SOCI_CORE_DEPENDENCIES) include(SociDependencies) #message("${SOCI_CORE_DEPENDENCIES}") ############################################################################### # Installation ############################################################################### if(APPLE OR CMAKE_SIZEOF_VOID_P EQUAL 4) set(SOCI_LIBDIR "lib") else() set(SOCI_LIBDIR "lib64") endif() set(BINDIR "bin" CACHE PATH "The directory to install binaries into.") set(LIBDIR ${SOCI_LIBDIR} CACHE PATH "The directory to install libraries into.") set(DATADIR "share" CACHE PATH "The directory to install data files into.") set(INCLUDEDIR "include" CACHE PATH "The directory to install includes into.") ############################################################################### # Enable tests ############################################################################### enable_testing() # Configure for testing with dashboard submissions to CDash #include(CTest) # disabled as unused # Define "make check" as alias for "make test" add_custom_target(check COMMAND ctest) ############################################################################### # Build configured components ############################################################################### include(SociBackend) include_directories(${SOCI_SOURCE_DIR}/core) add_subdirectory(core) add_subdirectory(backends)