diff --git a/.gitignore b/.gitignore
index 405ab0d53b..609b4e844a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
# General
*.swp
+*.kate-swp
tags
tmp
@@ -8,6 +9,16 @@ _build*
src/_build*
src/build
+# Files generated by CMake
+Makefile
+src/core/soci_backends_config.h
+
+# ... and the rest of CMake spam
+CMakeFiles/
+CMakeCache.txt
+CTestTestfile.cmake
+cmake_install.cmake
+
# Visual Studio
*.opensdf
*.sdf
@@ -22,3 +33,7 @@ src/build
*.creator*
*.files
*.includes
+CMakeLists.txt.user
+
+# Eclipse
+/.project
diff --git a/.travis.yml b/.travis.yml
index 894f6a63f1..bfe6ff13cf 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,15 +14,20 @@ services:
- postgresql
env:
- matrix:
- - SOCI_TRAVIS_BACKEND=db2
- - SOCI_TRAVIS_BACKEND=empty
- - SOCI_TRAVIS_BACKEND=firebird
- - SOCI_TRAVIS_BACKEND=mysql
- - SOCI_TRAVIS_BACKEND=odbc
- - SOCI_TRAVIS_BACKEND=oracle
- - SOCI_TRAVIS_BACKEND=postgresql
- - SOCI_TRAVIS_BACKEND=sqlite3
+ - SOCI_TRAVIS_BACKEND=db2
+ - SOCI_TRAVIS_BACKEND=empty
+ - SOCI_TRAVIS_BACKEND=firebird
+ - SOCI_TRAVIS_BACKEND=mysql
+ - SOCI_TRAVIS_BACKEND=odbc
+ - SOCI_TRAVIS_BACKEND=oracle CFLAGS=-m32 CXXFLAGS=-m32 WITH_BOOST=OFF
+ - SOCI_TRAVIS_BACKEND=postgresql
+ - SOCI_TRAVIS_BACKEND=postgression
+ - SOCI_TRAVIS_BACKEND=sqlite3
+
+matrix:
+ fast_finish: true
+ allow_failures:
+ - env: SOCI_TRAVIS_BACKEND=postgression
before_install: ./bin/ci/before_install.sh
before_script: ./bin/ci/before_script.sh
@@ -32,8 +37,8 @@ notifications:
email:
recipients:
- soci-devel@lists.sourceforge.net
- on_success: change # [always|never|change] # default: change
- on_failure: always # [always|never|change] # default: always
+ on_success: change # [always|never|change] # default: change
+ on_failure: always # [always|never|change] # default: always
irc:
channels:
diff --git a/src/AUTHORS b/AUTHORS
similarity index 87%
rename from src/AUTHORS
rename to AUTHORS
index 8f6c336433..0b4d5487a8 100644
--- a/src/AUTHORS
+++ b/AUTHORS
@@ -19,6 +19,8 @@ Viacheslav Naydenov
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
@@ -52,6 +54,7 @@ Matt Arsenault
Matthieu Kermagoret
Michael Davidsaver
Mika Fischer
+pacocamberos
Paul Bondo
Petr Vanek
Philip Pemberton
@@ -69,5 +72,7 @@ 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, send us an email!
+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!
diff --git a/src/CHANGES b/CHANGES
similarity index 88%
rename from src/CHANGES
rename to CHANGES
index fcb2adc576..b66729305d 100644
--- a/src/CHANGES
+++ b/CHANGES
@@ -1,10 +1,55 @@
This file contains the history of changes in the SOCI library.
+---
+Version 4.0.0 differs from 3.2.x in the following ways:
+
+- Provide context of the failure in soci_error::what() which now returns a
+ longer and more useful message. Use the new get_error_message() method to get
+ just the brief error message which used to be returned by what().
+
+- Firebird
+-- Add SOCI_FIREBIRD_EMBEDDED option to allow building with embedded library.
+-- Throw an exception instead of truncating too long VARCHAR columns values.
+
+- ODBC/MS SQL
+-- Fix inserting strings of length greater than 8000 bytes into database.
+
+- Oracle
+-- Use SQLT_BDOUBLE for floating point values instead of SQLT_FLT.
+
+---
+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
+- 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
@@ -77,7 +122,7 @@ Version 3.2.1 differs from 3.2.0 in the following ways:
---
Version 3.2.0 differs from 3.1.0 in the following ways:
-- SOCI is now organization at GitHub
+- 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
@@ -124,7 +169,7 @@ Version 3.2.0 differs from 3.1.0 in the following ways:
-- 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 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
@@ -297,7 +342,7 @@ Version 2.0.1 differs from 2.0.0 in the following ways:
- 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
+ Values::set() and Values::get() are called where T is a
TypeConversion-based type.
---
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000..8d686b2f74
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,159 @@
+###############################################################################
+#
+# 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)
+include(SociConfig)
+
+colormsg(_HIBLUE_ "Configuring SOCI:")
+
+###############################################################################
+# SOCI version information
+###############################################################################
+include(SociVersion)
+
+# The version here should be in sync with the one in include/soci/version.h.
+soci_version(MAJOR 4 MINOR 0 PATCH 0)
+
+###############################################################################
+# Build features and variants
+##############################################################################
+
+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)
+
+# from SociConfig.cmake
+boost_report_value(SOCI_CXX_C11)
+
+# 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_TARGET)
+set(SOCI_CORE_TARGET_STATIC)
+set(SOCI_CORE_DEPS_LIBS)
+
+include(SociDependencies)
+
+get_property(SOCI_INCLUDE_DIRS DIRECTORY ${CMAKE_SOURCE_DIR}
+ PROPERTY INCLUDE_DIRECTORIES)
+
+if(Threads_FOUND)
+ list(APPEND SOCI_CORE_DEPS_LIBS ${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_DEPS_LIBS ${DL_LIBRARY})
+ set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES ${DL_INCLUDE_DIR})
+ add_definitions(-DHAVE_DL=1)
+ endif()
+else() #MSVC
+ # This flag enables multi process compiling for Visual Studio 2005 and above
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
+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_DEPS_LIBS ${Boost_DATE_TIME_LIBRARY})
+ list(APPEND SOCI_COMPILE_DEFINITIONS "HAVE_BOOST_DATE_TIME=1")
+ endif()
+
+ list(APPEND SOCI_INCLUDE_DIRS ${Boost_INCLUDE_DIRS})
+ list(APPEND SOCI_CORE_INCLUDE_DIRS ${Boost_INCLUDE_DIRS})
+
+ set_directory_properties(PROPERTY COMPILE_DEFINITIONS "${SOCI_COMPILE_DEFINITIONS}")
+
+ set_property(DIRECTORY ${SOCI_SOURCE_DIR}
+ PROPERTY COMPILE_DEFINITIONS "${SOCI_COMPILE_DEFINITIONS}")
+endif()
+
+list(APPEND SOCI_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR})
+
+set_property(DIRECTORY ${CMAKE_SOURCE_DIR}
+ PROPERTY
+ INCLUDE_DIRECTORIES ${SOCI_INCLUDE_DIRS})
+
+###############################################################################
+# Installation
+###############################################################################
+
+if(NOT DEFINED SOCI_LIBDIR)
+ if(APPLE OR CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(SOCI_LIBDIR "lib")
+ else()
+ set(SOCI_LIBDIR "lib64")
+ endif()
+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}/include)
+
+add_subdirectory(src)
+add_subdirectory(tests)
+
+message(STATUS "")
+
diff --git a/src/CTestConfig.cmake b/CTestConfig.cmake
similarity index 100%
rename from src/CTestConfig.cmake
rename to CTestConfig.cmake
diff --git a/src/LICENSE_1_0.txt b/LICENSE_1_0.txt
similarity index 100%
rename from src/LICENSE_1_0.txt
rename to LICENSE_1_0.txt
diff --git a/README.md b/README.md
index 0262964528..5f93f8a9a6 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Website: http://soci.sourceforge.net
GitHub hosts SOCI source code repository, issues tracker and wiki:
https://github.com/SOCI
-Downloads and mailing lists at
+Downloads and mailing lists at
http://sourceforge.net/projects/soci/
Travis CI service at https://travis-ci.org/SOCI/soci
@@ -23,18 +23,18 @@ Requirements
Core:
* C++ compiler
-* Boost C++ Libraries (optional, headers only)
+* Boost C++ Libraries (optional, headers and Boost.DateTime)
Backend specific client libraries for:
* DB2
* Firebird
* MySQL
-* ODBC andwith specific database driver
+* ODBC with specific database driver
* Oracle
* PostgreSQL
* SQLite 3
-See documentation at http://soci.sourceforge.net for details
+See documentation at http://soci.sourceforge.net for details
Brief History
-------------
diff --git a/src/ideas.txt b/TODO
similarity index 98%
rename from src/ideas.txt
rename to TODO
index 37fb670bf3..40a828904c 100644
--- a/src/ideas.txt
+++ b/TODO
@@ -75,7 +75,7 @@ Additional pair based val/indicator interface?
Consolidate iteration methods?
most radical: do we still need Statement::fetch()? into()?
(Rowset can currently be used for any query, supports indicators,
-defaults, and no need to check for eNodata)
+defaults, and no need to check for eNodata)
---
ColumnProperties() more logically belongs to Rowset than to Row
@@ -121,7 +121,7 @@ Sub-concepts:
- joins are tricky
- boolean operators (<,>,=,<=,=> and <>) and WHERE-like clause support as a query
-
+
rowset rs = (s.prepare << "age > 28") // rows where field 'age' is less than 28
rowset rs = (s.prepare << "age <> 28") // rows where field 'age' is less or more than 28
rowset rs = (s.prepare << "firstname='John' AND age > 28") // multi-fields combined queries
diff --git a/bin/ci/before_install.sh b/bin/ci/before_install.sh
index 4bc98abb19..ebd5aeb700 100755
--- a/bin/ci/before_install.sh
+++ b/bin/ci/before_install.sh
@@ -1,4 +1,4 @@
-#!/bin/bash -e
+#!/bin/bash
# Run before_install actions for SOCI build at travis-ci.org
#
# Copyright (c) 2013 Mateusz Loskot
@@ -6,8 +6,14 @@
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 16126D3A3E5C1192
-sudo apt-get update -qq
-sudo apt-get install -qq libboost-dev libboost-date-time-dev
+sudo add-apt-repository -y ppa:apt-fast/stable
+sudo apt-get update -qq -y
+sudo apt-get install -qq -y apt-fast
+sudo apt-fast update -qq -y
+sudo apt-fast install -qq -y libboost-dev libboost-date-time-dev
before_install="${TRAVIS_BUILD_DIR}/bin/ci/before_install_${SOCI_TRAVIS_BACKEND}.sh"
-[ -x ${before_install} ] && ${before_install} || echo "nothing to run"
+if [ -x ${before_install} ]; then
+ echo "Running ${before_install}"
+ ${before_install}
+fi
diff --git a/bin/ci/before_install_firebird.sh b/bin/ci/before_install_firebird.sh
index 9ec3214f4b..e03bfd4575 100755
--- a/bin/ci/before_install_firebird.sh
+++ b/bin/ci/before_install_firebird.sh
@@ -8,7 +8,7 @@ source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
sudo apt-get install -qq firebird2.5-super firebird2.5-dev
# Configure Firebird server
-# See: Non-interactive setup for travis-ci.org
+# See: Non-interactive setup for travis-ci.org
# http://tech.groups.yahoo.com/group/firebird-support/message/120883
#sudo dpkg-reconfigure -f noninteractive firebird2.5-super
sudo sed /ENABLE_FIREBIRD_SERVER=/s/no/yes/ -i /etc/default/firebird2.5
diff --git a/bin/ci/before_install_oracle.sh b/bin/ci/before_install_oracle.sh
index fdd1067501..5502e63d48 100755
--- a/bin/ci/before_install_oracle.sh
+++ b/bin/ci/before_install_oracle.sh
@@ -1,15 +1,123 @@
-#!/bin/bash -e
-# Install Oracle client libraries for SOCI at travis-ci.org
+#!/bin/bash
+# Script performs non-interactive installation of Oracle XE 10g on Debian
#
-# Copyright (c) 2013 Mateusz Loskot
+# Based on oracle10g-update.sh from HTSQL project:
+# https://bitbucket.org/prometheus/htsql
#
+# Modified by Mateusz Loskot
+# Changes:
+# - Add fake swap support (backup /usr/bin/free manually anyway!)
+# - Increase Oracle XE's PROCESSES parameter to value from range 100-200.
+# Required to prevent random ORA-12520 errors while running tests.
+#
+# Modified by Peter Butkovic to enable i386 install on amd64 architecture (precise 64)
+# based on: http://www.ubuntugeek.com/how-to-install-oracle-10g-xe-in-64-bit-ubuntu.html
+#
+# set -ex
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
-sudo apt-get install -qq tar bzip2 libaio1
+#
+# Utilities
+#
+function free_backup()
+{
+ # Multiple copies to be on safe side
+ sudo cp /usr/bin/free /root
+ sudo mv /usr/bin/free /usr/bin/free.original
+}
-wget http://brzuchol.loskot.net/software/oracle/instantclient_11_2-linux-x64-mloskot.tar.bz2
-tar -jxf instantclient_11_2-linux-x64-mloskot.tar.bz2
-sudo mkdir -p /opt
-sudo mv instantclient_11_2 /opt
-sudo ln -s ${ORACLE_HOME}/libclntsh.so.11.1 ${ORACLE_HOME}/libclntsh.so
-sudo ln -s ${ORACLE_HOME}/libocci.so.11.1 ${ORACLE_HOME}/libocci.so
+function free_restore()
+{
+ sudo cp /usr/bin/free.original /usr/bin/free
+}
+
+# Install fake free
+# http://www.axelog.de/2010/02/7-oracle-ee-refused-to-install-into-openvz/
+free_backup
+
+sudo tee /usr/bin/free < /dev/null
+#!/bin/sh
+cat <<__eof
+ total used free shared buffers cached
+Mem: 1048576 327264 721312 0 0 0
+-/+ buffers/cache: 327264 721312
+Swap: 2000000 0 2000000
+__eof
+exit
+EOF
+
+sudo chmod 755 /usr/bin/free
+
+#
+# ok, bc, is the dependency that is required by DB2 as well => let's remove it from oracle xe dependencies and provide 64bit one only
+#
+
+# Install the Oracle 10g dependant packages
+sudo apt-fast install -qq -y --force-yes libc6:i386
+# travis needs the "apt-transport-https" to enable https transport
+sudo apt-fast install -qq -y bc apt-transport-https
+
+# add Oracle repo + key (please note https is a must here, otherwise "apt-get update" fails for this repo with the "Undetermined error")
+sudo bash -c 'echo "deb https://oss.oracle.com/debian/ unstable main non-free" >/etc/apt/sources.list.d/oracle.list'
+wget -q https://oss.oracle.com/el4/RPM-GPG-KEY-oracle -O- | sudo apt-key add -
+sudo apt-fast update -qq -y
+
+# only download the package, to manually install afterwards
+sudo apt-fast install -qq -y --force-yes -d oracle-xe-universal:i386
+sudo apt-fast install -qq -y --force-yes libaio:i386
+
+# remove key + repo (to prevent failures on next updates)
+sudo apt-key del B38A8516
+sudo bash -c 'rm -rf /etc/apt/sources.list.d/oracle.list'
+sudo apt-fast update -qq -y
+sudo apt-get autoremove -qq
+
+# remove bc from the dependencies of the oracle-xe-universal package (to keep 64bit one installed)
+mkdir /tmp/oracle_unpack
+dpkg-deb -x /var/cache/apt/archives/oracle-xe-universal_10.2.0.1-1.1_i386.deb /tmp/oracle_unpack
+cd /tmp/oracle_unpack
+dpkg-deb --control /var/cache/apt/archives/oracle-xe-universal_10.2.0.1-1.1_i386.deb
+sed -i "s/,\ bc//g" /tmp/oracle_unpack/DEBIAN/control
+mkdir /tmp/oracle_repack
+dpkg -b /tmp/oracle_unpack /tmp/oracle_repack/oracle-xe-universal_fixed_10.2.0.1-1.1_i386.deb
+
+# install Oracle 10g with the fixed dependencies, to prevent i386/amd64 conflicts on bc package
+sudo dpkg -i --force-architecture /tmp/oracle_repack/oracle-xe-universal_fixed_10.2.0.1-1.1_i386.deb
+
+# Fix the problem when the configuration script eats the last
+# character of the password if it is 'n': replace IFS="\n" with IFS=$'\n'.
+sudo sed -i -e s/IFS=\"\\\\n\"/IFS=\$\'\\\\n\'/ /etc/init.d/oracle-xe
+
+# Configure the server; provide the answers for the following questions:
+# The HTTP port for Oracle Application Express: 8080
+# A port for the database listener: 1521
+# The password for the SYS and SYSTEM database accounts: admin
+# Start the server on boot: yes
+sudo /etc/init.d/oracle-xe configure <>/root/.bashrc
+#. /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin/oracle_env.sh
+#END
+
+free_restore
+
+# Install development toolset for 32-bit for Travis CI 64-bit
+sudo apt-fast install -qq -y g++-multilib
diff --git a/bin/ci/before_script.sh b/bin/ci/before_script.sh
index 4fe32bc924..681bbf9c85 100755
--- a/bin/ci/before_script.sh
+++ b/bin/ci/before_script.sh
@@ -1,4 +1,4 @@
-#!/bin/bash -e
+#!/bin/bash
# Run before_script actions for SOCI build at travis-ci.org
#
# Copyright (c) 2013 Mateusz Loskot
@@ -6,4 +6,7 @@
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
before_script="${TRAVIS_BUILD_DIR}/bin/ci/before_script_${SOCI_TRAVIS_BACKEND}.sh"
-[ -x ${before_script} ] && ${before_script} || echo "nothing to run"
+if [ -x ${before_script} ]; then
+ echo "Running ${before_script}"
+ ${before_script}
+fi
diff --git a/bin/ci/before_script_odbc.sh b/bin/ci/before_script_odbc.sh
index 56495740d8..1bff332e5f 100755
--- a/bin/ci/before_script_odbc.sh
+++ b/bin/ci/before_script_odbc.sh
@@ -7,5 +7,5 @@ source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
mysql --version
mysql -e 'create database soci_test;'
-psql --version
+psql --version
psql -c 'create database soci_test;' -U postgres
diff --git a/bin/ci/before_script_oracle.sh b/bin/ci/before_script_oracle.sh
new file mode 100755
index 0000000000..91bac34143
--- /dev/null
+++ b/bin/ci/before_script_oracle.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+# Sets up environment for p6psy backend Oracle at travis-ci.org
+#
+# Copyright (c) 2013 Peter Butkovic
+#
+# Modified by Mateusz Loskot
+# Changes:
+# - Check connection as user for testing
+#
+
+# for some reason the file is not found any more here => creating user in install script
+# Load Oracle environment variables so that we could run `sqlplus`.
+. /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin/oracle_env.sh
+echo "ORACLE_HOME=${ORACLE_HOME}"
+echo "ORACLE_SID=${ORACLE_SID}"
+
+# create user for testing
+echo "CREATE USER travis IDENTIFIED BY travis;" | \
+sqlplus -S -L sys/admin AS SYSDBA
+
+echo "grant connect, resource to travis;" | \
+sqlplus -S -L sys/admin AS SYSDBA
+
+echo "grant create session, alter any procedure to travis;" | \
+sqlplus -S -L sys/admin AS SYSDBA
+
+# to enable xa recovery, see: https://community.oracle.com/thread/378954
+echo "grant select on sys.dba_pending_transactions to travis;" | \
+sqlplus -S -L sys/admin AS SYSDBA
+echo "grant select on sys.pending_trans$ to travis;" | \
+sqlplus -S -L sys/admin AS SYSDBA
+echo "grant select on sys.dba_2pc_pending to travis;" | \
+sqlplus -S -L sys/admin AS SYSDBA
+echo "grant execute on sys.dbms_system to travis;" | \
+sqlplus -S -L sys/admin AS SYSDBA
+
+# increase default=40 value of processes to prevent ORA-12520 failures while testing
+echo "alter system set processes=100 scope=spfile;" | \
+sqlplus -S -L sys/admin AS SYSDBA
+
+# check connection as user for testing
+echo "Connecting using travis/travis@XE"
+echo "SELECT * FROM product_component_version;" | \
+sqlplus -S -L travis/travis@XE
+
diff --git a/bin/ci/before_script_postgresql.sh b/bin/ci/before_script_postgresql.sh
index 20a2579a51..039a4a6e55 100755
--- a/bin/ci/before_script_postgresql.sh
+++ b/bin/ci/before_script_postgresql.sh
@@ -5,5 +5,5 @@
#
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
-psql --version
+psql --version
psql -c 'create database soci_test;' -U postgres
diff --git a/bin/ci/common.sh b/bin/ci/common.sh
index 0a643943da..feb15a771c 100644
--- a/bin/ci/common.sh
+++ b/bin/ci/common.sh
@@ -15,8 +15,6 @@ if [[ -f /sys/devices/system/cpu/online ]]; then
# Calculates 1.5 times physical threads
TCI_NUMTHREADS=$(( ( $(cut -f 2 -d '-' /sys/devices/system/cpu/online) + 1 ) * 15 / 10 ))
fi
-export ORACLE_HOME=/opt/instantclient_11_2
-export LD_LIBRARY_PATH=${ORACLE_HOME}:${LD_LIBRARY_PATH}
#
# Functions
#
@@ -27,10 +25,10 @@ tmstamp()
run_make()
{
- [ $TCI_NUMTHREADS -gt 0 ] && make -j $TCI_NUMTHREADS ] || make
+ [ $TCI_NUMTHREADS -gt 0 ] && make -j $TCI_NUMTHREADS || make
}
run_test()
{
- ctest -V --output-on-failure .
+ ctest -V --output-on-failure "$@" .
}
diff --git a/bin/ci/oracle.sh b/bin/ci/oracle.sh
new file mode 100644
index 0000000000..9cbfadd4d7
--- /dev/null
+++ b/bin/ci/oracle.sh
@@ -0,0 +1,14 @@
+# Definitions used by SOCI when building Oracle backend at travis-ci.org
+#
+# Copyright (c) 2015 Vadim Zeitlin
+#
+# Notice that this file is not executable, it is supposed to be sourced from
+# the other files.
+
+# Load Oracle environment variables
+. /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin/oracle_env.sh
+echo "ORACLE_HOME=${ORACLE_HOME}"
+echo "ORACLE_SID=${ORACLE_SID}"
+
+LD_LIBRARY_PATH=${ORACLE_HOME}:${LD_LIBRARY_PATH}
+export LD_LIBRARY_PATH
diff --git a/bin/ci/script.sh b/bin/ci/script.sh
index d982aee6e9..538dd53b40 100755
--- a/bin/ci/script.sh
+++ b/bin/ci/script.sh
@@ -1,4 +1,4 @@
-#!/bin/bash -e
+#!/bin/bash
# Run test script actions for SOCI build at travis-ci.org
#
# Copyright (c) 2013 Mateusz Loskot
@@ -6,9 +6,11 @@
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
# prepare build directory
-builddir="${TRAVIS_BUILD_DIR}/src/_build"
+builddir="${TRAVIS_BUILD_DIR}/_build"
mkdir -p ${builddir}
cd ${builddir}
# build and run tests
-${TRAVIS_BUILD_DIR}/bin/ci/script_${SOCI_TRAVIS_BACKEND}.sh
+SCRIPT=${TRAVIS_BUILD_DIR}/bin/ci/script_${SOCI_TRAVIS_BACKEND}.sh
+echo "Running ${SCRIPT}"
+${SCRIPT}
diff --git a/bin/ci/script_db2.sh b/bin/ci/script_db2.sh
index ed174c154b..1120c0d458 100755
--- a/bin/ci/script_db2.sh
+++ b/bin/ci/script_db2.sh
@@ -7,6 +7,7 @@
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
cmake \
+ -DCMAKE_VERBOSE_MAKEFILE=ON \
-DSOCI_TESTS=ON \
-DSOCI_STATIC=OFF \
-DSOCI_DB2=ON \
@@ -18,7 +19,7 @@ cmake \
-DSOCI_POSTGRESQL=OFF \
-DSOCI_SQLITE3=OFF \
-DSOCI_DB2_TEST_CONNSTR:STRING="DSN=SOCITEST\;Uid=db2inst1\;Pwd=db2inst1" \
- ..
+ ..
run_make
run_test
diff --git a/bin/ci/script_empty.sh b/bin/ci/script_empty.sh
index a93e541eb9..af7982d694 100755
--- a/bin/ci/script_empty.sh
+++ b/bin/ci/script_empty.sh
@@ -6,6 +6,7 @@
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
cmake \
+ -DCMAKE_VERBOSE_MAKEFILE=ON \
-DSOCI_TESTS=ON \
-DSOCI_STATIC=OFF \
-DSOCI_DB2=OFF \
diff --git a/bin/ci/script_firebird.sh b/bin/ci/script_firebird.sh
index 7c75fca7ad..1ad00f540d 100755
--- a/bin/ci/script_firebird.sh
+++ b/bin/ci/script_firebird.sh
@@ -6,6 +6,7 @@
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
cmake \
+ -DCMAKE_VERBOSE_MAKEFILE=ON \
-DSOCI_TESTS=ON \
-DSOCI_STATIC=OFF \
-DSOCI_DB2=OFF \
@@ -17,7 +18,7 @@ cmake \
-DSOCI_POSTGRESQL=OFF \
-DSOCI_SQLITE3=OFF \
-DSOCI_FIREBIRD_TEST_CONNSTR:STRING="service=LOCALHOST:/tmp/soci_test.fdb user=SYSDBA password=masterkey" \
- ..
+ ..
run_make
run_test
diff --git a/bin/ci/script_mysql.sh b/bin/ci/script_mysql.sh
index 58d57709b6..8589a21f4a 100755
--- a/bin/ci/script_mysql.sh
+++ b/bin/ci/script_mysql.sh
@@ -6,6 +6,7 @@
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
cmake \
+ -DCMAKE_VERBOSE_MAKEFILE=ON \
-DSOCI_TESTS=ON \
-DSOCI_STATIC=OFF \
-DSOCI_DB2=OFF \
@@ -17,7 +18,7 @@ cmake \
-DSOCI_POSTGRESQL=OFF \
-DSOCI_SQLITE3=OFF \
-DSOCI_MYSQL_TEST_CONNSTR:STRING="db=soci_test" \
- ..
+ ..
run_make
run_test
diff --git a/bin/ci/script_odbc.sh b/bin/ci/script_odbc.sh
index 79a655e788..5193857daf 100755
--- a/bin/ci/script_odbc.sh
+++ b/bin/ci/script_odbc.sh
@@ -5,7 +5,14 @@
#
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
+ODBC_TEST=${PWD}/../tests/odbc
+if test ! -d ${ODBC_TEST}; then
+ echo "ERROR: '${ODBC_TEST}' directory not found"
+ exit 1
+fi
+
cmake \
+ -DCMAKE_VERBOSE_MAKEFILE=ON \
-DSOCI_TESTS=ON \
-DSOCI_STATIC=OFF \
-DSOCI_DB2=OFF \
@@ -16,9 +23,11 @@ cmake \
-DSOCI_ORACLE=OFF \
-DSOCI_POSTGRESQL=OFF \
-DSOCI_SQLITE3=OFF \
- -DSOCI_ODBC_TEST_POSTGRESQL_CONNSTR="FILEDSN=${PWD}/../backends/odbc/test/test-postgresql.dsn;" \
- -DSOCI_ODBC_TEST_MYSQL_CONNSTR="FILEDSN=${PWD}/../backends/odbc/test/test-mysql.dsn;" \
+ -DSOCI_ODBC_TEST_POSTGRESQL_CONNSTR="FILEDSN=${ODBC_TEST}/test-postgresql.dsn;" \
+ -DSOCI_ODBC_TEST_MYSQL_CONNSTR="FILEDSN=${ODBC_TEST}/test-mysql.dsn;" \
..
run_make
-run_test
+
+# Exclude the test which can't be run as there is no MS SQL server available.
+run_test -E soci_odbc_test_mssql
diff --git a/bin/ci/script_oracle.sh b/bin/ci/script_oracle.sh
index 743476c893..f9863da425 100755
--- a/bin/ci/script_oracle.sh
+++ b/bin/ci/script_oracle.sh
@@ -4,15 +4,11 @@
# Copyright (c) 2013 Mateusz Loskot
#
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
-
-if [ "${CXX}" == "g++" ]
-then
- ORACLE_USER="soci_tester"
-else
- ORACLE_USER="soci_tester1"
-fi
+source ${TRAVIS_BUILD_DIR}/bin/ci/oracle.sh
cmake \
+ -DCMAKE_VERBOSE_MAKEFILE=ON \
+ -DWITH_BOOST=OFF \
-DSOCI_TESTS=ON \
-DSOCI_STATIC=OFF \
-DSOCI_DB2=OFF \
@@ -23,8 +19,8 @@ cmake \
-DSOCI_ORACLE=ON \
-DSOCI_POSTGRESQL=OFF \
-DSOCI_SQLITE3=OFF \
- -DSOCI_ORACLE_TEST_CONNSTR:STRING="service=brzuchol.loskot.net user=${ORACLE_USER} password=soci_secret" \
- ..
+ -DSOCI_ORACLE_TEST_CONNSTR:STRING="service=XE user=travis password=travis" \
+ ..
run_make
run_test
diff --git a/bin/ci/script_postgresql.sh b/bin/ci/script_postgresql.sh
index 2a5194615e..892d74372e 100755
--- a/bin/ci/script_postgresql.sh
+++ b/bin/ci/script_postgresql.sh
@@ -6,6 +6,7 @@
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
cmake \
+ -DCMAKE_VERBOSE_MAKEFILE=ON \
-DSOCI_TESTS=ON \
-DSOCI_STATIC=OFF \
-DSOCI_DB2=OFF \
@@ -17,7 +18,7 @@ cmake \
-DSOCI_POSTGRESQL=ON \
-DSOCI_SQLITE3=OFF \
-DSOCI_POSTGRESQL_TEST_CONNSTR:STRING="dbname=soci_test user=postgres" \
- ..
+ ..
run_make
run_test
diff --git a/bin/ci/script_postgression.sh b/bin/ci/script_postgression.sh
new file mode 100755
index 0000000000..846bfcd2d6
--- /dev/null
+++ b/bin/ci/script_postgression.sh
@@ -0,0 +1,47 @@
+#!/bin/bash -e
+# Builds and tests SOCI backend PostgreSQL at travis-ci.org
+#
+# Copyright (C) 2014 Vadim Zeitlin
+# Copyright (C) 2015 Mateusz Loskot
+#
+source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
+
+# Get Postgression's PostgreSQL connection parameters as URI
+SOCI_POSTGRESQL_CONNSTR=$(curl http://api.postgression.com)
+# or old-style conninfo string, both should work.
+#SOCI_POSTGRESQL_CONNSTR=$(curl http://api.postgression.com | \
+#sed 's|postgres://\([^:]\+\):\([^@]\+\)@\([^:]\+\):\([0-9]\+\)/\(.*\)|user=\1 password=\2 host=\3 port=\4 dbname=\5|')
+
+# Before proceeding with build, check Postgression availability
+echo $SOCI_POSTGRESQL_CONNSTR | grep NO_DATABASES_AVAILABLE
+if [ $? -eq 0 ];then
+ echo ${SOCI_POSTGRESQL_CONNSTR}
+ exit 1
+fi
+
+echo "Postgression connection parameters: $SOCI_POSTGRESQL_CONNSTR"
+
+echo "PostgreSQL client version:"
+psql --version
+# WARNING: Somehow, connecting to Postgression service with psql
+# seems to terminate Travis CI session preventing the job to
+# continue with build and tests.
+#psql -c 'select version();' "$SOCI_POSTGRESQL_CONNSTR"
+
+cmake \
+ -DCMAKE_VERBOSE_MAKEFILE=ON \
+ -DSOCI_TESTS=ON \
+ -DSOCI_STATIC=OFF \
+ -DSOCI_DB2=OFF \
+ -DSOCI_EMPTY=OFF \
+ -DSOCI_FIREBIRD=OFF \
+ -DSOCI_MYSQL=OFF \
+ -DSOCI_ODBC=OFF \
+ -DSOCI_ORACLE=OFF \
+ -DSOCI_POSTGRESQL=ON \
+ -DSOCI_SQLITE3=OFF \
+ -DSOCI_POSTGRESQL_TEST_CONNSTR:STRING="$SOCI_POSTGRESQL_CONNSTR" \
+ ..
+
+run_make
+run_test
diff --git a/bin/ci/script_sqlite3.sh b/bin/ci/script_sqlite3.sh
index 1a3de1fe72..5dfc0d0027 100755
--- a/bin/ci/script_sqlite3.sh
+++ b/bin/ci/script_sqlite3.sh
@@ -6,6 +6,7 @@
source ${TRAVIS_BUILD_DIR}/bin/ci/common.sh
cmake \
+ -DCMAKE_VERBOSE_MAKEFILE=ON \
-DSOCI_TESTS=ON \
-DSOCI_STATIC=OFF \
-DSOCI_DB2=OFF \
diff --git a/bin/vm/debian-oracle10g-install.sh b/bin/vm/debian-oracle10g-install.sh
index 39e8e4be22..a96b98383f 100644
--- a/bin/vm/debian-oracle10g-install.sh
+++ b/bin/vm/debian-oracle10g-install.sh
@@ -28,7 +28,7 @@ function free_restore()
# Install fake free
# http://www.axelog.de/2010/02/7-oracle-ee-refused-to-install-into-openvz/
free_backup
-cat <> /usr/bin/free
+cat <> /usr/bin/free
#!/bin/sh
cat <<__eof
total used free shared buffers cached
diff --git a/build/README b/build/README
deleted file mode 100644
index db968b7b2b..0000000000
--- a/build/README
+++ /dev/null
@@ -1,2 +0,0 @@
-This directory is dedicated for:
-- other building systems contributed by SOCI team and users
diff --git a/build/unix/build-core.tcl b/build/unix/build-core.tcl
deleted file mode 100644
index aba8d8ec87..0000000000
--- a/build/unix/build-core.tcl
+++ /dev/null
@@ -1,37 +0,0 @@
-proc buildCore {} {
- global CXXFLAGS
-
- puts "building static core"
-
- set cwd [pwd]
- cd "../../src/core"
- foreach cppFile [glob "*.cpp"] {
- execute "g++ -c $cppFile $CXXFLAGS"
- }
-
- execute "ar cr libsoci_core.a [glob *.o]"
- cd $cwd
- eval exec mkdir -p "lib"
- execute "cp ../../src/core/libsoci_core.a lib"
- eval exec mkdir -p "include"
- execute "cp [glob ../../src/core/*.h] include"
-}
-
-proc buildCoreSo {} {
- global CXXFLAGS SHARED
-
- puts "building shared core"
-
- set cwd [pwd]
- cd "../../src/core"
- foreach cppFile [glob "*.cpp"] {
- execute "g++ -c $cppFile $CXXFLAGS -fPIC"
- }
-
- execute "g++ $SHARED -o libsoci_core.so [glob *.o]"
- cd $cwd
- eval exec mkdir -p "lib"
- execute "cp ../../src/core/libsoci_core.so lib"
- eval exec mkdir -p "include"
- execute "cp [glob ../../src/core/*.h] include"
-}
diff --git a/build/unix/build-mysql.tcl b/build/unix/build-mysql.tcl
deleted file mode 100644
index f1371ae519..0000000000
--- a/build/unix/build-mysql.tcl
+++ /dev/null
@@ -1,142 +0,0 @@
-source "local/parameters.tcl"
-
-proc findMySQL {} {
- global mysqlInclude mysqlLib
-
- # candidate directories for local MySQL:
- set includeDirs {
- "/usr/local/include/mysql"
- "/usr/include/mysql"
- "/usr/local/include"
- "/usr/include"
- "/opt/local/include"
- }
- set libDirs {
- "/usr/local/lib/mysql"
- "/usr/lib/mysql"
- "/usr/local/lib"
- "/usr/lib"
- "/opt/local/lib"
- }
-
- if [info exists mysqlInclude] {
- set includeDirs [list $mysqlInclude]
- }
- if [info exists mysqlLib] {
- set libDirs [list $mysqlLib]
- }
-
- set includeDir ""
- foreach I $includeDirs {
- set header "${I}/mysql.h"
- if {[file exists $header]} {
- set includeDir $I
- break
- }
- }
- if {$includeDir == ""} {
- return {}
- }
-
- set libDir ""
- foreach L $libDirs {
- set libraryA "${L}/libmysqlclient.a"
- set librarySo "${L}/libmysqlclient.so"
- if {[file exists $libraryA] || [file exists $librarySo]} {
- set libDir $L
- break
- }
- }
- if {$libDir == ""} {
- return {}
- }
-
- return [list $includeDir $libDir]
-}
-
-proc buildMySQL {} {
- global CXXFLAGS
-
- puts "building static MySQL"
-
- set dirs [findMySQL]
- if {$dirs == {}} {
- puts "cannot find MySQL library files, skipping this target"
- return
- }
-
- set includeDir [lindex $dirs 0]
- set libDir [lindex $dirs 1]
-
- set cwd [pwd]
- cd "../../src/backends/mysql"
- foreach cppFile [glob "*.cpp"] {
- execute "g++ -c $cppFile $CXXFLAGS -I../../core -I${includeDir}"
- }
-
- execute "ar cr libsoci_mysql.a [glob *.o]"
- cd $cwd
- eval exec mkdir -p "lib"
- execute "cp ../../src/backends/mysql/libsoci_mysql.a lib"
- eval exec mkdir -p "include"
- execute "cp ../../src/backends/mysql/soci-mysql.h include"
-}
-
-proc buildMySQLSo {} {
- global CXXFLAGS SHARED
-
- puts "building shared MySQL"
-
- set dirs [findMySQL]
- if {$dirs == {}} {
- puts "cannot find MySQL library files, skipping this target"
- return
- }
-
- set includeDir [lindex $dirs 0]
- set libDir [lindex $dirs 1]
-
- set cwd [pwd]
- cd "../../src/backends/mysql"
- foreach cppFile [glob "*.cpp"] {
- execute "g++ -c $cppFile $CXXFLAGS -fPIC -I../../core -I${includeDir}"
- }
-
- execute "g++ $SHARED -o libsoci_mysql.so [glob *.o] -L${libDir} -lmysqlclient -lz"
- cd $cwd
- eval exec mkdir -p "lib"
- execute "cp ../../src/backends/mysql/libsoci_mysql.so lib"
- eval exec mkdir -p "include"
- execute "cp ../../src/backends/mysql/soci-mysql.h include"
-}
-
-proc buildMySQLTest {} {
- global CXXTESTFLAGS LDL
-
- puts "building MySQL test"
-
- set dirs [findMySQL]
- if {$dirs == {}} {
- puts "cannot find MySQL library files, skipping this target"
- return
- }
-
- set includeDir [lindex $dirs 0]
- set libDir [lindex $dirs 1]
-
- set dirs [findBoost]
- if {$dirs == {}} {
- puts "cannot find Boost library files, skipping this target"
- return
- }
-
- set boostIncludeDir [lindex $dirs 0]
- set boostLibDir [lindex $dirs 1]
-
- set cwd [pwd]
- cd "../../src/backends/mysql/test"
- execute "g++ test-mysql.cpp -o test-mysql $CXXTESTFLAGS -I.. -I../../../core -I../../../core/test -I${includeDir} -I${boostIncludeDir} -L../../../../build/unix/lib -L${libDir} -L${boostLibDir} -lsoci_core -lsoci_mysql -lboost_date_time ${LDL} -lmysqlclient -lz"
- cd $cwd
- eval exec mkdir -p "tests"
- execute "cp ../../src/backends/mysql/test/test-mysql tests"
-}
diff --git a/build/unix/build-oracle.tcl b/build/unix/build-oracle.tcl
deleted file mode 100644
index ac59d0b287..0000000000
--- a/build/unix/build-oracle.tcl
+++ /dev/null
@@ -1,120 +0,0 @@
-proc findOracle {} {
- global env oracleInclude oracleLib
-
- if {[info exists oracleInclude] &&
- [info exists oracleLib]} {
- set includeDir $oracleInclude
- set libDir $oracleLib
- } else {
- if {[info exists env(ORACLE_HOME)] == 0} {
- puts "The ORACLE_HOME variable is not set."
- return {}
- }
-
- set ORACLE_HOME $env(ORACLE_HOME)
-
- set includeDir [file join $ORACLE_HOME "rdbms/public"]
- set header [file join $includeDir "oci.h"]
- if {[file exists $header] == 0} {
- puts "ORACLE_HOME is strange."
- return {}
- }
-
- set libDir [file join $ORACLE_HOME "lib"]
- set libraryA [file join $libDir "libclntsh.a"]
- set librarySo [file join $libDir "libclntsh.so"]
- if {([file exists $libraryA] == 0) && ([file exists $librarySo] == 0)} {
- puts "ORACLE_HOME is strange."
- return {}
- }
- }
-
- return [list $includeDir $libDir]
-}
-
-proc buildOracle {} {
- global CXXFLAGS
-
- puts "building static Oracle"
-
- set dirs [findOracle]
- if {$dirs == {}} {
- puts "cannot find Oracle library files, skipping this target"
- return
- }
-
- set includeDir [lindex $dirs 0]
- set libDir [lindex $dirs 1]
-
- set cwd [pwd]
- cd "../../src/backends/oracle"
- foreach cppFile [glob "*.cpp"] {
- execute "g++ -c $cppFile $CXXFLAGS -I../../core -I${includeDir}"
- }
-
- execute "ar cr libsoci_oracle.a [glob *.o]"
- cd $cwd
- eval exec mkdir -p "lib"
- execute "cp ../../src/backends/oracle/libsoci_oracle.a lib"
- eval exec mkdir -p "include"
- execute "cp ../../src/backends/oracle/soci-oracle.h include"
-}
-
-proc buildOracleSo {} {
- global CXXFLAGS SHARED
-
- puts "building shared Oracle"
-
- set dirs [findOracle]
- if {$dirs == {}} {
- puts "cannot find Oracle library files, skipping this target"
- return
- }
-
- set includeDir [lindex $dirs 0]
- set libDir [lindex $dirs 1]
-
- set cwd [pwd]
- cd "../../src/backends/oracle"
- foreach cppFile [glob "*.cpp"] {
- execute "g++ -c $cppFile $CXXFLAGS -fPIC -I../../core -I${includeDir}"
- }
-
- execute "g++ $SHARED -o libsoci_oracle.so [glob *.o] -L${libDir} -lclntsh -lnnz10"
- cd $cwd
- eval exec mkdir -p "lib"
- execute "cp ../../src/backends/oracle/libsoci_oracle.so lib"
- eval exec mkdir -p "include"
- execute "cp ../../src/backends/oracle/soci-oracle.h include"
-}
-
-proc buildOracleTest {} {
- global CXXTESTFLAGS LDL
-
- puts "building Oracle test"
-
- set dirs [findOracle]
- if {$dirs == {}} {
- puts "cannot find Oracle library files, skipping this target"
- return
- }
-
- set includeDir [lindex $dirs 0]
- set libDir [lindex $dirs 1]
-
- set dirs [findBoost]
- if {$dirs == {}} {
- puts "cannot find Boost library files, skipping this target"
- return
- }
-
- set boostIncludeDir [lindex $dirs 0]
- set boostLibDir [lindex $dirs 1]
-
- set cwd [pwd]
- cd "../../src/backends/oracle/test"
- execute "g++ test-oracle.cpp -o test-oracle $CXXTESTFLAGS -I.. -I../../../core -I../../../core/test -I${includeDir} -I${boostIncludeDir} -L../../../../build/unix/lib -L${libDir} -L${boostLibDir} -lsoci_core -lsoci_oracle -lboost_date_time ${LDL} -lclntsh -lnnz10"
- cd $cwd
- eval exec mkdir -p "tests"
- execute "cp ../../src/backends/oracle/test/test-oracle tests"
-}
diff --git a/build/unix/build-postgresql.tcl b/build/unix/build-postgresql.tcl
deleted file mode 100644
index 49a4f939ad..0000000000
--- a/build/unix/build-postgresql.tcl
+++ /dev/null
@@ -1,148 +0,0 @@
-proc findPostgreSQL {} {
- global postgresqlInclude postgresqlLib
-
- # candidate directories for local PostgreSQL:
- set includeDirs {
- "/usr/local/pgsql/include"
- "/usr/local/postgresql/include"
- "/usr/local/include/pgsql"
- "/usr/local/include/postgresql"
- "/usr/include/pgsql"
- "/usr/include/postgresql"
- "/usr/local/include"
- "/usr/include"
- "/opt/local/include"
- }
- set libDirs {
- "/usr/local/pgsql/lib"
- "/usr/local/postgresql/lib"
- "/usr/local/lib/pgsql"
- "/usr/local/lib/postgresql"
- "/usr/lib/pgsql"
- "/usr/lib/postgresql"
- "/usr/local/lib"
- "/usr/lib"
- "/opt/local/lib"
- }
-
- if [info exists postgresqlInclude] {
- set includeDirs [list $postgresqlInclude]
- }
- if [info exists postgresqlLib] {
- set libDirs [list $postgresqlLib]
- }
-
- set includeDir ""
- foreach I $includeDirs {
- set header "${I}/libpq/libpq-fs.h"
- if {[file exists $header]} {
- set includeDir $I
- break
- }
- }
- if {$includeDir == ""} {
- return {}
- }
-
- set libDir ""
- foreach L $libDirs {
- set libraryA "${L}/libpq.a"
- set librarySo "${L}/libpq.so"
- if {[file exists $libraryA] || [file exists $librarySo]} {
- set libDir $L
- break
- }
- }
- if {$libDir == ""} {
- return {}
- }
-
- return [list $includeDir $libDir]
-}
-
-proc buildPostgreSQL {} {
- global CXXFLAGS
-
- puts "building static PostgreSQL"
-
- set dirs [findPostgreSQL]
- if {$dirs == {}} {
- puts "cannot find PostgreSQL library files, skipping this target"
- return
- }
-
- set includeDir [lindex $dirs 0]
- set libDir [lindex $dirs 1]
-
- set cwd [pwd]
- cd "../../src/backends/postgresql"
- foreach cppFile [glob "*.cpp"] {
- execute "g++ -c $cppFile $CXXFLAGS -I../../core -I${includeDir}"
- }
-
- execute "ar cr libsoci_postgresql.a [glob *.o]"
- cd $cwd
- eval exec mkdir -p "lib"
- execute "cp ../../src/backends/postgresql/libsoci_postgresql.a lib"
- eval exec mkdir -p "include"
- execute "cp ../../src/backends/postgresql/soci-postgresql.h include"
-}
-
-proc buildPostgreSQLSo {} {
- global CXXFLAGS SHARED
-
- puts "building shared PostgreSQL"
-
- set dirs [findPostgreSQL]
- if {$dirs == {}} {
- puts "cannot find PostgreSQL library files, skipping this target"
- return
- }
-
- set includeDir [lindex $dirs 0]
- set libDir [lindex $dirs 1]
-
- set cwd [pwd]
- cd "../../src/backends/postgresql"
- foreach cppFile [glob "*.cpp"] {
- execute "g++ -c $cppFile $CXXFLAGS -fPIC -I../../core -I${includeDir}"
- }
-
- execute "g++ $SHARED -o libsoci_postgresql.so [glob *.o] -L${libDir} -lpq"
- cd $cwd
- eval exec mkdir -p "lib"
- execute "cp ../../src/backends/postgresql/libsoci_postgresql.so lib"
- eval exec mkdir -p "include"
- execute "cp ../../src/backends/postgresql/soci-postgresql.h include"
-}
-
-proc buildPostgreSQLTest {} {
- global CXXTESTFLAGS LDL
-
- puts "building PostgreSQL test"
-
- set dirs [findPostgreSQL]
- if {$dirs == {}} {
- puts "cannot find PostgreSQL library files, skipping this target"
- return
- }
-
- set includeDir [lindex $dirs 0]
- set libDir [lindex $dirs 1]
-
- set dirs [findBoost]
- if {$dirs == {}} {
- puts "cannot find Boost library files, skipping this target"
- return
- }
-
- set boostIncludeDir [lindex $dirs 0]
- set boostLibDir [lindex $dirs 1]
-
- set cwd [pwd]
- cd "../../src/backends/postgresql/test"
- execute "g++ test-postgresql.cpp -o test-postgresql $CXXTESTFLAGS -I.. -I../../../core -I../../../core/test -I${includeDir} -I${boostIncludeDir} -L../../../../build/unix/lib -L${libDir} -L${boostLibDir} -lsoci_core -lsoci_postgresql -lboost_date_time ${LDL} -lpq"
- cd $cwd
- eval exec mkdir -p "tests"
- execute "cp ../../src/backends/postgresql/test/test-postgresql tests"
-}
diff --git a/build/unix/build-sqlite3.tcl b/build/unix/build-sqlite3.tcl
deleted file mode 100644
index a48d6516bd..0000000000
--- a/build/unix/build-sqlite3.tcl
+++ /dev/null
@@ -1,142 +0,0 @@
-proc findSqlite3 {} {
- global Sqlite3Include Sqlite3Lib
-
- # candidate directories for local sqlite3:
- set includeDirs {
- "/usr/local/include"
- "/usr/include"
- "/opt/local/include"
- }
- set libDirs {
- "/usr/local/lib"
- "/usr/lib"
- "/opt/local/lib"
- }
-
- if [info exists Sqlite3Include] {
- set includeDirs [list $Sqlite3Include]
- }
- if [info exists Sqlite3Lib] {
- set libDirs [list $Sqlite3Lib]
- }
-
- set includeDir ""
- foreach I $includeDirs {
- set header "${I}/sqlite3.h"
- if {[file exists $header]} {
- set includeDir $I
- break
- }
- }
- if {$includeDir == ""} {
- return {}
- }
-
- set libDir ""
- foreach L $libDirs {
- set libraryA "${L}/libsqlite3.a"
- set librarySo "${L}/libsqlite3.so"
- set libraryDl "${L}/libsqlite3.dylib"
- if {[file exists $libraryA] || [file exists $librarySo] || [file exists $libraryDl]} {
- set libDir $L
- break
- }
- }
- if {$libDir == ""} {
- return {}
- }
-
- return [list $includeDir $libDir]
-}
-
-proc buildSqlite3 {} {
- global CXXFLAGS tcl_platform
-
- puts "building static Sqlite3"
-
- set dirs [findSqlite3]
- if {$dirs == {}} {
- puts "cannot find Sqlite3 library files, skipping this target"
- return
- }
-
- set includeDir [lindex $dirs 0]
- set libDir [lindex $dirs 1]
-
- set cwd [pwd]
- cd "../../src/backends/sqlite3"
- foreach cppFile [glob "*.cpp"] {
- execute "g++ -c $cppFile $CXXFLAGS -I../../core -I${includeDir}"
- }
-
- execute "ar cr libsoci_sqlite3.a [glob *.o]"
- if {$tcl_platform(os) == "Darwin"} {
- # special case for Mac OS X
- execute "ranlib libsoci_sqlite3.a"
- }
- cd $cwd
- eval exec mkdir -p "lib"
- execute "cp ../../src/backends/sqlite3/libsoci_sqlite3.a lib"
- eval exec mkdir -p "include"
- execute "cp ../../src/backends/sqlite3/soci-sqlite3.h include"
-
-}
-
-proc buildSqlite3So {} {
- global CXXFLAGS SHARED
-
- puts "building shared Sqlite3"
-
- set dirs [findSqlite3]
- if {$dirs == {}} {
- puts "cannot find Sqlite3 library files, skipping this target"
- return
- }
-
- set includeDir [lindex $dirs 0]
- set libDir [lindex $dirs 1]
-
- set cwd [pwd]
- cd "../../src/backends/sqlite3"
- foreach cppFile [glob "*.cpp"] {
- execute "g++ -c $cppFile $CXXFLAGS -fPIC -I../../core -I${includeDir}"
- }
-
- execute "g++ $SHARED -o libsoci_sqlite3.so [glob *.o] -L${libDir} -lsqlite3"
- cd $cwd
- eval exec mkdir -p "lib"
- execute "cp ../../src/backends/sqlite3/libsoci_sqlite3.so lib"
- eval exec mkdir -p "include"
- execute "cp ../../src/backends/sqlite3/soci-sqlite3.h include"
-}
-
-proc buildSqlite3Test {} {
- global CXXTESTFLAGS LDL
-
- puts "building Sqlite3 test"
-
- set dirs [findSqlite3]
- if {$dirs == {}} {
- puts "cannot find Sqlite3 library files, skipping this target"
- return
- }
-
- set includeDir [lindex $dirs 0]
- set libDir [lindex $dirs 1]
-
- set dirs [findBoost]
- if {$dirs == {}} {
- puts "cannot find Boost library files, skipping this target"
- return
- }
-
- set boostIncludeDir [lindex $dirs 0]
- set boostLibDir [lindex $dirs 1]
-
- set cwd [pwd]
- cd "../../src/backends/sqlite3/test"
- execute "g++ test-sqlite3.cpp -o test-sqlite3 $CXXTESTFLAGS -I.. -I../../../core -I../../../core/test -I${includeDir} -I${boostIncludeDir} -L../../../../build/unix/lib -L${libDir} -L${boostLibDir} -lsoci_core -lsoci_sqlite3 -lboost_date_time ${LDL} -lsqlite3"
- cd $cwd
- eval exec mkdir -p "tests"
- execute "cp ../../src/backends/sqlite3/test/test-sqlite3 tests"
-}
diff --git a/build/unix/build.tcl b/build/unix/build.tcl
deleted file mode 100755
index 7ec3d32108..0000000000
--- a/build/unix/build.tcl
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/usr/bin/tclsh
-
-# some common compilation settings if you need to change them:
-
-if [info exists env(CXXFLAGS)] {
- set CXXFLAGS $env(CXXFLAGS)
-} else {
- set CXXFLAGS "-Wall -pedantic -Wno-long-long -O2"
-}
-
-set CXXTESTFLAGS "-O2"
-
-if {$tcl_platform(os) == "Darwin"} {
- # special case for Mac OS X
- set SHARED "-dynamiclib -flat_namespace -undefined suppress"
-} else {
- set SHARED "-shared"
-}
-
-if {$tcl_platform(os) == "FreeBSD"} {
- # FreeBSD does not have the libdl library, it is part of libc.
- set LDL ""
-} else {
- set LDL "-ldl"
-}
-
-source "execute.tcl"
-source "find-boost.tcl"
-source "build-core.tcl"
-source "build-oracle.tcl"
-source "build-postgresql.tcl"
-source "build-mysql.tcl"
-
-proc printUsageAndExit {} {
- puts "Usage:"
- puts "$ ./build.tcl list-of-targets"
- puts ""
- puts "list of targets can contain any of:"
- puts "core - the core part of the library (static version)"
- puts "core-so - the core part of the library (shared version)"
- puts "oracle - the static Oracle backend"
- puts "oracle-so - the shared Oracle backend"
- puts " Note: before building Oracle backend"
- puts " set the ORACLE_HOME variable properly."
- puts "postgresql - the static PostgreSQL backend"
- puts "postgresql-so - the shared PostgreSQL backend"
- puts "mysql - the static MySQL backend"
- puts "mysql-so - the shared MySQL backend"
- puts ""
- puts "oracle-test - the test for Oracle"
- puts "postgresql-test - the test for PostgreSQL"
- puts "mysql-test - the test for MySQL"
- puts " Note: build static core and backends first."
- puts ""
- puts "Examples:"
- puts ""
- puts "$ ./build.tcl core mysql"
- puts ""
- puts "$ ./build.tcl core postgresql postgresql-test"
- puts ""
- puts "After successful build the results are in include, lib and test directories."
- puts "Move/copy the contents of these directories wherever you want."
- exit
-}
-
-if {$argc == 0 || $argv == "--help"} {
- printUsageAndExit
-}
-
-foreach target $argv {
- switch -exact $target {
- core buildCore
- core-so buildCoreSo
- oracle buildOracle
- oracle-so buildOracleSo
- oracle-test buildOracleTest
- postgresql buildPostgreSQL
- postgresql-so buildPostgreSQLSo
- postgresql-test buildPostgreSQLTest
- mysql buildMySQL
- mysql-so buildMySQLSo
- mysql-test buildMySQLTest
- default {
- puts "unknown target $target - skipping"
- }
- }
-}
diff --git a/build/unix/execute.tcl b/build/unix/execute.tcl
deleted file mode 100644
index 90d5748572..0000000000
--- a/build/unix/execute.tcl
+++ /dev/null
@@ -1,14 +0,0 @@
-proc execute {command} {
- puts $command
- set result [catch {eval exec $command "2>@ stdout"} output]
- if {$result != 0} {
- puts "The last command did not execute properly:"
- puts $output
- puts "Please contact the SOCI team."
- exit
- } else {
- if {$output != ""} {
- puts $output
- }
- }
-}
diff --git a/build/unix/find-boost.tcl b/build/unix/find-boost.tcl
deleted file mode 100644
index 2904ac3d78..0000000000
--- a/build/unix/find-boost.tcl
+++ /dev/null
@@ -1,47 +0,0 @@
-proc findBoost {} {
- global rootBoost
-
- # candidate directories for local Boost:
- set includeDirs {
- "/usr/local/include"
- "/usr/include"
- "/opt/local/include"
- }
- set libDirs {
- "/usr/local/lib"
- "/usr/lib"
- "/opt/local/lib"
- }
-
- if [info exists rootBoost] {
- set includeDirs [list $rootBoost]
- set libDirs [list $rootBoost]
- }
-
- set includeDir ""
- foreach I $includeDirs {
- set header "${I}/boost/version.hpp"
- if {[file exists $header]} {
- set includeDir $I
- break
- }
- }
- if {$includeDir == ""} {
- return {}
- }
-
- set libDir ""
- foreach L $libDirs {
- set libraryA "${L}/libboost_date_time.a"
- set librarySo "${L}/libboost_date_time.so"
- if {[file exists $libraryA] || [file exists $librarySo]} {
- set libDir $L
- break
- }
- }
- if {$libDir == ""} {
- return {}
- }
-
- return [list $includeDir $libDir]
-}
diff --git a/build/unix/install.tcl b/build/unix/install.tcl
deleted file mode 100644
index e11eda5bb8..0000000000
--- a/build/unix/install.tcl
+++ /dev/null
@@ -1,74 +0,0 @@
-set headerInstallPrefix "/usr/local/include/soci"
-set libInstallPrefix "/usr/local/lib"
-set sociVersion "3.0.0"
-set sociMajor "3"
-
-source "execute.tcl"
-source "local/parameters.tcl"
-
-if [info exists env(DESTDIR)] {
- set DESTDIR $env(DESTDIR)
- set headerInstallPrefix [file normalize ${DESTDIR}/${headerInstallPrefix}]
- set libInstallPrefix [file normalize ${DESTDIR}/${libInstallPrefix}]
-}
-
-set uninstallFile [open "local/uninstall.sh" "w"]
-
-if {[file exists $headerInstallPrefix] == 0} {
- execute "mkdir -p $headerInstallPrefix"
- puts $uninstallFile "rm -rf $headerInstallPrefix"
-}
-
-foreach header [glob "include/*"] {
- set tail [file tail $header]
- puts "copying $tail to ${headerInstallPrefix}"
- execute "cp $header $headerInstallPrefix"
- puts $uninstallFile "rm -f ${headerInstallPrefix}/${tail}"
-}
-
-if {[file exists $libInstallPrefix] == 0} {
- execute "mkdir -p $libInstallPrefix"
- puts $uninstallFile "rm -rf $libInstallPrefix"
-}
-
-foreach lib [glob "lib/*.a"] {
- set tail [file tail $lib]
- puts "copying $tail to ${libInstallPrefix}"
- execute "cp $lib $libInstallPrefix"
- puts $uninstallFile "rm -f ${libInstallPrefix}/${tail}"
-}
-
-set buildDir [pwd]
-cd $libInstallPrefix
-foreach lib [glob "${buildDir}/lib/*.so"] {
- set rootName [file rootname [file tail $lib]]
- set targetName "${rootName}-${sociVersion}.so"
- set majorLink "${rootName}-${sociMajor}.so"
- set link "${rootName}.so"
-
- puts "copying [file tail $lib] to ${targetName}"
- execute "cp $lib $targetName"
- puts $uninstallFile "rm -f ${libInstallPrefix}/${targetName}"
-
- puts "creating link ${majorLink}"
- execute "ln -s $targetName [file tail $majorLink]"
- puts $uninstallFile "rm -f ${libInstallPrefix}/${majorLink}"
-
- puts "creating ${link}"
- execute "ln -s $targetName [file tail $link]"
- puts $uninstallFile "rm -f ${libInstallPrefix}/${link}"
-}
-
-close $uninstallFile
-
-puts "ldconfig ${libInstallPrefix}"
-catch { eval exec "ldconfig ${libInstallPrefix}" }
-
-puts ""
-puts ""
-puts "Hint: the shared libraries were installed in $libInstallPrefix"
-puts "- If you use dynamically loaded backends, then you might need to set"
-puts " the SOCI_BACKENDS_PATH variable accordingly."
-puts ""
-puts "Hint: to remove all installed files and links run make uninstall"
-puts ""
diff --git a/build/unix/parse-parameters.tcl b/build/unix/parse-parameters.tcl
deleted file mode 100644
index 574a6f60e6..0000000000
--- a/build/unix/parse-parameters.tcl
+++ /dev/null
@@ -1,60 +0,0 @@
-set paramsFile [open "local/parameters"]
-set tclParamsFile [open "local/parameters.tcl" "w"]
-
-set line [gets $paramsFile]
-while {![eof $paramsFile]} {
- set pair [split $line "="]
- if {[llength $pair] == 2} {
- set name [lindex $pair 0]
- set value [lindex $pair 1]
-
- switch -exact -- $name {
- --include-prefix {
- puts $tclParamsFile "set headerInstallPrefix $value"
- puts "setting prefix for SOCI headers to $value"
- }
- --lib-prefix {
- puts $tclParamsFile "set libInstallPrefix $value"
- puts "setting prefix for SOCI libraries to $value"
- }
- --mysql-include {
- puts $tclParamsFile "set mysqlInclude $value"
- puts "setting include directory for MySQL to $value"
- }
- --mysql-lib {
- puts $tclParamsFile "set mysqlLib $value"
- puts "setting lib directory for MySQL to $value"
- }
- --oracle-include {
- puts $tclParamsFile "set oracleInclude $value"
- puts "setting include directory for Oracle to $value"
- }
- --oracle-lib {
- puts $tclParamsFile "set oracleLib $value"
- puts "setting lib directory for Oracle to $value"
- }
- --postgresql-include {
- puts $tclParamsFile "set postgresqlInclude $value"
- puts "setting include directory for PostgreSQL to $value"
- }
- --postgresql-lib {
- puts $tclParamsFile "set postgresqlLib $value"
- puts "setting lib directory for PostgreSQL to $value"
- }
- --boost-include {
- puts $tclParamsFile "set boostInclude $value"
- puts "setting Boost include directory to $value"
- }
- --boost-lib {
- puts $tclParamsFile "set boostLib $value"
- puts "setting Boost lib directory to $value"
- }
- default {
- puts "unknown option: $name : skipping it!"
- }
- }
- }
- set line [gets $paramsFile]
-}
-close $paramsFile
-close $tclParamsFile
diff --git a/src/cmake/.gitignore b/cmake/.gitignore
similarity index 100%
rename from src/cmake/.gitignore
rename to cmake/.gitignore
diff --git a/src/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
similarity index 100%
rename from src/cmake/CMakeLists.txt
rename to cmake/CMakeLists.txt
diff --git a/src/cmake/SociBackend.cmake b/cmake/SociBackend.cmake
similarity index 52%
rename from src/cmake/SociBackend.cmake
rename to cmake/SociBackend.cmake
index 5551086e3b..4c113de368 100644
--- a/src/cmake/SociBackend.cmake
+++ b/cmake/SociBackend.cmake
@@ -1,14 +1,14 @@
################################################################################
# SociBackend.cmake - part of CMake configuration of SOCI library
################################################################################
-# Copyright (C) 2010 Mateusz Loskot
+# Copyright (C) 2010-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)
################################################################################
# Macros in this module:
-#
+#
# soci_backend
# - defines project of a database backend for SOCI library
#
@@ -16,10 +16,47 @@
# - defines test project of a database backend for SOCI library
################################################################################
+macro(soci_backend_deps_found NAME DEPS SUCCESS)
+ #message(STATUS "DEPS=${DEPS}")
+
+ # Determine required dependencies
+ set(DEPS_INCLUDE_DIRS)
+ set(DEPS_LIBRARIES)
+ set(DEPS_DEFS)
+ set(DEPS_NOT_FOUND)
+
+ # CMake 2.8+ syntax only:
+ #foreach(dep IN LISTS DEPS)
+ foreach(dep ${DEPS})
+ soci_check_package_found(${dep} DEPEND_FOUND)
+ if(NOT DEPEND_FOUND)
+ list(APPEND DEPS_NOT_FOUND ${dep})
+ else()
+ string(TOUPPER "${dep}" DEPU)
+ list(APPEND DEPS_INCLUDE_DIRS ${${DEPU}_INCLUDE_DIR})
+ list(APPEND DEPS_INCLUDE_DIRS ${${DEPU}_INCLUDE_DIRS})
+ list(APPEND DEPS_LIBRARIES ${${DEPU}_LIBRARIES})
+ list(APPEND DEPS_DEFS HAVE_${DEPU}=1)
+ endif()
+ endforeach()
+
+ list(LENGTH DEPS_NOT_FOUND NOT_FOUND_COUNT)
+
+ if (NOT_FOUND_COUNT GREATER 0)
+ set(${SUCCESS} False)
+ else()
+ set(${NAME}_DEPS_INCLUDE_DIRS ${DEPS_INCLUDE_DIRS})
+ set(${NAME}_DEPS_LIBRARIES ${DEPS_LIBRARIES})
+ set(${NAME}_DEPS_DEFS ${DEPS_DEFS})
+ set(${SUCCESS} True)
+ endif()
+
+ #message(STATUS "soci_backend_deps_found: ${SUCCESS}=${${SUCCESS}}")
+endmacro()
+
# Defines project of a database backend for SOCI library
#
# soci_backend(backendname
-# HEADERS header1 header2
# DEPENDS dependency1 dependency2
# DESCRIPTION description
# AUTHORS author1 author2
@@ -27,7 +64,7 @@
#
macro(soci_backend NAME)
parse_arguments(THIS_BACKEND
- "HEADERS;DEPENDS;DESCRIPTION;AUTHORS;MAINTAINERS;"
+ "DEPENDS;DESCRIPTION;AUTHORS;MAINTAINERS;"
""
${ARGN})
@@ -43,36 +80,13 @@ macro(soci_backend NAME)
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)
+ soci_backend_deps_found(${NAMEU} "${THIS_BACKEND_DEPENDS}" ${NAMEU}_DEPS_FOUND)
+ if(NOT ${NAMEU}_DEPS_FOUND)
colormsg(_RED_ "WARNING:")
colormsg(RED "Some required dependencies of ${NAME} backend not found:")
- if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} LESS 2.8)
+ if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} LESS 2.8)
foreach(dep ${DEPENDS_NOT_FOUND})
colormsg(RED " ${dep}")
endforeach()
@@ -87,43 +101,56 @@ macro(soci_backend NAME)
set(${THIS_BACKEND_OPTION} OFF)
- else(NOT_FOUND_COUNT GREATER 0)
+ else()
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}")
+ get_directory_property(THIS_INCLUDE_DIRS INCLUDE_DIRECTORIES)
+ get_directory_property(THIS_COMPILE_DEFS COMPILE_DEFINITIONS)
- # Backend-specific preprocessor definitions
- add_definitions(${THIS_BACKEND_DEPENDS_DEFS})
+ # Backend-specific depedencies
+ set(THIS_BACKEND_DEPENDS_INCLUDE_DIRS ${${NAMEU}_DEPS_INCLUDE_DIRS})
+ set(THIS_BACKEND_DEPENDS_LIBRARIES ${${NAMEU}_DEPS_LIBRARIES})
+ set(THIS_BACKEND_DEPENDS_DEFS ${${NAMEU}_DEPS_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})
+ # Collect include directories
+ list(APPEND THIS_INCLUDE_DIRS ${SOCI_SOURCE_DIR}/include/private)
+ list(APPEND THIS_INCLUDE_DIRS ${THIS_BACKEND_DEPENDS_INCLUDE_DIRS})
+ # Collect compile definitions
+ list(APPEND THIS_COMPILE_DEFS ${THIS_BACKEND_DEPENDS_DEFS})
- # 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)
+ set_directory_properties(PROPERTIES
+ INCLUDE_DIRECTORIES "${THIS_INCLUDE_DIRS}"
+ COMPILE_DEFINITIONS "${THIS_COMPILE_DEFS}")
# Backend target
+ set(THIS_BACKEND_VAR SOCI_${NAMEU})
set(THIS_BACKEND_TARGET ${PROJECTNAMEL}_${NAMEL})
- set(THIS_BACKEND_TARGET_VAR SOCI_${NAMEU}_TARGET)
+ set(THIS_BACKEND_TARGET_VAR ${THIS_BACKEND_VAR}_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)
+ soci_target_output_name(${THIS_BACKEND_TARGET} ${THIS_BACKEND_VAR}_OUTPUT_NAME)
+
+ set(THIS_BACKEND_OUTPUT_NAME ${${THIS_BACKEND_VAR}_OUTPUT_NAME})
+ set(THIS_BACKEND_OUTPUT_NAME_VAR ${THIS_BACKEND_VAR}_OUTPUT_NAME)
+
+ set(${THIS_BACKEND_VAR}_COMPILE_DEFINITIONS ${THIS_COMPILE_DEFS})
+ set(THIS_BACKEND_COMPILE_DEFINITIONS_VAR ${THIS_BACKEND_VAR}_COMPILE_DEFINITIONS)
+
+ set(${THIS_BACKEND_VAR}_INCLUDE_DIRECTORIES ${THIS_INCLUDE_DIRS})
+ set(THIS_BACKEND_INCLUDE_DIRECTORIES_VAR ${THIS_BACKEND_VAR}_INCLUDE_DIRECTORIES)
+
+ # Backend installable headers and sources
+ file(GLOB THIS_BACKEND_HEADERS ${SOCI_SOURCE_DIR}/include/soci/${NAMEL}/*.h)
+ 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)
# 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}
@@ -132,19 +159,25 @@ macro(soci_backend NAME)
${THIS_BACKEND_HEADERS})
target_link_libraries(${THIS_BACKEND_TARGET}
- ${SOCI_CORE_TARGET}
- ${THIS_BACKEND_DEPENDS_LIBRARIES})
+ ${SOCI_CORE_TARGET}
+ ${THIS_BACKEND_DEPENDS_LIBRARIES})
if(WIN32)
- set_target_properties(${THIS_BACKEND_TARGET}
+ set_target_properties(${THIS_BACKEND_TARGET}
PROPERTIES
- OUTPUT_NAME ${THIS_BACKEND_TARGET_OUTPUT_NAME}
+ OUTPUT_NAME ${THIS_BACKEND_OUTPUT_NAME}
DEFINE_SYMBOL SOCI_DLL)
else()
- set_target_properties(${THIS_BACKEND_TARGET}
+ set_target_properties(${THIS_BACKEND_TARGET}
PROPERTIES
SOVERSION ${${PROJECT_NAME}_SOVERSION}
INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib)
+
+ if(APPLE)
+ set_target_properties(${THIS_BACKEND_TARGET}
+ PROPERTIES
+ LINK_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress")
+ endif()
endif()
set_target_properties(${THIS_BACKEND_TARGET}
@@ -154,7 +187,7 @@ macro(soci_backend NAME)
endif()
# Static library target
- if (SOCI_STATIC)
+ if(SOCI_STATIC)
set(THIS_BACKEND_TARGET_STATIC ${THIS_BACKEND_TARGET}_static)
add_library(${THIS_BACKEND_TARGET_STATIC}
@@ -162,46 +195,50 @@ macro(soci_backend NAME)
${THIS_BACKEND_SOURCES}
${THIS_BACKEND_HEADERS})
+ # Still need to link the libraries for tests to work
+ target_link_libraries (${THIS_BACKEND_TARGET_STATIC}
+ ${THIS_BACKEND_DEPENDS_LIBRARIES}
+ )
+
set_target_properties(${THIS_BACKEND_TARGET_STATIC}
- PROPERTIES
- OUTPUT_NAME ${THIS_BACKEND_TARGET_OUTPUT_NAME}
- PREFIX "lib"
- CLEAN_DIRECT_OUTPUT 1)
+ PROPERTIES
+ OUTPUT_NAME ${THIS_BACKEND_OUTPUT_NAME}
+ PREFIX "lib"
+ CLEAN_DIRECT_OUTPUT 1)
endif()
# Backend installation
install(FILES ${THIS_BACKEND_HEADERS}
- DESTINATION
- ${INCLUDEDIR}/${PROJECTNAMEL}/${NAMEL})
+ DESTINATION
+ ${INCLUDEDIR}/${PROJECTNAMEL}/${NAMEL})
if (SOCI_SHARED)
install(TARGETS ${THIS_BACKEND_TARGET}
- RUNTIME DESTINATION ${BINDIR}
- LIBRARY DESTINATION ${LIBDIR}
- ARCHIVE DESTINATION ${LIBDIR})
+ 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})
+ RUNTIME DESTINATION ${BINDIR}
+ LIBRARY DESTINATION ${LIBDIR}
+ ARCHIVE DESTINATION ${LIBDIR})
endif()
- else()
- colormsg(HIRED "${NAME}" RED "backend disabled, since")
- endif()
+ else()
+ colormsg(HIRED "${NAME}" RED "backend disabled, since")
+ endif()
- endif(NOT_FOUND_COUNT GREATER 0)
+ endif()
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)
+ boost_report_value(${THIS_BACKEND_OUTPUT_NAME_VAR})
+ boost_report_value(${THIS_BACKEND_COMPILE_DEFINITIONS_VAR})
+ boost_report_value(${THIS_BACKEND_INCLUDE_DIRECTORIES_VAR})
endif()
# LOG
@@ -212,7 +249,6 @@ macro(soci_backend NAME)
#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}")
@@ -243,7 +279,7 @@ endfunction(soci_backend_test_create_vcxproj_user)
#
# soci_backend_test(BACKEND mybackend SOURCE mytest1.cpp
# NAME mytest1
-# CONNSTR "my test connection"
+# CONNSTR "my test connection"
# DEPENDS library1 library2)
#
macro(soci_backend_test)
@@ -260,90 +296,90 @@ macro(soci_backend_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)
+ string(TOUPPER "${THIS_TEST_NAME}" NAMEU)
+ set(TEST_FULL_NAME SOCI_${BACKENDU}_TEST_${NAMEU})
+ else()
+ set(TEST_FULL_NAME SOCI_${BACKENDU}_TEST)
+ endif()
+ string(TOLOWER "${TEST_FULL_NAME}" TEST_TARGET)
+ string(TOUPPER "${TEST_FULL_NAME}" NAMEU)
+
+ soci_backend_deps_found(${NAMEU} "${THIS_TEST_DEPENDS}" ${NAMEU}_DEPS_FOUND)
+ if(${NAMEU}_DEPS_FOUND)
+ get_directory_property(THIS_INCLUDE_DIRS INCLUDE_DIRECTORIES)
+ get_directory_property(THIS_COMPILE_DEFS COMPILE_DEFINITIONS)
+
+ set(THIS_TEST_DEPENDS_INCLUDE_DIRS ${${NAMEU}_DEPS_INCLUDE_DIRS})
+ set(THIS_TEST_DEPENDS_LIBRARIES ${${NAMEU}_DEPS_LIBRARIES})
+ set(THIS_TEST_DEPENDS_DEFS ${${NAMEU}_DEPS_DEFS})
+
+ list(APPEND THIS_INCLUDE_DIRS ${THIS_TEST_DEPENDS_INCLUDE_DIRS})
+ list(APPEND THIS_COMPILE_DEFS ${THIS_TEST_DEPENDS_DEFS})
+
+ set_directory_properties(PROPERTIES
+ INCLUDE_DIRECTORIES "${THIS_INCLUDE_DIRS}"
+ COMPILE_DEFINITIONS "${THIS_COMPILE_DEFS}")
+ else()
+ colormsg(_RED_ "WARNING:")
+ colormsg(RED "Some dependencies of ${THIS_TEST_BACKEND} test not found")
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})
+ if( SOCI_SHARED )
+ # Shared libraries test
+ add_executable(${TEST_TARGET} ${THIS_TEST_SOURCE})
- # 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()
+ target_link_libraries(${TEST_TARGET}
+ ${SOCI_CORE_DEPS_LIBS}
+ ${THIS_TEST_DEPENDS_LIBRARIES}
+ soci_core
+ soci_${BACKENDL})
- string(TOLOWER "${TEST_FULL_NAME}" TEST_TARGET)
+ add_test(${TEST_TARGET}
+ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TEST_TARGET}
+ ${${TEST_CONNSTR_VAR}})
- set(TEST_HEADERS ${PROJECT_SOURCE_DIR}/core/test/common-tests.h)
+ soci_backend_test_create_vcxproj_user(${TEST_TARGET} "\"${${TEST_CONNSTR_VAR}}\"")
- # 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}}\"")
+ # Ask make check to try to build tests first before executing them
+ add_dependencies(check ${TEST_TARGET})
+ endif(SOCI_SHARED)
# Static libraries test
if(SOCI_STATIC)
set(TEST_TARGET_STATIC ${TEST_TARGET}_static)
- add_executable(${TEST_TARGET_STATIC} ${TEST_HEADERS} ${THIS_TEST_SOURCE})
+ add_executable(${TEST_TARGET_STATIC} ${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})
+ ${SOCI_CORE_DEPS_LIBS}
+ ${THIS_TEST_DEPENDS_LIBRARIES}
+ soci_core_static
+ soci_${BACKENDL}_static)
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}}\"")
+
+ # Ask make check to try to build tests first before executing them
+ add_dependencies(check ${TEST_TARGET_STATIC})
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()
diff --git a/src/cmake/SociConfig.cmake b/cmake/SociConfig.cmake
similarity index 55%
rename from src/cmake/SociConfig.cmake
rename to cmake/SociConfig.cmake
index fd301b221d..73610e0f2f 100644
--- a/src/cmake/SociConfig.cmake
+++ b/cmake/SociConfig.cmake
@@ -8,6 +8,28 @@
# http://www.boost.org/LICENSE_1_0.txt)
################################################################################
+include(CheckCXXSymbolExists)
+
+if(WIN32)
+ check_cxx_symbol_exists("_M_AMD64" "" SOCI_TARGET_ARCH_X64)
+ if(NOT RTC_ARCH_X64)
+ check_cxx_symbol_exists("_M_IX86" "" SOCI_TARGET_ARCH_X86)
+ endif(NOT RTC_ARCH_X64)
+ # add check for arm here
+ # see http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+else(WIN32)
+ check_cxx_symbol_exists("__i386__" "" SOCI_TARGET_ARCH_X86)
+ check_cxx_symbol_exists("__x86_64__" "" SOCI_TARGET_ARCH_X64)
+ check_cxx_symbol_exists("__arm__" "" SOCI_TARGET_ARCH_ARM)
+endif(WIN32)
+
+#
+# C++11 Option
+#
+
+set (SOCI_CXX_C11 OFF CACHE BOOL "Build to the C++11 standard")
+
+
#
# Force compilation flags and set desired warnings level
#
@@ -19,35 +41,43 @@ if (MSVC)
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")
+ "-pedantic -Werror -Wall -Wpointer-arith -Wcast-align -Wcast-qual -Wfloat-equal -Wredundant-decls -Wno-long-long")
+
+
+ if (SOCI_CXX_C11)
+ set(SOCI_CXX_VERSION_FLAGS "-std=c++11")
+ add_definitions(-DSOCI_CXX_C11)
+ else()
+ set(SOCI_CXX_VERSION_FLAGS "-std=gnu++98")
+ endif()
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
-
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC ${SOCI_GCC_CLANG_COMMON_FLAGS}")
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC ${SOCI_GCC_CLANG_COMMON_FLAGS} ${SOCI_CXX_VERSION_FLAGS} ")
if (CMAKE_COMPILER_IS_GNUCXX)
if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++98")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-variadic-macros")
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}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SOCI_GCC_CLANG_COMMON_FLAGS} ${SOCI_CXX_VERSION_FLAGS}")
else()
- message(FATAL_ERROR "CMake is unable to recognize compilation toolset to build SOCI for you!")
+ message(WARNING "Unknown toolset - using default flags to build SOCI")
endif()
endif()
diff --git a/src/cmake/SociDependencies.cmake b/cmake/SociDependencies.cmake
similarity index 93%
rename from src/cmake/SociDependencies.cmake
rename to cmake/SociDependencies.cmake
index 3c12771a7d..a1014ed3bd 100644
--- a/src/cmake/SociDependencies.cmake
+++ b/cmake/SociDependencies.cmake
@@ -11,7 +11,7 @@
# http://www.boost.org/LICENSE_1_0.txt)
################################################################################
# Macros in this module:
-#
+#
# soci_backend - defines a database backend for SOCI library
#
################################################################################
@@ -19,6 +19,10 @@
#
# List of SOCI dependncies
#
+set(SOCI_CORE_DEPENDENCIES
+ Threads
+ Boost)
+
set(SOCI_BACKENDS_DB_DEPENDENCIES
MySQL
ODBC
@@ -28,13 +32,13 @@ set(SOCI_BACKENDS_DB_DEPENDENCIES
Firebird
DB2)
-set(SOCI_BACKENDS_ALL_DEPENDENCIES
- Boost
+set(SOCI_ALL_DEPENDENCIES
+ ${SOCI_CORE_DEPENDENCIES}
${SOCI_BACKENDS_DB_DEPENDENCIES})
#
# Perform checks
-#
+#
colormsg(_HIBLUE_ "Looking for SOCI dependencies:")
macro(boost_external_report NAME)
@@ -46,7 +50,7 @@ macro(boost_external_report NAME)
list(REMOVE_AT VARNAMES 0)
# Test both, given original name and uppercase version too
- if(NOT SUCCESS)
+ if(NOT SUCCESS)
string(TOUPPER ${NAME} VARNAME)
set(SUCCESS ${${VARNAME}_FOUND})
if(NOT SUCCESS)
@@ -69,7 +73,7 @@ option(WITH_VALGRIND "Run tests under valgrind" OFF)
#
# Detect available dependencies
#
-foreach(external ${SOCI_BACKENDS_ALL_DEPENDENCIES})
+foreach(external ${SOCI_ALL_DEPENDENCIES})
string(TOUPPER "${external}" EXTERNAL)
option(WITH_${EXTERNAL} "Attempt to find and configure ${external}" ON)
if(WITH_${EXTERNAL})
diff --git a/src/cmake/SociUtilities.cmake b/cmake/SociUtilities.cmake
similarity index 92%
rename from src/cmake/SociUtilities.cmake
rename to cmake/SociUtilities.cmake
index 05e91532ff..404ef1abf8 100644
--- a/src/cmake/SociUtilities.cmake
+++ b/cmake/SociUtilities.cmake
@@ -5,7 +5,7 @@
################################################################################
# Copyright (C) 2007 Douglas Gregor
# Copyright (C) 2007 Troy Straszheim
-# Copyright (C) 2010 Mateusz Loskot
+# Copyright (C) 2010-2013 Mateusz Loskot
#
# Distributed under the Boost Software License, Version 1.0.
# See accompanying file LICENSE_1_0.txt or copy at
@@ -29,7 +29,7 @@
# 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)
@@ -63,16 +63,16 @@ endmacro(cdr)
# 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...)
-#
+#
+# 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
@@ -109,8 +109,8 @@ macro(parse_arguments prefix arg_names option_names)
set(${prefix}_${current_arg_name} ${current_arg_list})
endmacro(parse_arguments)
-# Perform a reverse topological sort on the given LIST.
-#
+# 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
@@ -132,7 +132,7 @@ endmacro(parse_arguments)
# using the following variables:
#
# MY_A_EDGES b
-# MY_B_EDGES
+# MY_B_EDGES
# MY_C_EDGES a b
#
# With the involcation of topological_sort shown above and these
@@ -153,7 +153,7 @@ function(topological_sort LIST PREFIX SUFFIX)
# search from where.
if (NOT FOUND_${UPPER_VERTEX})
# Push this vertex onto the stack with all of its outgoing edges
- string(REPLACE ";" " " NEW_ELEMENT
+ string(REPLACE ";" " " NEW_ELEMENT
"${VERTEX};${${PREFIX}${UPPER_VERTEX}${SUFFIX}}")
list(APPEND STACK ${NEW_ELEMENT})
@@ -191,14 +191,14 @@ function(topological_sort LIST PREFIX SUFFIX)
# Push the remaining edges for the current vertex onto the
# stack
- string(REPLACE ";" " " NEW_ELEMENT
+ 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
+ set(OUT_EDGES
${${PREFIX}${UPPER_SOURCE}${SUFFIX}})
endif(NOT FOUND_${UPPER_TARGET})
@@ -275,19 +275,19 @@ function (colormsg)
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"
+# 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
+# pretty-prints the value of a variable so that the
# equals signs align
#
function(boost_report_value NAME)
@@ -296,7 +296,7 @@ function(boost_report_value NAME)
#message(STATUS "boost_report_value: NAME=${NAME} (${varlen})")
#message(STATUS "boost_report_value: \${NAME}=${${NAME}}")
math(EXPR padding_len 40-${varlen})
- string(SUBSTRING " "
+ string(SUBSTRING " "
0 ${padding_len} varpadding)
colormsg("${NAME}${varpadding} = ${${NAME}}")
endfunction()
@@ -309,16 +309,16 @@ function(trace NAME)
0 ${padding_len} varpadding)
message("${NAME} ${varpadding} ${${NAME}}")
endif()
-endfunction()
+endfunction()
#
-# pretty-prints the value of a variable so that the
+# 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 " "
+ string(SUBSTRING " "
0 ${padding_len} varpadding)
message(STATUS "${PRETTYNAME}${varpadding} = ${${VARNAME}}")
endfunction()
@@ -348,7 +348,7 @@ macro(soci_check_package_found NAME SUCCESS)
set(VARNAME_SUCCESS ${${VARNAME}_FOUND})
# Test both, given original name and uppercase version too
- if(VARNAME_SUCCESS)
+ if(VARNAME_SUCCESS)
set(${SUCCESS} TRUE)
else()
string(TOUPPER ${NAME} VARNAME)
@@ -357,15 +357,17 @@ macro(soci_check_package_found NAME SUCCESS)
set(${SUCCESS} TRUE)
endif()
endif()
+
+ #message(STATUS "soci_check_package_found: ${SUCCESS}=${${SUCCESS}}")
endmacro()
#
# Pretty-print of given property of current directory.
#
-macro(soci_report_directory_property PROPNAME)
+function(soci_report_directory_property PROPNAME)
get_directory_property(${PROPNAME} ${PROPNAME})
boost_report_value(${PROPNAME})
-endmacro()
+endfunction()
#
# Scans the current directory and returns a list of subdirectories.
diff --git a/src/cmake/SociVersion.cmake b/cmake/SociVersion.cmake
similarity index 99%
rename from src/cmake/SociVersion.cmake
rename to cmake/SociVersion.cmake
index e6758502d5..d9e277351c 100644
--- a/src/cmake/SociVersion.cmake
+++ b/cmake/SociVersion.cmake
@@ -8,7 +8,7 @@
# http://www.boost.org/LICENSE_1_0.txt)
################################################################################
# Macros in this module:
-#
+#
# soci_version - defines version information for SOCI library
#
################################################################################
diff --git a/src/cmake/dependencies/Boost.cmake b/cmake/dependencies/Boost.cmake
similarity index 83%
rename from src/cmake/dependencies/Boost.cmake
rename to cmake/dependencies/Boost.cmake
index c64af9eee3..366d32b748 100644
--- a/src/cmake/dependencies/Boost.cmake
+++ b/cmake/dependencies/Boost.cmake
@@ -1,10 +1,9 @@
set(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)
+if (NOT Boost_DATE_TIME_FOUND)
find_package(Boost 1.33.1)
endif()
diff --git a/src/cmake/dependencies/DB2.cmake b/cmake/dependencies/DB2.cmake
similarity index 100%
rename from src/cmake/dependencies/DB2.cmake
rename to cmake/dependencies/DB2.cmake
diff --git a/cmake/dependencies/Firebird.cmake b/cmake/dependencies/Firebird.cmake
new file mode 100644
index 0000000000..b072702b0a
--- /dev/null
+++ b/cmake/dependencies/Firebird.cmake
@@ -0,0 +1,9 @@
+option(SOCI_FIREBIRD_EMBEDDED "Use embedded library in Firebird backend" OFF)
+boost_report_value(SOCI_FIREBIRD_EMBEDDED)
+
+set(Firebird_FIND_QUIETLY TRUE)
+
+find_package(Firebird)
+
+boost_external_report(Firebird INCLUDE_DIR LIBRARIES VERSION)
+
diff --git a/cmake/dependencies/MySQL.cmake b/cmake/dependencies/MySQL.cmake
new file mode 100644
index 0000000000..5599b08858
--- /dev/null
+++ b/cmake/dependencies/MySQL.cmake
@@ -0,0 +1,5 @@
+set(MySQL_FIND_QUIETLY TRUE)
+
+find_package(MySQL)
+
+boost_external_report(MySQL INCLUDE_DIR LIBRARIES)
diff --git a/src/cmake/dependencies/ODBC.cmake b/cmake/dependencies/ODBC.cmake
similarity index 100%
rename from src/cmake/dependencies/ODBC.cmake
rename to cmake/dependencies/ODBC.cmake
diff --git a/src/cmake/dependencies/Oracle.cmake b/cmake/dependencies/Oracle.cmake
similarity index 100%
rename from src/cmake/dependencies/Oracle.cmake
rename to cmake/dependencies/Oracle.cmake
diff --git a/src/cmake/dependencies/PostgreSQL.cmake b/cmake/dependencies/PostgreSQL.cmake
similarity index 100%
rename from src/cmake/dependencies/PostgreSQL.cmake
rename to cmake/dependencies/PostgreSQL.cmake
diff --git a/src/cmake/dependencies/SQLite3.cmake b/cmake/dependencies/SQLite3.cmake
similarity index 100%
rename from src/cmake/dependencies/SQLite3.cmake
rename to cmake/dependencies/SQLite3.cmake
diff --git a/cmake/dependencies/Threads.cmake b/cmake/dependencies/Threads.cmake
new file mode 100644
index 0000000000..6a5487554b
--- /dev/null
+++ b/cmake/dependencies/Threads.cmake
@@ -0,0 +1,4 @@
+set(Threads_FIND_QUIETLY TRUE)
+
+find_package(Threads)
+boost_report_value(CMAKE_THREAD_LIBS_INIT)
diff --git a/src/cmake/modules/FindDB2.cmake b/cmake/modules/FindDB2.cmake
similarity index 95%
rename from src/cmake/modules/FindDB2.cmake
rename to cmake/modules/FindDB2.cmake
index ba8b8165a2..2fd243efa7 100644
--- a/src/cmake/modules/FindDB2.cmake
+++ b/cmake/modules/FindDB2.cmake
@@ -26,7 +26,7 @@ if(UNIX)
else()
set(DB2_LIBDIRS "lib64")
endif()
-
+
set(DB2_FIND_INCLUDE_PATHS)
set(DB2_FIND_LIB_PATHS)
foreach(db2_install_path ${DB2_INSTALL_PATHS})
@@ -45,10 +45,10 @@ if(UNIX)
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_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,
@@ -56,8 +56,8 @@ elseif(WIN32)
set(DB2_FIND_LIB_NO_LIB NO_SYSTEM_ENVIRONMENT_PATH)
endif()
-
- set(DB2_FIND_INCLUDE_PATHS
+
+ set(DB2_FIND_INCLUDE_PATHS
$ENV{ProgramW6432}/IBM/SQLLIB/include
$ENV{ProgramFiles}/IBM/SQLLIB/include)
set(DB2_FIND_LIB_PATHS
@@ -84,10 +84,6 @@ 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})
diff --git a/src/cmake/modules/FindDL.cmake b/cmake/modules/FindDL.cmake
similarity index 100%
rename from src/cmake/modules/FindDL.cmake
rename to cmake/modules/FindDL.cmake
diff --git a/src/cmake/modules/FindFirebird.cmake b/cmake/modules/FindFirebird.cmake
similarity index 85%
rename from src/cmake/modules/FindFirebird.cmake
rename to cmake/modules/FindFirebird.cmake
index 4fa279df29..0e9b6784bf 100644
--- a/src/cmake/modules/FindFirebird.cmake
+++ b/cmake/modules/FindFirebird.cmake
@@ -14,10 +14,15 @@ find_path(FIREBIRD_INCLUDE_DIR ibase.h
$ENV{ProgramFiles}/Firebird/*/include
)
+if(SOCI_FIREBIRD_EMBEDDED)
+ set(FIREBIRD_LIB_NAMES fbembed)
+else()
+ set(FIREBIRD_LIB_NAMES fbclient fbclient_ms)
+endif()
+
find_library(FIREBIRD_LIBRARIES
NAMES
- fbclient
- fbclient_ms
+ ${FIREBIRD_LIB_NAMES}
PATHS
/usr/lib
$ENV{ProgramFiles}/Firebird/*/lib
diff --git a/src/cmake/modules/FindMySQL.cmake b/cmake/modules/FindMySQL.cmake
similarity index 94%
rename from src/cmake/modules/FindMySQL.cmake
rename to cmake/modules/FindMySQL.cmake
index f9b3908503..76112f140a 100644
--- a/src/cmake/modules/FindMySQL.cmake
+++ b/cmake/modules/FindMySQL.cmake
@@ -23,6 +23,7 @@ if(WIN32)
$ENV{MYSQL_DIR}/include
$ENV{ProgramFiles}/MySQL/*/include
$ENV{SystemDrive}/MySQL/*/include
+ $ENV{ProgramW6432}/MySQL/*/include
)
else(WIN32)
find_path(MYSQL_INCLUDE_DIR mysql.h
@@ -54,41 +55,30 @@ if(WIN32)
endif(CMAKE_BUILD_TYPE_TOLOWER MATCHES "debug")
# find_library(MYSQL_LIBRARIES NAMES mysqlclient
- find_library(MYSQL_LIBRARIES NAMES libmysql
- PATHS
+ set(MYSQL_LIB_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}
+ $ENV{MYSQL_DIR}/lib/opt
+ $ENV{MYSQL_DIR}/client/release
+ $ENV{ProgramFiles}/MySQL/*/lib/opt
+ $ENV{SystemDrive}/MySQL/*/lib/opt
+ $ENV{ProgramW6432}/MySQL/*/lib
+ )
+ find_library(MYSQL_LIBRARIES NAMES mysqlclient libmysql
+ PATHS
+ ${MYSQL_LIB_PATHS}
)
else(WIN32)
# find_library(MYSQL_LIBRARIES NAMES mysqlclient
- find_library(MYSQL_LIBRARIES NAMES libmysql
- PATHS
+ 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
- )
-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
diff --git a/src/cmake/modules/FindODBC.cmake b/cmake/modules/FindODBC.cmake
similarity index 65%
rename from src/cmake/modules/FindODBC.cmake
rename to cmake/modules/FindODBC.cmake
index 85ecdcfe9d..fd3d9e36df 100644
--- a/src/cmake/modules/FindODBC.cmake
+++ b/cmake/modules/FindODBC.cmake
@@ -1,13 +1,13 @@
-#
+#
# 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
@@ -27,26 +27,31 @@ find_path(ODBC_INCLUDE_DIR sql.h
"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:/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."
)
-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."
-)
+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)
diff --git a/cmake/modules/FindOracle.cmake b/cmake/modules/FindOracle.cmake
new file mode 100644
index 0000000000..1daf24c005
--- /dev/null
+++ b/cmake/modules/FindOracle.cmake
@@ -0,0 +1,76 @@
+###############################################################################
+#
+# 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.
+#
+###############################################################################
+
+# First check for CMAKE variable
+if( NOT ORACLE_HOME )
+ # If ORACLE_HOME is not defined check for env var and if exists set from env var
+ if(EXISTS $ENV{ORACLE_HOME})
+ set(ORACLE_HOME $ENV{ORACLE_HOME})
+ endif(EXISTS $ENV{ORACLE_HOME})
+endif(NOT 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 oraocci12)
+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})
+
+# 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)
diff --git a/src/cmake/modules/FindPostgreSQL.cmake b/cmake/modules/FindPostgreSQL.cmake
similarity index 97%
rename from src/cmake/modules/FindPostgreSQL.cmake
rename to cmake/modules/FindPostgreSQL.cmake
index 8178418ccb..91e9cc20cd 100644
--- a/src/cmake/modules/FindPostgreSQL.cmake
+++ b/cmake/modules/FindPostgreSQL.cmake
@@ -31,7 +31,7 @@ if(PG_CONFIG)
exec_program(${PG_CONFIG}
ARGS "--includedir"
- OUTPUT_VARIABLE PG_CONFIG_INCLUDEDIR)
+ OUTPUT_VARIABLE PG_CONFIG_INCLUDEDIR)
exec_program(${PG_CONFIG}
ARGS "--libdir"
@@ -53,7 +53,7 @@ find_path(POSTGRESQL_INCLUDE_DIR libpq-fe.h
find_library(POSTGRESQL_LIBRARIES NAMES pq libpq
PATHS
- ${PG_CONFIG_LIBDIR}
+ ${PG_CONFIG_LIBDIR}
/usr/lib
/usr/local/lib
/usr/lib/postgresql
diff --git a/src/cmake/modules/FindSQLite3.cmake b/cmake/modules/FindSQLite3.cmake
similarity index 98%
rename from src/cmake/modules/FindSQLite3.cmake
rename to cmake/modules/FindSQLite3.cmake
index 2efb4d4b60..1359bc79ab 100644
--- a/src/cmake/modules/FindSQLite3.cmake
+++ b/cmake/modules/FindSQLite3.cmake
@@ -46,7 +46,7 @@ find_library(SQLITE3_LIBRARY
${SQLITE_ROOT_DIR}/lib
$ENV{OSGEO4W_ROOT}/lib)
-set(SQLITE3_LIBRARIES
+set(SQLITE3_LIBRARIES
${SQLITE3_LIBRARIES}
${SQLITE3_LIBRARY})
diff --git a/src/cmake/modules/FindSoci.cmake b/cmake/modules/FindSoci.cmake
similarity index 100%
rename from src/cmake/modules/FindSoci.cmake
rename to cmake/modules/FindSoci.cmake
diff --git a/src/cmake/resources/vs2010-test-cmd-args.vcxproj.user.in b/cmake/resources/vs2010-test-cmd-args.vcxproj.user.in
similarity index 100%
rename from src/cmake/resources/vs2010-test-cmd-args.vcxproj.user.in
rename to cmake/resources/vs2010-test-cmd-args.vcxproj.user.in
diff --git a/doc/backends.html b/doc/backends.html
deleted file mode 100644
index 869fd5ca6d..0000000000
--- a/doc/backends.html
+++ /dev/null
@@ -1,499 +0,0 @@
-
-
-
-
-
- SOCI - backends
-
-
-
-
SOCI - The C++ Database Access Library
-
-
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.
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.
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.
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.
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.
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:
-
-
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.
-
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.
-
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.
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.
-
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:
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.
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 version
Operating System
Compiler
-
1.5.2.4731
SunOS 5.10
g++ 3.4.3
-
1.5.2.4731
Windows XP
Visual C++ 8.0
-
1.5.3.4870
Windows XP
Visual 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:
-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.
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 version
Operating System
Compiler
-
5.5.28
OS X 10.8.2
Apple LLVM version 4.2
-(clang-425.0.24)
-
5.0.96
Ubuntu 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
-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:
-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:
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:
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 version
Operating System
Compiler
-
10.2.0 (XE)
RedHat 5
g++ 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:
-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:
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 version
Operating System
Compiler
-
9.0
Mac OS X 10.6.6
g++ 4.2
-
8.4
FreeBSD 8.2
g++ 4.1
-
8.4
Debian 6
g++ 4.3
-
8.4
RedHat 5
g++ 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:
-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
-
-
None.
-
-
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.
The SOCI SQLite3 backend is supported for use with SQLite3 >= 3.1
-
-
Tested Platforms
-
-
-
-
SQLite3 version
Operating System
Compiler
-
3.5.2
Mac OS X 10.5
g++ 4.0.1
-
3.1.3
Mac OS X 10.4
g++ 4.0.1
-
3.2.1
Linux i686 2.6.10-gentoo-r6
g++ 3.4.5
-
3.3.4
Ubuntu 5.1
g++ 4.0.2
-
3.3.4
Windows XP
(cygwin) g++ 3.3.4
-
3.3.4
Windows XP
Visual C++ 2005 Express Edition
-
3.3.8
Windows XP
Visual C++ 2005 Professional
-
3.4.0
Windows XP
(cygwin) g++ 3.4.4
-
3.4.0
Windows XP
Visual 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.
-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:
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.
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.
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:
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.
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.
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:
-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:
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:
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:
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:
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()):
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:
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:
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:
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:
-
-
there is a person with id = 7 and his name is returned
-
there is a person with id = 7, but he has no name (his name is
-null in the database table)
-
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:
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:
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:
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:
The offset parameter is always counted from the beginning
-of the BLOB's data.
-
-
-
Portability notes:
-
-
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.
-
The trim function is not currently available for
-the PostgreSQL backend.
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).
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"
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:
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.2, libsoci_sqlite3.so.3.2.2, 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.
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.
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.
-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.
-
-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.
-
-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.
-
-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.
-
-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.
-
-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.
-
-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.
-
-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:
-
-
-
Modular design based on dynamic backend loading. Thanks to this feature, new backends implemented within the context of the main SOCI project are immediately available for Ada programmers without any additional work. A large community of C++ users can help ensure that the new backends are well tested in a variety of environments and usage scenarios.
-
Native backends for major database servers ensure optimal performance and minimize configuration overhead and complexity that is usually associated with other database access methods.
-
Direct support for bulk operations allow to achieve high performance with queries that operate on large data sets.
-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.
-
-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.
-
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.
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:
-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.
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.
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.
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:
-
- 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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
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:
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>.
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.
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.
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.
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).
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.
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.
-// 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:
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:
-
-
-// Example 3.
-const int BATCH_SIZE = 25;
-std::vector<int> ids;
-for (int i = 0; i != BATCH_SIZE; ++i)
-{
- ids.push_back(i);
-}
-
-statement st = (sql.prepare <<
- "insert into numbers(value) values(:val)",
- use(ids));
-for (int i = 0; i != 4; ++i)
-{
- st.execute(true);
-}
-
-
-
(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:
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:
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.
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:
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.
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.
-
-
diff --git a/doc/structure.odg b/doc/structure.odg
deleted file mode 100644
index 64aa0761c5..0000000000
Binary files a/doc/structure.odg and /dev/null differ
diff --git a/doc/structure.png b/doc/structure.png
deleted file mode 100644
index 1694cb6871..0000000000
Binary files a/doc/structure.png and /dev/null differ
diff --git a/doc/style.css b/doc/style.css
deleted file mode 100644
index 74cc190236..0000000000
--- a/doc/style.css
+++ /dev/null
@@ -1,118 +0,0 @@
-body
-{
- 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;
-}
diff --git a/docs/backends.md b/docs/backends.md
new file mode 100644
index 0000000000..84eb7b4f98
--- /dev/null
+++ b/docs/backends.md
@@ -0,0 +1,273 @@
+## Backends reference
+
+This part of the documentation is provided for those who want towrite (and contribute!) their own backends. It is anyway recommendedthat authors of new backend see the code of some existing backend forhints on how things are really done.
+
+The backend interface is a set of base classes that the actual backendsare supposed to specialize. The main SOCI interface uses only theinterface and respecting the protocol (for example, the order offunction calls) described here. Note that both the interface and theprotocol 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 otherbackends, where things are done differently and therefore have to beadjusted, 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 retrievedsome 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 foreach value retrieved from the database. If the given server supportsbinary data transmission and the data format for the given type agreeswith what is used on the client machine, then these two functions neednot do anything; otherwise buffer management and data conversionsshould 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;` (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.
+
+
+* `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.
\ No newline at end of file
diff --git a/docs/backends/db2.md b/docs/backends/db2.md
new file mode 100644
index 0000000000..e24fabb8ba
--- /dev/null
+++ b/docs/backends/db2.md
@@ -0,0 +1,90 @@
+## DB2 Backend Reference
+
+* [Prerequisites](#prerequisites)
+ * [Supported Versions](#versions)
+ * [Tested Platforms](#platforms)
+ * [Required Client Libraries](#required)
+* [Connecting to the Database](#connecting)
+* [SOCI Feature Support](#features)
+ * [Dynamic Binding](#dynamic)
+ * [Binding by Name](#name)
+ * [Bulk Operations](#bulk)
+ * [Transactions](#transactions)
+ * [BLOB Data Type](#blob)
+ * [RowID Data Type](#rowid)
+ * [Nested Statements](#nested)
+ * [Stored Procedures](#stored)
+* [Accessing the Native Database API](#native)
+* [Backend-specific Extensions](#extensions)
+* [Configuration options](#config)
+
+### Prerequisites
+#### Supported Versions
+
+The SOCI DB2 backend.
+
+#### Tested Platforms
+
+
+
+
DB2 version
Operating System
Compiler
+
-
Linux PPC64
GCC
+
9.1
Linux
GCC
+
9.5
Linux
GCC
+
9.7
Linux
GCC
+
10.1
Linux
GCC
+
10.1
Windows 8
Visual 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
+
+#### 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.
\ No newline at end of file
diff --git a/docs/backends/firebird.md b/docs/backends/firebird.md
new file mode 100644
index 0000000000..f1a92bd15a
--- /dev/null
+++ b/docs/backends/firebird.md
@@ -0,0 +1,200 @@
+## Firebird Backend Reference
+
+* [Prerequisites](#prerequisites)
+ * [Supported Versions](#versions)
+ * [Tested Platforms](#platforms)
+ * [Required Client Libraries](#required)
+* [Connecting to the Database](#connecting)
+* [SOCI Feature Support](#features)
+ * [Dynamic Binding](#dynamic)
+ * [Binding by Name](#name)
+ * [Bulk Operations](#bulk)
+ * [Transactions](#transactions)
+ * [BLOB Data Type](#blob)
+ * [RowID Data Type](#rowid)
+ * [Nested Statements](#nested)
+ * [Stored Procedures](#stored)
+* [Accessing the Native Database API](#native)
+* [Backend-specific Extensions](#extensions)
+* [Configuration options](#configuration)
+ * [FirebirdSOCIError](#firebirdsocierror)
+
+### Prerequisites
+
+#### Supported Versions
+
+The SOCI Firebird backend supports versions of Firebird from 1.5 to 2.5 and can be used with either the client-server or embedded Firebird libraries. The former is the default, to select the latter set SOCI_FIREBIRD_EMBEDDED CMake option to ON value when building.
+
+#### Tested Platforms
+
+
+
+
Firebird version
Operating System
Compiler
+
1.5.2.4731
SunOS 5.10
g++ 3.4.3
+
1.5.2.4731
Windows XP
Visual C++ 8.0
+
1.5.3.4870
Windows XP
Visual C++ 8.0 Professional
+
2.5.2.26540
Debian GNU/Linux 7
g++ 4.7.2
+
+
+
+#### 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](../basics.html) and [exchanging data](../exchange.html) 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()`, the type you should pass as T depends upon the underlying database type. For the Firebird backend, this type mapping is:
+
+
+
+[1] There is also 64bit integer type for larger values which is
+currently not supported.
+
+(See the [dynamic resultset binding](../exchange.html#dynamic) documentation for general information on using the `Row` class.)
+
+
+#### Binding by Name
+
+In addition to [binding by position](../exchange.html#bind_position), the Firebird backend supports [binding by name](../exchange.html#bind_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](../statements.html#bulk) interface. This feature is also supported by emulation.
+
+#### Transactions
+
+[Transactions](../statements.html#transactions) are also fully supported by the Firebird backend. In fact, an implicit transaction is always started when using this backend if one hadn't been started by explicitly calling begin() before. The current transaction is automatically committed in `Session's` destructor.
+
+#### BLOB Data Type
+
+The Firebird backend supports working with data stored in columns of type Blob, via SOCI's `[BLOB](../exchange.html#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](../statements.html#procedures) class.
+
+
+### Acessing the native database API
+
+SOCI provides access to underlying datbabase APIs via several getBackEnd() functions, as described in the [beyond SOCI](../beyond.html) 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()
+
code>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.
\ No newline at end of file
diff --git a/doc/backends/index.html b/docs/backends/index.md
similarity index 69%
rename from doc/backends/index.html
rename to docs/backends/index.md
index fc1735cc4e..cbb8cec5ee 100644
--- a/doc/backends/index.html
+++ b/docs/backends/index.md
@@ -1,21 +1,10 @@
-
-
-
-
-
- SOCI - Existing Backends
-
+## Existing backends and supported platforms
-
-
SOCI - The C++ Database Access Library
+### Supported Features
-
Existing backends and supported platforms
+(Follow the links to learn more about each backend.)
-
Supported Features
-
-
(Follow the links to learn more about each backend.)
-
-
+
@@ -62,7 +51,7 @@
YES
YES
YES
- (with servers that support them, usually >= 4.0)
+ (with servers that support them, usually >= 4.0)
-
-
-
diff --git a/docs/backends/mysql.md b/docs/backends/mysql.md
new file mode 100644
index 0000000000..0b289de17a
--- /dev/null
+++ b/docs/backends/mysql.md
@@ -0,0 +1,204 @@
+## MySQL Backend Reference
+
+* [Prerequisites](#prerequisites)
+ * [Supported Versions](#versions)
+ * [Tested Platforms](#tested)
+ * [Required Client Libraries](#required)
+* [Connecting to the Database](#connecting)
+* [SOCI Feature Support](#support)
+ * [Dynamic Binding](#dynamic)
+ * [Binding by Name](#name)
+ * [Bulk Operations](#bulk)
+ * [Transactions](#transactions)
+ * [BLOB Data Type](#blob)
+ * [RowID Data Type](#rowid)
+ * [Nested Statements](#nested)
+ * [Stored Procedures](#stored)
+* [Accessing the Native Database API](#native)
+* [Backend-specific Extensions](#extensions)
+* [Configuration options](#configuration)
+
+
+
+### 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 version
Operating System
Compiler
+
5.5.28
OS X 10.8.2
Apple LLVM version 4.2
+(clang-425.0.24)
+
5.0.96
Ubuntu 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]("../basics.html) and [exchanging data](../exchange.html) 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
TIMESTAMP (works only with MySQL >= 5.0), DATE,
+ TIME, DATETIME
+
dt_date
+
std::tm
+
+
+
+
+(See the [dynamic resultset binding](../exchange.html#dynamic) documentation for general information on using the `Row` class.)
+
+#### Binding by Name
+
+In addition to [binding by position](../exchange.html#bind_position), the MySQL backend supports
+[binding by name](../exchange.html#bind_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
+
+[Transactions](../statements.html#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 [procedure MySQL documentation](http://dev.mysql.com/doc/refman/5.0/en/stored-procedures.html)). Stored functions can be executed by using SOCI's [procedure class](../statements.html#procedures). 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](../beyond.html) 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.
\ No newline at end of file
diff --git a/docs/backends/odbc.md b/docs/backends/odbc.md
new file mode 100644
index 0000000000..4d56979ac9
--- /dev/null
+++ b/docs/backends/odbc.md
@@ -0,0 +1,252 @@
+## ODBC Backend Reference
+
+* [Prerequisites](#prerequisites)
+ * [Supported Versions](#versions)
+ * [Tested Platforms](#tested)
+ * [Required Client Libraries](#required)
+* [Connecting to the Database](#connecting)
+* [SOCI Feature Support](#support)
+ * [Dynamic Binding](#dynamic)
+ * [Binding by Name](#name)
+ * [Bulk Operations](#bulk)
+ * [Transactions](#transactions)
+ * [BLOB Data Type](#blob)
+ * [RowID Data Type](#rowid)
+ * [Nested Statements](#nested)
+ * [Stored Procedures](#stored)
+* [Accessing the Native Database API](#native)
+* [Backend-specific Extensions](#extensions)
+ * [odbc_soci_error](#odbcsocierror)
+* [Configuration options](#configuration)
+
+
+### Prerequisites
+
+#### Supported Versions
+
+The SOCI ODBC backend is supported for use with ODBC 3.
+
+#### Tested Platforms
+
+
+
+
ODBC version
Operating System
Compiler
+
3
Linux (Ubuntu 12.04)
g++ 4.6.3
+
3
Linux (Ubuntu 12.04)
clang 3.2
+
3.8
Windows 8
Visual Studio 2012
+
3
Windows 7
Visual Studio 2010
+
3
Windows XP
Visual Studio 2005 (express)
+
3
Windows XP
Visual C++ 8.0 Professional
+
3
Windows XP
g++ 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](http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbcsql/od_odbc_d_4x4k.asp)` 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](../basics.html) and [exchanging data](../exchange.html) 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()`, the type you should pass as T depends upon the underlying database type.
+For the ODBC backend, this type mapping is:
+
+
+
+Not all ODBC drivers support all datatypes.
+
+(See the [dynamic resultset binding](../exchange.html#dynamic) documentation for general information on using the `row` class.)
+
+
+#### Binding by Name
+
+In addition to [binding by position](../exchange.html#bind_position), the ODBC backend supports [binding by name](../exchange.html#bind_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](../statements.html#bulk) 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](../statements.html#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](../beyond.html) 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);
\ No newline at end of file
diff --git a/docs/backends/oracle.md b/docs/backends/oracle.md
new file mode 100644
index 0000000000..dbe33ce169
--- /dev/null
+++ b/docs/backends/oracle.md
@@ -0,0 +1,219 @@
+## Oracle Backend Reference
+
+* [Prerequisites](#prerequisites)
+ * [Supported Versions](#versions)
+ * [Tested Platforms](#tested)
+ * [Required Client Libraries](#required)
+* [Connecting to the Database](#connecting)
+* [SOCI Feature Support](#support)
+ * [Dynamic Binding](#dynamic)
+ * [Binding by Name](#name)
+ * [Bulk Operations](#bulk)
+ * [Transactions](#transactions)
+ * [BLOB Data Type](#blob)
+ * [RowID Data Type](#rowid)
+ * [Nested Statements](#nested)
+ * [Stored Procedures](#stored)
+* [Accessing the Native Database API](#native)
+* [Backend-specific Extensions](#extensions)
+ * [oracle_soci_error](#oraclesocierror)
+
+
+### 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 version
Operating System
Compiler
+
10.2.0 (XE)
RedHat 5
g++ 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)
+
+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](../basics.html) and [exchanging data](../exchange.html) 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()`, the type you should pass as `T` depends upon the nderlying 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](../exchange.html#dynamic) documentation for general information on using the `row` class.)
+
+#### Binding by Name
+
+In addition to [binding by position](../exchange.html#bind_position), the Oracle backend supports [binding by name](../exchange.html#bind_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](../statements.html#bulk) interface.
+
+#### Transactions
+
+[Transactions](../statements.html#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](../exchange.html#blob) class.
+
+#### rowid Data Type
+
+Oracle rowid's are accessible via SOCI's [rowid](../reference.html#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](../statements.html#procedures) class.
+
+### Acessing the native database API
+
+SOCI provides access to underlying datbabase APIs via several `get_backend()` functions, as described in the [Beyond SOCI](../beyond.html) 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
+
+#### oracle_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;
+ }
+ }
\ No newline at end of file
diff --git a/docs/backends/postgresql.md b/docs/backends/postgresql.md
new file mode 100644
index 0000000000..e6f9985b2d
--- /dev/null
+++ b/docs/backends/postgresql.md
@@ -0,0 +1,204 @@
+## PostgreSQL Backend Reference
+
+* [Prerequisites](#prerequisites)
+ * [Supported Versions](#versions)
+ * [Tested Platforms](#tested)
+ * [Required Client Libraries](#required)
+* [Connecting to the Database](#connecting)
+* [SOCI Feature Support](#support)
+ * [Dynamic Binding](#dynamic)
+ * [Binding by Name](#name)
+ * [Bulk Operations](#bulk)
+ * [Transactions](#transactions)
+ * [BLOB Data Type](#blob)
+ * [RowID Data Type](#rowid)
+ * [Nested Statements](#nested)
+ * [Stored Procedures](#stored)
+* [Accessing the Native Database API](#native)
+* [Backend-specific Extensions](#extensions)
+ * [UUID Data Type](#uuid)
+* [Configuration options](#configuration)
+
+### 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 version
Operating System
Compiler
+
9.0
Mac OS X 10.6.6
g++ 4.2
+
8.4
FreeBSD 8.2
g++ 4.1
+
8.4
Debian 6
g++ 4.3
+
8.4
RedHat 5
g++ 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](http://www.postgresql.org/docs/8.3/interactive/libpq.html#LIBPQ-CONNECT)` 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 [exchanging data](../basics.html">SOCI basics and 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()`, 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](../exchange.html#dynamic) documentation for general information on using the `row` class.)
+
+#### Binding by Name
+
+In addition to [binding by position](../exchange.html#bind_position), the PostgreSQL backend supports [binding by name](../exchange.html#bind_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](#options) section for details.
+
+#### Bulk Operations
+
+The PostgreSQL backend has full support for SOCI's [bulk operations](../statements.html#bulk) interface.
+
+#### Transactions
+
+[Transactions](../statements.html#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](../exchange.html#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](../reference.html#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](../statements.html#procedures) class.
+
+### Acessing the native database API
+
+SOCI provides access to underlying datbabase APIs via several `get_backend()` functions, as described in the [beyond SOCI](../beyond.html) 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.
\ No newline at end of file
diff --git a/docs/backends/sqlite3.md b/docs/backends/sqlite3.md
new file mode 100644
index 0000000000..409905fc74
--- /dev/null
+++ b/docs/backends/sqlite3.md
@@ -0,0 +1,200 @@
+## SQLite3 Backend Reference
+
+* [Prerequisites](#prerequisites)
+ * [Supported Versions](#versions)
+ * [Tested Platforms](#tested)
+ * [Required Client Libraries](#required)
+* [Connecting to the Database](#connecting)
+* [SOCI Feature Support](#support)
+ * [Dynamic Binding](#dynamic)
+ * [Binding by Name](#name)
+ * [Bulk Operations](#bulk)
+ * [Transactions](#transactions)
+ * [BLOB Data Type](#blob)
+ * [RowID Data Type](#rowid)
+ * [Nested Statements](#nested)
+ * [Stored Procedures](#stored)
+* [Accessing the Native Database API](#native)
+* [Backend-specific Extensions](#extensions)
+ * [SQLite3 result code support](#sqlite3result)
+* [Configuration options](#options)
+
+
+### Prerequisites
+
+#### Supported Versions
+
+The SOCI SQLite3 backend is supported for use with SQLite3 >= 3.1
+
+#### Tested Platforms
+
+
+
+
SQLite3 version
Operating System
Compiler
+
3.5.2
Mac OS X 10.5
g++ 4.0.1
+
3.1.3
Mac OS X 10.4
g++ 4.0.1
+
3.2.1
Linux i686 2.6.10-gentoo-r6
g++ 3.4.5
+
3.3.4
Ubuntu 5.1
g++ 4.0.2
+
3.3.4
Windows XP
(cygwin) g++ 3.3.4
+
3.3.4
Windows XP
Visual C++ 2005 Express Edition
+
3.3.8
Windows XP
Visual C++ 2005 Professional
+
3.4.0
Windows XP
(cygwin) g++ 3.4.4
+
3.4.0
Windows XP
Visual 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");
+
+ // or:
+
+ session sql("sqlite3", "db=db.sqlite timeout=2 shared_cache=true");
+
+The set of parameters used in the connection string for SQLite is:
+
+* `dbname` or `db`
+* `timeout` - set sqlite busy timeout (in seconds) ([link](http://www.sqlite.org/c3ref/busy_timeout.html)
+* `synchronous` - set the pragma synchronous flag ([link](http://www.sqlite.org/pragma.html#pragma_synchronous))
+* `shared_cache` - should be `true` ([link](http://www.sqlite.org/c3ref/enable_shared_cache.html))
+
+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](../basics.html) and [exchanging data](../exchange.html) 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()`, 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][INTEGER_PRIMARY_KEY] 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*, *double*
+
dt_double
+
double
+
+
+
*int8*, *bigint*
+
dt_long_long
+
long long
+
+
+
*unsigned big int*
+
dt_unsigned_long_long
+
unsigned long long
+
+
+
*int*, *boolean*
+
dt_integer
+
int
+
+
+
*text, *char*
+
dt_string
+
std::string
+
+
+
*date*, *time*
+
dt_date
+
std::tm
+
+
+
+
+[INTEGER_PRIMARY_KEY] : 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](../exchange.html#dynamic) documentation for general information on using the `row` class.)
+
+#### Binding by Name
+
+In addition to [binding by position](../exchange.html#bind_position), the SQLite3 backend supports [binding by name](../exchange.html#bind_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]](http://www.sqlite.org/capi3ref.html#sqlite3_bind_int):
+
+ 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](../statements.html#bulk) interface. However, this support is emulated and is not native.
+
+#### Transactions
+
+[Transactions](../statements.html#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]](http://www.sqlite.org/capi3ref.html#sqlite3_last_insert_rowid)
+
+#### 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](../beyond.html) 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
\ No newline at end of file
diff --git a/docs/beyond.md b/docs/beyond.md
new file mode 100644
index 0000000000..55767b60d1
--- /dev/null
+++ b/docs/beyond.md
@@ -0,0 +1,75 @@
+## 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, MySQL, ODBC, PostgreSQL and SQLite3 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(sql.get_back_end());
+ oracle_blob_back_end * blobBackEnd = static_cast(b.get_back_end());
+
+ OCILobDisableBuffering(sessionBackEnd->svchp_, sessionBackEnd->errhp_, blobBackEnd->lobp_);
+
+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.
\ No newline at end of file
diff --git a/docs/boost.md b/docs/boost.md
new file mode 100644
index 0000000000..d5f4acf478
--- /dev/null
+++ b/docs/boost.md
@@ -0,0 +1,78 @@
+## Integration with Boost
+
+The SOCI user code can be easily integrated with the [Boost library](http://www.boost.org/) thanks to the very flexible type conversion facility. There are three important Boost types that are supported out of the box.
+
+####boost::optional
+
+`boost::optional` 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` objects can be used everywhere where the regular user provided values are expected.
+
+Example:
+
+ boost::optional 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` 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
+
+`boost::tuple` 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.
+
+ boost::tuple 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`
+
+ boost::tuple, 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
+
+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
+ #include
+ #include
+ #include
+
+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.
\ No newline at end of file
diff --git a/docs/connections.md b/docs/connections.md
new file mode 100644
index 0000000000..2f61585d79
--- /dev/null
+++ b/docs/connections.md
@@ -0,0 +1,90 @@
+## 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 `close`d and `reconnect`ed, 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](multithreading.html) for a detailed description of connection pools.
+
+It is possible to have many active `session`s at the same time, even using different backends.
+
+### Portability note
+
+The following backend factories are currently (as of 3.1.0 release) available:
+
+* [mysql](backends/mysql.html) (requires `#include "soci-mysql.h"`)
+* [oracle](backends/oracle.html) (requires `#include "soci-oracle.h"`)
+* [postgresql](backends/postgresql.html) (requires `#include "soci-postgresql.h"`)
+
+The following backends are also available, with various levels of completeness:
+
+* [sqlite3](backends/sqlite3.html) (requires `#include "soci-sqlite3.h"`)
+* [odbc](backends/odbc.html) (requires `#include "soci-odbc.h"`)
+* [firebird](backends/firebird.html) (requires `#include "soci-firebird.h"`)
\ No newline at end of file
diff --git a/docs/errors.md b/docs/errors.md
new file mode 100644
index 0000000000..4e3ce67e83
--- /dev/null
+++ b/docs/errors.md
@@ -0,0 +1,82 @@
+## 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;
+ }
+ }
+
+The only public method of `soci_error` is `std::string get_error_message() const`, which returns just the brief error message, without any additional information that can be present in the full error message returned by `what()`.
+
+
+#### 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;
+ }
+ }
\ No newline at end of file
diff --git a/docs/exchange.md b/docs/exchange.md
new file mode 100644
index 0000000000..0e90aa6e4c
--- /dev/null
+++ b/docs/exchange.md
@@ -0,0 +1,536 @@
+## Exchanging data
+
+* [Binding local data](#bind_local)
+* [Binding output data](#bind_output)
+ * [Binding input data](#bind_input)
+ * [Binding by position](#bind_position)
+ * [Binding by name](#bind_name)
+* [Handling of nulls and other conditions](exchange.html#data_states)
+ * [Indicators](#indicators)
+* [Types](#types)
+ * [Static binding](#static)
+ * [Static binding for bulk operations](#static_bulk)
+ * [Dynamic resultset binding](#dynamic)
+ * [Extending with user-provided datatypes](#custom_types)
+ * [Object-relational mapping](#object_relational)
+* [Large objects (BLOBs)](#blob)
+
+
+### 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.
+
+ 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](#dynamic) for the exception to this rule).
+
+
+#### Binding output
+
+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](#dynamic") 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 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 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 << "> 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.
+
+
+#### 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 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 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:
+
+* 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.
+* The `trim` function is not currently available for the PostgreSQL backend.
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000000..405da98449
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,71 @@
+# Documentation and tutorial
+
+* [Structure](structure.html)
+* [Installation](installation.html)
+* [Errors](errors.html)
+* [Connections](connections.html)
+* [Queries](queries.html)
+* [Exchanging data](exchange.html)
+* [Statements, procedures and transactions](statements.html)
+* [Multithreading and SOCI](multithreading.html)
+* [Integration with Boost](boost.html)
+* [Interfaces](interfaces.html)
+* [Beyond standard SQL](beyond.html)
+* [Client interface reference](interfaces.html)
+* [Backends reference](backends.html)
+* [Rationale FAQ](rationale.html)
+* [Ada language binding](languages/ada.html)
+* [Existing backends and supported platforms](backends/index.html)
+
+The following (complete!) example is purposedly provided without any explanation.
+
+ #include "soci.h"
+ #include "soci-oracle.h"
+ #include
+ #include
+ #include
+ #include
+ #include
+
+ 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';
+ }
+ }
\ No newline at end of file
diff --git a/docs/installation.md b/docs/installation.md
new file mode 100644
index 0000000000..6721625148
--- /dev/null
+++ b/docs/installation.md
@@ -0,0 +1,213 @@
+## Installation
+
+* [Requirements](#requirements)
+* [Downloading](#downloading)
+* [Building using CMake](#building)
+ * [On Unix](#unix)
+ * [On Windows](#windows)
+* [Building using classic Makefiles on Unix](#makefiles)
+* [Running Tests](#regression)
+* [Usage](#library)
+
+### Requirements
+
+Below is an overall list of SOCI core:
+
+* C++ compiler: [GCC](http://gcc.gnu.org/), [Microsoft Visual C++](http://msdn.microsoft.com/en-us/visualc), [LLVM/clang](http://clang.llvm.org/)
+* [CMake](http://www.cmake.org) 2.8+ - in order to use build configuration for CMake
+* [Boost C++ Libraries](http://www.boost.org): DateTime, Fusion, Optional, Preprocessor, Tuple
+
+and backend-specific dependencies:
+
+* [DB2 Call Level Interface (CLI)](http://pic.dhe.ibm.com/infocenter/db2luw/v10r1/topic/com.ibm.swg.im.dbclient.install.doc/doc/c0023452.html)
+* [Firebird client library](http://www.firebirdsql.org/manual/ufb-cs-clientlib.html)
+* [mysqlclient](http://dev.mysql.com/doc/refman/5.6/en/c.html) - C API to MySQL
+* ODBC (Open Database Connectivity) implementation: [Microsoft ODBC](http://msdn.microsoft.com/en-us/library/windows/desktop/ms710252.aspx) [iODBC](http://www.iodbc.org/), [unixODBC](http://www.unixodbc.org/)
+* [Oracle Call Interface (OCI)](http://www.oracle.com/technetwork/database/features/oci/index.html)
+* [libpq](http://www.postgresql.org/docs/8.4/static/libpq.html) - C API to PostgreSQL
+* [SQLite 3](http://www.sqlite.org/) library
+
+### Downloading
+
+Download package with latest release of the SOCI source code: [soci-X.Y.Z](https://sourceforge.net/projects/soci/), 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](http://cmake.org/) 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](http://cmake.org/cmake/help/documentation.html)) 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](http://cmake.org/cmake/help/runningcmake.html") 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](http://cmake.org/cmake/help/cmake-2-8-docs.html#variable:CMAKE_BUILD_TYPE)).
+* CMAKE_INSTALL_PREFIX - path - Install directory used by install command (see CMake [help](http://cmake.org/cmake/help/cmake-2-8-docs.html#variable:CMAKE_INSTALL_PREFIX)).
+* CMAKE_VERBOSE_MAKEFILE - boolean - If ON, create verbose makefile (see CMake [help](http://cmake.org/cmake/help/cmake-2-8-docs.html#variable:CMAKE_VERBOSE_MAKEFILE)).
+
+#### 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](http://www.boost.org/). If ON, CMake will try to find Boost headers and binaries of [Boost.Date_Time](http://www.boost.org/doc/libs/release/doc/html/date_time.html) 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](backends/db2.html) backend. Automatically switched on, if `WITH_DB2` is set to ON.
+* SOCI_DB2_TEST_CONNSTR - string - See [DB2 backend reference](backends/db2.html) 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](backends/firebird.html) backend. Automatically switched on, if `WITH_FIREBIRD` is set to ON.
+* SOCI_FIREBIRD_TEST_CONNSTR - string - See [Firebird backend refernece](backends/firebird.html) 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](http://dev.mysql.com/doc/refman/5.0/en/c.html) libraries providing MySQL C API. Note, currently the [mysql_config](http://dev.mysql.com/doc/refman/5.0/en/building-clients.html) 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](backends/mysql.html) 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](backends/mysql.html). 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](http://www.unixodbc.org/) or [iODBC](http://www.iodbc.org/) 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](backends/odbc.html) 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](backends/odbc.html) 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)](http://en.wikipedia.org/wiki/Oracle_Call_Interface) 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](backends/oracle.html) 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 reference](backends/oracle.html). 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](http://www.postgresql.org/docs/9.0/interactive/libpq.html") 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](backends/postgresql.html") backend. Automatically switched on, if `WITH_POSTGRESQL` is set to ON.
+* SOCI_POSTGRESQL_TEST_CONNSTR - boolean - Should CMak try to detect [SQLite C/C++ library](http://www.sqlite.org/cintro.html). As bonus, the configuration tries [OSGeo4W distribution](http://trac.osgeo.org/osgeo4w/) 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](backends/sqlite3.html) 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 reference](backends/sqlite3.html) for details. Example: `-DSOCI_SQLITE3_TEST_CONNSTR="my.db"`
+
+#### Empty (sample backend)
+
+##### SOCI empty sample backend configuration
+
+* SOCI_EMPTY - boolean - Builds the [sample backend](backends.html) 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 processand 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
+
+
+For each backend and its test program, the `Makefile.basic`s 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.basic`s. 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.4.0.0`, `libsoci_sqlite3.so.4.0.0`, 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.
\ No newline at end of file
diff --git a/docs/interfaces.md b/docs/interfaces.md
new file mode 100644
index 0000000000..ebc56a9f4e
--- /dev/null
+++ b/docs/interfaces.md
@@ -0,0 +1,74 @@
+## 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.html#simpleclient) 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.
\ No newline at end of file
diff --git a/docs/languages/ada/concepts.md b/docs/languages/ada/concepts.md
new file mode 100644
index 0000000000..7a7c66abbb
--- /dev/null
+++ b/docs/languages/ada/concepts.md
@@ -0,0 +1,32 @@
+# 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.
\ No newline at end of file
diff --git a/docs/languages/ada/idioms.md b/docs/languages/ada/idioms.md
new file mode 100644
index 0000000000..034e6ab2eb
--- /dev/null
+++ b/docs/languages/ada/idioms.md
@@ -0,0 +1,268 @@
+# 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.
diff --git a/docs/languages/ada/index.md b/docs/languages/ada/index.md
new file mode 100644
index 0000000000..4fd7921b5b
--- /dev/null
+++ b/docs/languages/ada/index.md
@@ -0,0 +1,39 @@
+# SOCI-Ada Language Binding - documentation
+
+* [Introduction](#introduction)
+* [Compilation](#compilation)
+* [Concepts](concepts.html)
+* [Common Idioms](idioms.html)
+* [API Reference](reference.html)
+
+## 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:
+
+* Modular design based on dynamic backend loading. Thanks to this feature, new backends implemented within the context of the main SOCI project are immediately available for Ada programmers without any additional work. A large community of C++ users can help ensure that the new backends are well tested in a variety of environments and usage scenarios.
+* Native backends for major database servers ensure optimal performance and minimize configuration overhead and complexity that is usually associated with other database access methods.
+* Direct support for bulk operations allow to achieve high performance with queries that operate on large data sets.
+* Very liberal open-source license ([Boost, accepted by Open Source Initiative](http://www.opensource.org/licenses/bsl1.0.html)) that encourages both commercial and non-commercial use.
+* Easy to use and compact interface.
+
+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.
\ No newline at end of file
diff --git a/docs/languages/ada/reference.md b/docs/languages/ada/reference.md
new file mode 100644
index 0000000000..9650eb9921
--- /dev/null
+++ b/docs/languages/ada/reference.md
@@ -0,0 +1,523 @@
+# 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:
+
+* Oracle: * [http://soci.sourceforge.net/doc/backends/oracle.html](http://soci.sourceforge.net/doc/backends/oracle.html" target="_blank)
+* PostgreSQL: * [http://soci.sourceforge.net/doc/backends/postgresql.html](http://soci.sourceforge.net/doc/backends/postgresql.html" target="_blank)
+* MySQL: * [http://soci.sourceforge.net/doc/backends/mysql.html](http://soci.sourceforge.net/doc/backends/mysql.html" target="_blank)
+
+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 `Open`ed and `Close`d 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 `Session`s.
+---
+
+ --
+ -- 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.
+
+
+ -- 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.
+
+---
+
+---
+#####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.
\ No newline at end of file
diff --git a/docs/multithreading.md b/docs/multithreading.md
new file mode 100644
index 0000000000..41e147b066
--- /dev/null
+++ b/docs/multithreading.md
@@ -0,0 +1,38 @@
+## 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 `session`s 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](reference.html) for details.
\ No newline at end of file
diff --git a/docs/queries.md b/docs/queries.md
new file mode 100644
index 0000000000..d8d3efe71e
--- /dev/null
+++ b/docs/queries.md
@@ -0,0 +1,84 @@
+## 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> 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](boost.html) that allows to use `boost::optional` 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](http://www.boost.org/LICENSE_1_0.txt), 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 plainuncertainty) 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](http://www.boost.org/more/license_info.html) 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](http://soci.sourceforge.net/people.html) on the relevant SOCI page) to discuss any remaining concerns.
\ No newline at end of file
diff --git a/docs/reference.md b/docs/reference.md
new file mode 100644
index 0000000000..cc8d8e706e
--- /dev/null
+++ b/docs/reference.md
@@ -0,0 +1,704 @@
+## Client interface reference
+
+* [commonly used types](#commontypes)
+* [class session](#session)
+* [class connection_parameters](#parameters)
+* [class connection_pool](#pool)
+* [class transaction](#transaction)
+* [function into](#into)
+* [function use](#use)
+* [class statement](#statement)
+* [class procedure](#procedure)
+* [class type_conversion](#typeconversion)
+* [class row](#row)
+* [class column_properties](#columnproperties)
+* [class values](#values)
+* [class blob](#blob)
+* [class rowid](#rowid)
+* [class backend_factory](#backendfactory)
+* [Simple client interface](#simpleclient)
+
+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.
+
+### 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 *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"](beyond.html#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](basics.html) 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 entryin 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.
+
+
+### 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
+ IT into(T & t);
+
+ template
+ IT into(T & t, T1 p1);
+
+ template
+ IT into(T & t, indicator & ind);
+
+ template
+ IT into(T & t, indicator & ind, T1 p1);
+
+ template
+ IT into(T & t, std::vector & ind);
+
+Example:
+
+ int count;
+ sql << "select count(*) from person", into(count);
+
+See [Binding local dat](exchange.html#bind_local) 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
+ *IT* use(T & t);
+
+ template
+ *IT* use(T & t, T1 p1);
+
+ template
+ *IT* use(T & t, indicator & ind);
+
+ template
+ *IT* use(T & t, indicator & ind, T1 p1);
+
+ template
+ *IT* use(T & t, std::vector const & ind);
+
+ template
+ *IT* use(T & t, std::vector const & ind, T1 p1);
+
+
+Example:
+
+ int val = 7;
+ sql << "insert into numbers(val) values(:val)", use(val);
+
+See [Binding local data](exchange.html#bind_local) 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 bind_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.
+* `bind_clean_up` function for cleaning up any bound references. It allows to keep statement in cache and reuse it later with new references by calling `exchange` for each new bind variable.
+* `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](statements.html#preparation) for example uses.
+
+Most of the functions from the `statement` class interface are called automatically, but can be also used explicitly. See [Interfaces](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](statements.html#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
+ 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](exchange.html#custom_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
+ T get(std::size_t pos) const;
+
+ template
+ T get(std::size_t pos, T const & nullValue) const;
+
+ template
+ T get(std::string const & name) const;
+
+ template
+ T get(std::string const & name, T const & nullValue) const;
+
+ template
+ 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](exchange.html#dynamic) 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](exchange.html#dynamic) 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
+ T get(std::size_t pos) const;
+
+ template
+ T get(std::size_t pos, T const & nullValue) const;
+
+ template
+ T get(std::string const & name) const;
+
+ template
+ T get(std::string const & name, T const & nullValue) const;
+
+ template
+ values const & operator>>(T & value) const;
+
+ void skip(std::size_t num = 1) const;
+ void reset_get_counter() const;
+
+ template
+ void set(std::string const & name, T const & value, indicator indic = i_ok);
+
+ template
+ void set(const T & value, indicator indic = i_ok);
+
+ template
+ 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](exchange.html#object_relational) 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)](exchange.html#blob) 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 `.
+
+ 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 *blob_handle;
+ blob_handle soci_create_blob(session_handle s);
+ void soci_destroy_blob(blob_handle b);
+
+ int soci_blob_get_len(blob_handle b);
+ int soci_blob_read(blob_handle b, int offset, char *buf, int toRead);
+ int soci_blob_write(blob_handle b, int offset, char const *buf, int toWrite);
+ int soci_blob_append(blob_handle b, char const *buf, int toWrite);
+ int soci_blob_trim(blob_handle b, int newLen);
+
+ int soci_blob_state(blob_handle b);
+ char const * soci_blob_error_message(blob_handle b);
+
+The functions above provide the *blob* abstraction with the help of opaque handle. The `soci_blob_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.
+
+For easy error testing, functions `soci_blob_read`, `soci_blob_write`, `soci_blob_append`, and `soci_blob_trim` return `-1` in case of error and `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_blob`, which returns `NULL` if it was not possible to create an internal object representing the blob.
+
+
+ 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_blob (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.
+
+ 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);
+ blob_handle soci_get_into_blob (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_blob (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_blob (statement_handle st, char const * name, blob_handle blob);
+
+ 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);
+ blob_handle soci_get_use_blob (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.
+
diff --git a/docs/statements.md b/docs/statements.md
new file mode 100644
index 0000000000..cb4a9fb1dd
--- /dev/null
+++ b/docs/statements.md
@@ -0,0 +1,311 @@
+## Statements, procedures and transactions
+
+* [Statement preparation and repeated execution](#preparation)
+* [Rowset and iterator-based access](#rowset)
+* [Bulk operations](#bulk)
+* [Stored procedures](#procedures)
+* [Transactions](#transactions)
+* [Basic logging support](#logging)
+
+### 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 rs = (sql.prepare << "select values from numbers");
+
+ for (rowset::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](exchange.html#dynamic):
+
+
+ // person table has 4 columns
+
+ rowset rs = (sql.prepare << "select id, firstname, lastname, gender from person");
+
+ // iteration through the resultset:
+ for (rowset::const_iterator it = rs.begin(); it != rs.end(); ++it)
+ {
+ row const& row = *it;
+
+ // dynamic data extraction from each row:
+ cout << "Id: " << row.get(0) << '\n'
+ << "Name: " << row.get(1) << " " << row.get(2) << '\n'
+ << "Gender: " << row.get(3) << endl;
+ }
+
+`rowset_iterator` can be used with standard algorithms as well:
+
+
+ rowset rs = (sql.prepare << "select firstname from person");
+
+ std::copy(rs.begin(), rs.end(), std::ostream_iterator(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 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 valsOut(BATCH_SIZE);
+ statement st = (sql.prepare <<
+ "select value from numbers",
+ into(valsOut));
+ st.execute();
+ while (st.fetch())
+ {
+ std::vector::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.
+
+### Statement caching
+
+Some backends have some facilities to improve statement parsing and compilation to limit overhead when creating commonly used query. But for backends that does not support this kind optimization you can keep prepared statement and use it later with new references. To do such, prepare a statement as usual, you have to use `exchange` to bind new variables to statement object, then `execute` statement and finish by cleaning bound references with `bind_clean_up`.
+
+ sql << "CREATE TABLE test(a INTEGER)";
+
+ {
+ // prepare statement
+ soci::statement stmt = (db.prepare << "INSERT INTO numbers(value) VALUES(:val)");
+
+ {
+ // first insert
+ int a0 = 0;
+
+ // update reference
+ stmt.exchange(soci::use(a0));
+
+ stmt.define_and_bind();
+ stmt.execute(true);
+ stmt.bind_clean_up();
+ }
+
+ {
+ // come later, second insert
+ int a1 = 1;
+
+ // update reference
+ stmt.exchange(soci::use(a1));
+
+ stmt.define_and_bind();
+ stmt.execute(true);
+ stmt.bind_clean_up();
+ }
+ }
+
+ {
+ std::vector v(10);
+ db << "SELECT value FROM numbers", soci::into(v);
+ for (int i = 0; i < v.size(); ++i)
+ std::cout << "value " << i << ": " << v[i] << std::endl;
+ }
+
+
+#####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.
+
+### 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.
\ No newline at end of file
diff --git a/docs/structure.md b/docs/structure.md
new file mode 100644
index 0000000000..ee6e63f4ed
--- /dev/null
+++ b/docs/structure.md
@@ -0,0 +1,27 @@
+## Structure
+
+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](index.html) 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.
+---
\ No newline at end of file
diff --git a/include/private/README.md b/include/private/README.md
new file mode 100644
index 0000000000..7d46ec5872
--- /dev/null
+++ b/include/private/README.md
@@ -0,0 +1,5 @@
+# soci/include/private
+
+Private headers do not define any parts of public interface,
+are not installed in user's filesystem.
+Private headers only define common features used internally.
diff --git a/src/backends/firebird/common.h b/include/private/firebird/common.h
similarity index 72%
rename from src/backends/firebird/common.h
rename to include/private/firebird/common.h
index a97c3eeb12..636090724d 100644
--- a/src/backends/firebird/common.h
+++ b/include/private/firebird/common.h
@@ -8,7 +8,7 @@
#ifndef SOCI_FIREBIRD_COMMON_H_INCLUDED
#define SOCI_FIREBIRD_COMMON_H_INCLUDED
-#include "soci-firebird.h"
+#include "soci/firebird/soci-firebird.h"
#include
#include
#include
@@ -40,7 +40,7 @@ void setTextParam(char const * s, std::size_t size, char * buf_,
std::string getTextParam(XSQLVAR const *var);
template
-const char *str2dec(const char * s, IntType &out, int &scale)
+const char *str2dec(const char * s, IntType &out, short &scale)
{
int sign = 1;
if ('+' == *s)
@@ -65,7 +65,7 @@ const char *str2dec(const char * s, IntType &out, int &scale)
int d = *s - '0';
if (d < 0 || d > 9)
return s;
- res = res * 10 + d * sign;
+ res = res * 10 + static_cast(d * sign);
if (1 == sign)
{
if (res < out)
@@ -82,19 +82,45 @@ const char *str2dec(const char * s, IntType &out, int &scale)
return s;
}
+template
+inline
+T round_for_isc(T value)
+{
+ return value;
+}
+
+inline
+double round_for_isc(double value)
+{
+ // Unfortunately all the rounding functions are C99 and so are not supported
+ // by MSVC, so do it manually.
+ return value < 0 ? value - 0.5 : value + 0.5;
+}
+
+//helper template to generate proper code based on compile time type check
+template struct cond_to_isc {};
+template<> struct cond_to_isc
+{
+ static void checkInteger(short scale, short type)
+ {
+ if( scale >= 0 && (type == SQL_SHORT || type == SQL_LONG || type == SQL_INT64) )
+ throw soci_error("Can't convert non-integral value to integral column type");
+ }
+};
+template<> struct cond_to_isc
+{
+ static void checkInteger(short scale,short type) { SOCI_UNUSED(scale) SOCI_UNUSED(type) }
+};
+
template
-void to_isc(void * val, XSQLVAR * var, int x_scale = 0)
+void to_isc(void * val, XSQLVAR * var, short 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");
- }
+ cond_to_isc::is_integer>::checkInteger(scale,type);
for (int i = 0; i > scale; --i)
multiplier *= 10;
@@ -105,19 +131,19 @@ void to_isc(void * val, XSQLVAR * var, int x_scale = 0)
{
case SQL_SHORT:
{
- short tmp = static_cast(value*multiplier/divisor);
+ short tmp = static_cast(round_for_isc(value*multiplier)/divisor);
std::memcpy(var->sqldata, &tmp, sizeof(short));
}
break;
case SQL_LONG:
{
- int tmp = static_cast(value*multiplier/divisor);
+ int tmp = static_cast(round_for_isc(value*multiplier)/divisor);
std::memcpy(var->sqldata, &tmp, sizeof(int));
}
break;
case SQL_INT64:
{
- long long tmp = static_cast(value*multiplier/divisor);
+ long long tmp = static_cast(round_for_isc(value*multiplier)/divisor);
std::memcpy(var->sqldata, &tmp, sizeof(long long));
}
break;
@@ -141,7 +167,7 @@ void to_isc(void * val, XSQLVAR * var, int x_scale = 0)
template
void parse_decimal(void * val, XSQLVAR * var, const char * s)
{
- int scale;
+ short scale;
UIntType t1;
IntType t2;
if (!*str2dec(s, t1, scale))
@@ -174,6 +200,22 @@ std::string format_decimal(const void *sqldata, int sqlscale)
return r + std::string(sqlscale, '0');
}
+
+template struct cond_from_isc {};
+template<> struct cond_from_isc {
+ static void checkInteger(short scale)
+ {
+ std::ostringstream msg;
+ msg << "Can't convert value with scale " << -scale
+ << " to integral type";
+ throw soci_error(msg.str());
+ }
+};
+template<> struct cond_from_isc
+{
+ static void checkInteger(short scale) { SOCI_UNUSED(scale) }
+};
+
template
T1 from_isc(XSQLVAR * var)
{
@@ -182,14 +224,7 @@ T1 from_isc(XSQLVAR * var)
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());
- }
-
+ cond_from_isc::is_integer>::checkInteger(scale);
for (int i = 0; i > scale; --i)
{
tens *= 10;
diff --git a/src/backends/firebird/error-firebird.h b/include/private/firebird/error-firebird.h
similarity index 94%
rename from src/backends/firebird/error-firebird.h
rename to include/private/firebird/error-firebird.h
index 37ec3f5c58..b793d83a2e 100644
--- a/src/backends/firebird/error-firebird.h
+++ b/include/private/firebird/error-firebird.h
@@ -8,7 +8,7 @@
#ifndef SOCI_FIREBIRD_ERROR_H_INCLUDED
#define SOCI_FIREBIRD_ERROR_H_INCLUDED
-#include "soci-firebird.h"
+#include "soci/firebird/soci-firebird.h"
#include
namespace soci
diff --git a/include/private/soci-compiler.h b/include/private/soci-compiler.h
new file mode 100644
index 0000000000..42e52b5903
--- /dev/null
+++ b/include/private/soci-compiler.h
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2015 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_PRIVATE_SOCI_COMPILER_H_INCLUDED
+#define SOCI_PRIVATE_SOCI_COMPILER_H_INCLUDED
+
+#include "soci-cpp.h"
+
+// CHECK_GCC(major,minor) evaluates to 1 when using g++ of at least this
+// version or 0 when using g++ of lesser version or not using g++ at all.
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define CHECK_GCC(major, minor) \
+ ((__GNUC__ > (major)) \
+ || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
+#else
+# define CHECK_GCC(major, minor) 0
+#endif
+
+// GCC_WARNING_{SUPPRESS,RESTORE} macros can be used to bracket the code
+// producing a specific warning to disable it.
+//
+// They only work with g++ 4.6+ or clang, warnings are not disabled for earlier
+// g++ versions.
+#if defined(__clang__) || CHECK_GCC(4, 6)
+# define GCC_WARNING_SUPPRESS(x) \
+ _Pragma (SOCI_STRINGIZE(GCC diagnostic push)) \
+ _Pragma (SOCI_STRINGIZE(GCC diagnostic ignored SOCI_STRINGIZE(SOCI_CONCAT(-W,x))))
+# define GCC_WARNING_RESTORE(x) \
+ _Pragma (SOCI_STRINGIZE(GCC diagnostic pop))
+#else /* gcc < 4.6 or not gcc and not clang at all */
+# define GCC_WARNING_SUPPRESS(x)
+# define GCC_WARNING_RESTORE(x)
+#endif
+
+#endif // SOCI_PRIVATE_SOCI_COMPILER_H_INCLUDED
diff --git a/include/private/soci-cpp.h b/include/private/soci-cpp.h
new file mode 100644
index 0000000000..71121247a7
--- /dev/null
+++ b/include/private/soci-cpp.h
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2015 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_PRIVATE_SOCI_CPP_H_INCLUDED
+#define SOCI_PRIVATE_SOCI_CPP_H_INCLUDED
+
+// Some very common preprocessor helpers.
+
+// SOCI_CONCAT() pastes together two tokens after expanding them.
+#define SOCI_CONCAT_IMPL(x, y) x ## y
+#define SOCI_CONCAT(x, y) SOCI_CONCAT_IMPL(x, y)
+
+// SOCI_STRINGIZE() makes a string of its argument after expanding it.
+#define SOCI_STRINGIZE_IMPL(x) #x
+#define SOCI_STRINGIZE(x) SOCI_STRINGIZE_IMPL(x)
+
+// SOCI_MAKE_UNIQUE_NAME() creates a uniquely named identifier with the given
+// prefix.
+//
+// It uses __COUNTER__ macro to avoid problems with broken __LINE__ in MSVC
+// when using "Edit and Continue" (/ZI) option as there are no compilers known
+// to work with SOCI and not support it. If one such is ever discovered, we
+// should use __LINE__ for it instead.
+#define SOCI_MAKE_UNIQUE_NAME(name) SOCI_CONCAT(name, __COUNTER__)
+
+#endif // SOCI_PRIVATE_SOCI_CPP_H_INCLUDED
diff --git a/include/private/soci-cstrtod.h b/include/private/soci-cstrtod.h
new file mode 100644
index 0000000000..63b88f2baf
--- /dev/null
+++ b/include/private/soci-cstrtod.h
@@ -0,0 +1,80 @@
+//
+// Copyright (C) 2014 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_PRIVATE_SOCI_CSTRTOD_H_INCLUDED
+#define SOCI_PRIVATE_SOCI_CSTRTOD_H_INCLUDED
+
+#include "soci/error.h"
+
+#include
+#include
+
+namespace soci
+{
+
+namespace details
+{
+
+// Locale-independent, i.e. always using "C" locale, function for converting
+// strings to numbers.
+//
+// The string must contain a floating point number in "C" locale, i.e. using
+// point as decimal separator, and nothing but it. If it does, the converted
+// number is returned, otherwise an exception is thrown.
+inline
+double cstring_to_double(char const* s)
+{
+ // Unfortunately there is no clean way to parse a number in C locale
+ // without this hack: normally, using std::istringstream with classic
+ // locale should work, but some standard library implementations are buggy
+ // and handle non-default locale in thread-unsafe way, by changing the
+ // global C locale which is unacceptable as it introduces subtle bugs in
+ // multi-thread programs. So we rely on just the standard C functions and
+ // try to make them work by tweaking the input into the form appropriate
+ // for the current locale.
+
+ // First try with the original input.
+ char* end;
+ double d = strtod(s, &end);
+
+ bool parsedOK;
+ if (*end == '.')
+ {
+ // Parsing may have stopped because the current locale uses something
+ // different from the point as decimal separator, retry with a comma.
+ //
+ // In principle, values other than point or comma are possible but they
+ // don't seem to be used in practice, so for now keep things simple.
+ size_t const bufSize = strlen(s) + 1;
+ char* const buf = new char[bufSize];
+ strcpy(buf, s);
+ buf[end - s] = ',';
+ d = strtod(buf, &end);
+ parsedOK = end != buf && *end == '\0';
+ delete [] buf;
+ }
+ else
+ {
+ // Notice that we must detect false positives as well: parsing a string
+ // using decimal comma should fail when using this function.
+ parsedOK = end != s && *end == '\0' && !strchr(s, ',');
+ }
+
+ if (!parsedOK)
+ {
+ throw soci_error(std::string("Cannot convert data: string \"") + s + "\" "
+ "is not a number.");
+ }
+
+ return d;
+}
+
+} // namespace details
+
+} // namespace soci
+
+#endif // SOCI_PRIVATE_SOCI_CSTRTOD_H_INCLUDED
diff --git a/include/private/soci-dtocstr.h b/include/private/soci-dtocstr.h
new file mode 100644
index 0000000000..bcf9098f07
--- /dev/null
+++ b/include/private/soci-dtocstr.h
@@ -0,0 +1,58 @@
+//
+// Copyright (C) 2014 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_PRIVATE_SOCI_DTOCSTR_H_INCLUDED
+#define SOCI_PRIVATE_SOCI_DTOCSTR_H_INCLUDED
+
+#include "soci/soci-platform.h"
+#include "soci/error.h"
+
+#include
+#include
+
+namespace soci
+{
+
+namespace details
+{
+
+// Locale-independent, i.e. always using "C" locale, function for converting
+// floating point number to string.
+//
+// The resulting string will contain the floating point number in "C" locale,
+// i.e. will always use point as decimal separator independently of the current
+// locale.
+inline
+std::string double_to_cstring(double d)
+{
+ // See comments in cstring_to_double() in soci-cstrtod.h, we're dealing
+ // with the same issues here.
+
+ static size_t const bufSize = 32;
+ char buf[bufSize];
+ snprintf(buf, bufSize, "%.20g", d);
+
+ // Replace any commas which can be used as decimal separator with points.
+ for (char* p = buf; *p != '\0'; p++ )
+ {
+ if (*p == ',')
+ {
+ *p = '.';
+
+ // There can be at most one comma in this string anyhow.
+ break;
+ }
+ }
+
+ return buf;
+}
+
+} // namespace details
+
+} // namespace soci
+
+#endif // SOCI_PRIVATE_SOCI_DTOCSTR_H_INCLUDED
diff --git a/include/private/soci-exchange-cast.h b/include/private/soci-exchange-cast.h
new file mode 100644
index 0000000000..6b28c5bf4e
--- /dev/null
+++ b/include/private/soci-exchange-cast.h
@@ -0,0 +1,84 @@
+//
+// Copyright (C) 2015 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_EXCHANGE_CAST_H_INCLUDED
+#define SOCI_EXCHANGE_CAST_H_INCLUDED
+
+#include "soci/soci-backend.h"
+
+#include
+
+namespace soci
+{
+
+namespace details
+{
+
+// cast the given non-null untyped pointer to its corresponding type
+template struct exchange_type_traits;
+
+template <>
+struct exchange_type_traits
+{
+ typedef char value_type;
+};
+
+template <>
+struct exchange_type_traits
+{
+ typedef std::string value_type;
+};
+
+template <>
+struct exchange_type_traits
+{
+ typedef short value_type;
+};
+
+template <>
+struct exchange_type_traits
+{
+ typedef int value_type;
+};
+
+template <>
+struct exchange_type_traits
+{
+ typedef long long value_type;
+};
+
+template <>
+struct exchange_type_traits
+{
+ typedef unsigned long long value_type;
+};
+
+template <>
+struct exchange_type_traits
+{
+ typedef double value_type;
+};
+
+template <>
+struct exchange_type_traits
+{
+ typedef std::tm value_type;
+};
+
+// exchange_type_traits not defined for x_statement, x_rowid and x_blob here.
+
+template
+typename exchange_type_traits::value_type& exchange_type_cast(void *data)
+{
+ return *static_cast::value_type*>(data);
+}
+
+} // namespace details
+
+} // namespace soci
+
+#endif // SOCI_EXCHANGE_CAST_H_INCLUDED
diff --git a/include/private/soci-mktime.h b/include/private/soci-mktime.h
new file mode 100644
index 0000000000..1b383d8389
--- /dev/null
+++ b/include/private/soci-mktime.h
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2015 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_PRIVATE_SOCI_MKTIME_H_INCLUDED
+#define SOCI_PRIVATE_SOCI_MKTIME_H_INCLUDED
+
+// Not because we also want to get timegm() if available.
+#include
+
+namespace soci
+{
+
+namespace details
+{
+
+// Fill the provided struct tm with the values corresponding to the given date
+// in UTC.
+//
+// Notice that both years and months are normal human 1-based values here and
+// not 1900 or 0-based as in struct tm itself.
+inline
+void
+mktime_from_ymdhms(tm& t,
+ int year, int month, int day,
+ int hour, int minute, int second)
+{
+ 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;
+
+ mktime(&t);
+}
+
+} // namespace details
+
+} // namespace soci
+
+#endif // SOCI_PRIVATE_SOCI_MKTIME_H_INCLUDED
diff --git a/include/private/soci-static-assert.h b/include/private/soci-static-assert.h
new file mode 100644
index 0000000000..ecb79b2acd
--- /dev/null
+++ b/include/private/soci-static-assert.h
@@ -0,0 +1,19 @@
+//
+// Copyright (C) 2015 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_PRIVATE_STATIC_ASSERT_H_INCLUDED
+#define SOCI_PRIVATE_STATIC_ASSERT_H_INCLUDED
+
+#include "soci-cpp.h"
+
+// This is a simple approximation for C++11 static_assert: generate a
+// compile-time error if the given expression evaluates to 0 and make the
+// identifier (not string!) msg appear in the error message.
+#define SOCI_STATIC_ASSERT(expr) \
+ struct SOCI_MAKE_UNIQUE_NAME(SociAssert) { unsigned msg: expr; }
+
+#endif // SOCI_PRIVATE_STATIC_ASSERT_H_INCLUDED
diff --git a/src/core/backend-loader.h b/include/soci/backend-loader.h
similarity index 97%
rename from src/core/backend-loader.h
rename to include/soci/backend-loader.h
index e4453abc63..f7dc6fa78c 100644
--- a/src/core/backend-loader.h
+++ b/include/soci/backend-loader.h
@@ -8,7 +8,7 @@
#ifndef SOCI_BACKEND_LOADER_H_INCLUDED
#define SOCI_BACKEND_LOADER_H_INCLUDED
-#include "soci-backend.h"
+#include "soci/soci-backend.h"
// std
#include
#include
diff --git a/include/soci/bind-values.h b/include/soci/bind-values.h
new file mode 100644
index 0000000000..3945636b3c
--- /dev/null
+++ b/include/soci/bind-values.h
@@ -0,0 +1,196 @@
+#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;
+ private:
+ SOCI_NOT_COPYABLE(use_sequence)
+ };
+
+ 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;
+ private:
+ SOCI_NOT_COPYABLE(use_sequence)
+ };
+
+ 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;
+ private:
+ SOCI_NOT_COPYABLE(into_sequence)
+ };
+
+ 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;
+ private:
+ SOCI_NOT_COPYABLE(into_sequence)
+ };
+
+ 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
diff --git a/src/core/blob-exchange.h b/include/soci/blob-exchange.h
similarity index 93%
rename from src/core/blob-exchange.h
rename to include/soci/blob-exchange.h
index 03f2258ba0..a9e8679bc0 100644
--- a/src/core/blob-exchange.h
+++ b/include/soci/blob-exchange.h
@@ -8,9 +8,9 @@
#ifndef SOCI_BLOB_EXCHANGE_H_INCLUDED
#define SOCI_BLOB_EXCHANGE_H_INCLUDED
-#include "blob.h"
-#include "into-type.h"
-#include "use-type.h"
+#include "soci/blob.h"
+#include "soci/into-type.h"
+#include "soci/use-type.h"
// std
#include
@@ -49,6 +49,7 @@ template <>
struct exchange_traits
{
typedef basic_type_tag type_family;
+ enum { x_type = x_blob };
};
} // namespace details
diff --git a/src/core/blob.h b/include/soci/blob.h
similarity index 96%
rename from src/core/blob.h
rename to include/soci/blob.h
index 16159ff6ad..50ac0692a1 100644
--- a/src/core/blob.h
+++ b/include/soci/blob.h
@@ -8,7 +8,7 @@
#ifndef SOCI_BLOB_H_INCLUDED
#define SOCI_BLOB_H_INCLUDED
-#include "soci-config.h"
+#include "soci/soci-platform.h"
// std
#include
diff --git a/include/soci/boost-fusion.h b/include/soci/boost-fusion.h
new file mode 100644
index 0000000000..f235b18431
--- /dev/null
+++ b/include/soci/boost-fusion.h
@@ -0,0 +1,28 @@
+//
+// 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
diff --git a/src/core/boost-gregorian-date.h b/include/soci/boost-gregorian-date.h
similarity index 96%
rename from src/core/boost-gregorian-date.h
rename to include/soci/boost-gregorian-date.h
index cfa3c81d23..66321c5291 100644
--- a/src/core/boost-gregorian-date.h
+++ b/include/soci/boost-gregorian-date.h
@@ -8,7 +8,7 @@
#ifndef SOCI_BOOST_GREGORIAN_DATE_H_INCLUDED
#define SOCI_BOOST_GREGORIAN_DATE_H_INCLUDED
-#include "type-conversion-traits.h"
+#include "soci/type-conversion-traits.h"
// boost
#include
#include
diff --git a/src/core/boost-optional.h b/include/soci/boost-optional.h
similarity index 78%
rename from src/core/boost-optional.h
rename to include/soci/boost-optional.h
index 2f6699a35e..9e42611f4c 100644
--- a/src/core/boost-optional.h
+++ b/include/soci/boost-optional.h
@@ -8,13 +8,19 @@
#ifndef SOCI_BOOST_OPTIONAL_H_INCLUDED
#define SOCI_BOOST_OPTIONAL_H_INCLUDED
-#include "type-conversion-traits.h"
+#include "soci/type-conversion-traits.h"
// boost
#include
namespace soci
{
+// tmp is uninitialized
+#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ > 6)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
// simple fall-back for boost::optional
template
struct type_conversion >
@@ -52,4 +58,8 @@ struct type_conversion >
} // namespace soci
+#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ > 6)
+#pragma GCC diagnostic pop
+#endif
+
#endif // SOCI_BOOST_OPTIONAL_H_INCLUDED
diff --git a/include/soci/boost-tuple.h b/include/soci/boost-tuple.h
new file mode 100644
index 0000000000..37547367b4
--- /dev/null
+++ b/include/soci/boost-tuple.h
@@ -0,0 +1,18 @@
+//
+// 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
diff --git a/src/core/connection-parameters.h b/include/soci/connection-parameters.h
similarity index 95%
rename from src/core/connection-parameters.h
rename to include/soci/connection-parameters.h
index 86483a33a2..ba0eef936d 100644
--- a/src/core/connection-parameters.h
+++ b/include/soci/connection-parameters.h
@@ -8,7 +8,7 @@
#ifndef SOCI_CONNECTION_PARAMETERS_H_INCLUDED
#define SOCI_CONNECTION_PARAMETERS_H_INCLUDED
-#include "soci-config.h"
+#include "soci/soci-platform.h"
#include