Update soci

This commit is contained in:
Brad Chase
2017-12-02 13:44:06 -05:00
239 changed files with 16094 additions and 7461 deletions

View File

@@ -0,0 +1,59 @@
version: 2
jobs:
lint:
docker:
- image: circleci/ruby:2.4.1-node
steps:
- checkout
- run:
name: install markdownlint
command: |
sudo npm install -g markdownlint-cli
markdownlint --version
- run:
name: lint README.md
command: markdownlint --config .markdownlint.json README.md
- run:
name: lint docs/
command: markdownlint --config .markdownlint.json docs/
build-deploy:
docker:
- image: circleci/python:2.7
steps:
- checkout
- run:
name: install mkdocs
command: sudo pip install mkdocs
- run:
name: generate docs
command: mkdocs build --clean
- run:
name: install lftp
command: |
sudo apt-get update -q
sudo apt-get install -y lftp
- run:
name: deploy docs
command: lftp sftp://${DEPLOY_DOCS_USER}:${DEPLOY_DOCS_PASS}@${DEPLOY_DOCS_HOST} -e "set ftp:ssl-force true; set ftp:ssl-protect-data true; set ssl:verify-certificate no; set sftp:auto-confirm yes; mirror -v -R ./site ${DEPLOY_DOCS_BASE}/doc/${CIRCLE_BRANCH}; quit"
workflows:
version: 2
docs-workflow:
jobs:
- lint:
filters:
branches:
only:
- master
- /release*/
- build-deploy:
requires:
- lint
filters:
branches:
only:
- master
- /release*/
notify:
webhooks:
- url: https://webhooks.gitter.im/e/9ff4be3a6f08f55106e2

32
src/soci/.editorconfig Normal file
View File

@@ -0,0 +1,32 @@
# This is the EditorConfig (http://editorconfig.org/) coding style file for SOCI.
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
# CMake configuration files
[{CMakeLists.txt,*.cmake}]
indent_size = 2
indent_style = space
trim_trailing_whitespace = true
insert_final_newline = true
# CI configuration files
[{.travis.yml,appveyor.yml,Vagrantfile}]
indent_size = 2
indent_style = space
trim_trailing_whitespace = true
insert_final_newline = true
# Windows shell scripts
[*.{cmd,bat,ps1}]
end_of_line = crlf
indent_size = 4
indent_style = space
insert_final_newline = false
trim_trailing_whitespace = true

View File

@@ -1,6 +1,14 @@
# Auto detect text files and perform LF normalization
* text=auto
*.bash eol=lf
*.env eol=lf
*.sh eol=lf
*.cmd eol=crlf
*.bat eol=crlf
*.BAT eol=crlf
*.CMD eol=crlf
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union

13
src/soci/.gitignore vendored
View File

@@ -5,13 +5,14 @@ tags
tmp
# Build directories
_build*
src/_build*
src/build
/*build*
/*site*
# Files generated by CMake
Makefile
src/core/soci_backends_config.h
tests/odbc/test-access.dsn
tests/odbc/test-mysql.dsn
# ... and the rest of CMake spam
CMakeFiles/
@@ -19,10 +20,11 @@ CMakeCache.txt
CTestTestfile.cmake
cmake_install.cmake
# Visual Studio
# Visual Studio / Visual Studio Code
*.opensdf
*.sdf
*.suo
/*.vs*
# KDevelop
*.kate-swp
@@ -37,3 +39,6 @@ CMakeLists.txt.user
# Eclipse
/.project
# Vagrant
/.vagrant/

View File

@@ -0,0 +1,7 @@
{
"default": true,
"MD013": false,
"MD026": false,
"MD024": false,
"MD029": {"style": "ordered"}
}

View File

@@ -3,8 +3,12 @@
#
# Copyright (c) 2013 Mateusz Loskot <mateusz@loskot.net>
#
# TODO: Switch to Trusty https://github.com/SOCI/soci/issues/574
dist: precise
language: cpp
sudo: required
compiler:
- g++
#- clang
@@ -14,32 +18,43 @@ services:
- postgresql
env:
- 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
global:
- secure: "I7/28jg7R24y64426d5XsfILrd/VW0BdwFbNpEgBfW1qNk9GpkNGTvp/ET6hKwBVrW5jmN9QdEviGcPpQRIAlMj6g9GvZeAUxM+VZTcXD2u30REUPPxNTJMRVHPfL9DA7EMFCST8SjBCgMdTHFwqLV4vSQEF4NTXbntley/IPfM="
matrix:
- SOCI_TRAVIS_BACKEND=db2
- SOCI_TRAVIS_BACKEND=empty
- SOCI_TRAVIS_BACKEND=firebird
- SOCI_TRAVIS_BACKEND=mysql
- SOCI_TRAVIS_BACKEND=odbc
- SOCI_TRAVIS_BACKEND=postgresql
- SOCI_TRAVIS_BACKEND=sqlite3
- SOCI_TRAVIS_BACKEND=valgrind
- SOCI_TRAVIS_BACKEND=oracle WITH_BOOST=OFF
matrix:
fast_finish: true
allow_failures:
- env: SOCI_TRAVIS_BACKEND=postgression
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- kalakris-cmake
packages:
- cmake
coverity_scan:
project:
name: "SOCI/soci"
notification_email: soci-devel@lists.sourceforge.net
build_command_prepend: "mkdir build.cov; cd build.cov; cmake .."
build_command: "make -j 4"
branch_pattern: coverity_scan
before_install: ./bin/ci/before_install.sh
before_script: ./bin/ci/before_script.sh
script: ./bin/ci/script.sh
before_install: ./scripts/travis/before_install.sh
before_script: ./scripts/travis/before_script.sh
script: ./scripts/travis/script.sh
notifications:
email:
recipients:
- soci-devel@lists.sourceforge.net
on_success: change # [always|never|change] # default: change
on_failure: always # [always|never|change] # default: always
webhooks:
urls:
- https://webhooks.gitter.im/e/000781732a3b1637ef82
on_start: always
irc:
channels:
- "irc.freenode.org#soci"

456
src/soci/CHANGELOG.md Normal file
View File

@@ -0,0 +1,456 @@
# Change Log
## [Unreleased](https://github.com/SOCI/soci/tree/HEAD)
[Full Changelog](https://github.com/SOCI/soci/compare/3.2.3...HEAD)
**Closed issues:**
- Exception while selecting null values with indicators [\#581](https://github.com/SOCI/soci/issues/581)
- Null value fetched and no indicator defined [\#580](https://github.com/SOCI/soci/issues/580)
- sequence support MySQL and PostgreSQL [\#569](https://github.com/SOCI/soci/issues/569)
- Implement session::get\_table\_names\(\) for sqlite3 [\#563](https://github.com/SOCI/soci/issues/563)
- Make Oracle work again on Travis CI [\#554](https://github.com/SOCI/soci/issues/554)
- Split AppVeyor jobs per backend [\#550](https://github.com/SOCI/soci/issues/550)
- how to build soci with postgresql? [\#543](https://github.com/SOCI/soci/issues/543)
- How can I install SOCI on HP UX? [\#538](https://github.com/SOCI/soci/issues/538)
- Error C2065 'x\_type': undeclared identifier [\#531](https://github.com/SOCI/soci/issues/531)
- Unable to catch sqlite3\_soci\_error, program aborts [\#529](https://github.com/SOCI/soci/issues/529)
- unresolved external symbol sqlite3\_soci\_error::result when linking soci\_sqlite3\_test.exe on VS2015 U3 [\#528](https://github.com/SOCI/soci/issues/528)
- How to use rowset with Core interface [\#527](https://github.com/SOCI/soci/issues/527)
- can std::string of soci hold the right utf8 data? [\#525](https://github.com/SOCI/soci/issues/525)
- \[Q\] Store query in unsorted\_map [\#522](https://github.com/SOCI/soci/issues/522)
- use vector for `in` [\#520](https://github.com/SOCI/soci/issues/520)
- Deadlock found when trying to get lock; try restarting transaction [\#518](https://github.com/SOCI/soci/issues/518)
- Link issue with master [\#513](https://github.com/SOCI/soci/issues/513)
- Uninitialised type in oracle\_statement\_backend::describe\_column [\#511](https://github.com/SOCI/soci/issues/511)
- unfortunate placement of soci headers with common names [\#505](https://github.com/SOCI/soci/issues/505)
- SOCI\_STATIC and plugins [\#497](https://github.com/SOCI/soci/issues/497)
- Illegal memory access on Windows [\#488](https://github.com/SOCI/soci/issues/488)
- into/use\_container\<T\> is causing troubles [\#485](https://github.com/SOCI/soci/issues/485)
- Provide CMake package configuration file [\#481](https://github.com/SOCI/soci/issues/481)
- delete already deleted pimpl if connection\_pool is assigned [\#478](https://github.com/SOCI/soci/issues/478)
- Is there any roadmap to support vertica ? [\#477](https://github.com/SOCI/soci/issues/477)
- Handle OCI\_SUCCESS\_WITH\_INFO [\#473](https://github.com/SOCI/soci/issues/473)
- Coverity not fully configured [\#472](https://github.com/SOCI/soci/issues/472)
- soci 3.2.3 build on windows is not complete [\#468](https://github.com/SOCI/soci/issues/468)
- Char \* not supported in use/into. Documentation states otherwise. [\#466](https://github.com/SOCI/soci/issues/466)
- VS2015 Exceptions =\> abort\(\) [\#465](https://github.com/SOCI/soci/issues/465)
- Error classification [\#464](https://github.com/SOCI/soci/issues/464)
- Oracle wallet authentication [\#463](https://github.com/SOCI/soci/issues/463)
- get the result in a c++ code of stored procedure after a call [\#460](https://github.com/SOCI/soci/issues/460)
- NLS supports for connection params in Oracle [\#458](https://github.com/SOCI/soci/issues/458)
- AppVeyor can not find sh.exe? [\#447](https://github.com/SOCI/soci/issues/447)
- async query call [\#445](https://github.com/SOCI/soci/issues/445)
- Does this library to work with firebird events? [\#442](https://github.com/SOCI/soci/issues/442)
- SOCI doesn't define SOCI\_HAVE\_CXX\_C11 for VS2015 [\#441](https://github.com/SOCI/soci/issues/441)
- ...is not a member of 'sqlite\_api' [\#440](https://github.com/SOCI/soci/issues/440)
- Compile errors [\#439](https://github.com/SOCI/soci/issues/439)
- C++11 \#define should be in soci-config.hpp defined [\#437](https://github.com/SOCI/soci/issues/437)
- Fix discrepency between SOCI\_USE\_BOOST and HAVE\_BOOST [\#433](https://github.com/SOCI/soci/issues/433)
- Add Vagrant configuration for easy development [\#432](https://github.com/SOCI/soci/issues/432)
- DB2 statement execute error handling is ambiguous [\#431](https://github.com/SOCI/soci/issues/431)
- Issue using boost::tuple integration after upgrading from soci 3.2.2 to 3.2.3 [\#429](https://github.com/SOCI/soci/issues/429)
- conversion\_use\_type misses members initialization [\#412](https://github.com/SOCI/soci/issues/412)
- AppVeyor: ODBC tests are failed [\#407](https://github.com/SOCI/soci/issues/407)
- Can't run SOCI tests under Windows using ODBC data source [\#396](https://github.com/SOCI/soci/issues/396)
- Problems building SOCI under windows [\#384](https://github.com/SOCI/soci/issues/384)
- std::strings in nvarchar\(max\) is still a problem [\#383](https://github.com/SOCI/soci/issues/383)
- Build VS2015 Win10 Errors [\#379](https://github.com/SOCI/soci/issues/379)
- soci-3.2.3/backends/mysql/session.cpp:202: bad if test ? [\#377](https://github.com/SOCI/soci/issues/377)
- Clang warnings preventing compilation [\#374](https://github.com/SOCI/soci/issues/374)
- Boost 1.58.0 fails static assertion when streaming optional w/o optional\_io header [\#370](https://github.com/SOCI/soci/issues/370)
- Building of very first file fails with mingw [\#369](https://github.com/SOCI/soci/issues/369)
- How to pass dynamic multiple variables to query [\#354](https://github.com/SOCI/soci/issues/354)
- Rename SOCI headers [\#342](https://github.com/SOCI/soci/issues/342)
- OSX: struct session conflicting with unqualified soci::session [\#340](https://github.com/SOCI/soci/issues/340)
- Remove old build .tcl scripts [\#339](https://github.com/SOCI/soci/issues/339)
- Building errors with mingw, linking and undef. reference [\#338](https://github.com/SOCI/soci/issues/338)
- Missing static ODBC object file in installation script [\#337](https://github.com/SOCI/soci/issues/337)
- Mac OS: master branch fails to build on Yosemite [\#334](https://github.com/SOCI/soci/issues/334)
- Port: Allow SOCI\_LIBDIR to be set on the command line for easier packaging. \#195 [\#311](https://github.com/SOCI/soci/issues/311)
- Port: Add WITH\_CXX11 configuration flag \(currently for gcc and clang\) \#203 [\#310](https://github.com/SOCI/soci/issues/310)
- Incorrect time zone in struct tm returned from SOCI [\#308](https://github.com/SOCI/soci/issues/308)
- Drop GitFlow branching model [\#305](https://github.com/SOCI/soci/issues/305)
- Merge master 3.2.3 into develop [\#303](https://github.com/SOCI/soci/issues/303)
- Get rid of asserts in the code [\#300](https://github.com/SOCI/soci/issues/300)
- Set up a test database for Oracle Travis CI build. [\#290](https://github.com/SOCI/soci/issues/290)
- Big std::strings in nvarchar\(max\)s via ODBC fails with HY104 [\#287](https://github.com/SOCI/soci/issues/287)
- BUG problem on the second iteration in a rowset [\#280](https://github.com/SOCI/soci/issues/280)
- ODBC stored procedure [\#275](https://github.com/SOCI/soci/issues/275)
- Build and compile soci odbc failed [\#274](https://github.com/SOCI/soci/issues/274)
- Add MinGW build to Travis CI [\#247](https://github.com/SOCI/soci/issues/247)
- Fix warnings in MySQL backend compilation [\#244](https://github.com/SOCI/soci/issues/244)
- \[fix\] Remove -ansi when building on FreeBSD 10 [\#236](https://github.com/SOCI/soci/issues/236)
- Clean up terse or misspelled exception messages in ODBC backend [\#231](https://github.com/SOCI/soci/issues/231)
- odbc\_soci\_error should append sqlstate\_, sqlcode\_ and message\_ to the string used to initialize soci\_error [\#228](https://github.com/SOCI/soci/issues/228)
- Install Oracle on Travis CI server [\#224](https://github.com/SOCI/soci/issues/224)
- ODBC string bulk insertions are adding an escape char at the end of each string [\#202](https://github.com/SOCI/soci/issues/202)
- soci test projects for MSVC using cmake end up with wrong include path and linker error [\#177](https://github.com/SOCI/soci/issues/177)
- \#include "soci-backend.h" in sqlite3/soci-sqlite3.h [\#169](https://github.com/SOCI/soci/issues/169)
- double free [\#142](https://github.com/SOCI/soci/issues/142)
- Allow unknown toolsets in SociConfig.cmake [\#104](https://github.com/SOCI/soci/issues/104)
- Includes are wrong with make-install on Linux Mint [\#101](https://github.com/SOCI/soci/issues/101)
- Throw if truncation happens but no indicators was provided [\#51](https://github.com/SOCI/soci/issues/51)
- MySQL IEEE floating point representation [\#22](https://github.com/SOCI/soci/issues/22)
**Merged pull requests:**
- Repair VC8 compile of test applications [\#593](https://github.com/SOCI/soci/pull/593) ([hrabe](https://github.com/hrabe))
- Replace C alternative boolean operator representations with primary [\#592](https://github.com/SOCI/soci/pull/592) ([mloskot](https://github.com/mloskot))
- \[cmake\] Update FindPostgreSQL.cmake from CMake 3.9 [\#590](https://github.com/SOCI/soci/pull/590) ([mloskot](https://github.com/mloskot))
- \[AppVeyor\] Add build job with Visual Studio 2017 [\#588](https://github.com/SOCI/soci/pull/588) ([mloskot](https://github.com/mloskot))
- More XML/CLOB-related changes, including ODBC "support" [\#586](https://github.com/SOCI/soci/pull/586) ([vadz](https://github.com/vadz))
- Enable Oracle builds for pull requests [\#585](https://github.com/SOCI/soci/pull/585) ([mloskot](https://github.com/mloskot))
- Fix bug with null strings in bulk selections in ODBC and DB2 [\#583](https://github.com/SOCI/soci/pull/583) ([vadz](https://github.com/vadz))
- Oracle fix empty string as null handling in the test [\#582](https://github.com/SOCI/soci/pull/582) ([vadz](https://github.com/vadz))
- Restore Oracle build job on Travis CI [\#579](https://github.com/SOCI/soci/pull/579) ([mloskot](https://github.com/mloskot))
- Add CLOB and XML support to Firebird backend [\#578](https://github.com/SOCI/soci/pull/578) ([vadz](https://github.com/vadz))
- Move directory /bin to /scripts [\#577](https://github.com/SOCI/soci/pull/577) ([mloskot](https://github.com/mloskot))
- Add support for EditorConfig [\#576](https://github.com/SOCI/soci/pull/576) ([alexott](https://github.com/alexott))
- fix some of warnings from fresh Coverity report [\#572](https://github.com/SOCI/soci/pull/572) ([alexott](https://github.com/alexott))
- Sanitizer fix & cmake support for build in superprojects [\#570](https://github.com/SOCI/soci/pull/570) ([mcencora](https://github.com/mcencora))
- Update structure of SOCI 4.0.0 documentation [\#566](https://github.com/SOCI/soci/pull/566) ([mloskot](https://github.com/mloskot))
- Some fix for SQLite3 backend [\#564](https://github.com/SOCI/soci/pull/564) ([Arenoros](https://github.com/Arenoros))
- Fix handling of strings in ODBC backend bulk operations [\#561](https://github.com/SOCI/soci/pull/561) ([vadz](https://github.com/vadz))
- Refactor code for parsing date/time to avoid duplication [\#559](https://github.com/SOCI/soci/pull/559) ([vadz](https://github.com/vadz))
- Lazy initialization of the temporary LOB objects for Oracle. [\#557](https://github.com/SOCI/soci/pull/557) ([msobczak](https://github.com/msobczak))
- Fix check for clang in CMake configuration [\#556](https://github.com/SOCI/soci/pull/556) ([vadz](https://github.com/vadz))
- Work around MySQL ODBC driver bug [\#555](https://github.com/SOCI/soci/pull/555) ([vadz](https://github.com/vadz))
- Consistently check for connection in the session object methods [\#548](https://github.com/SOCI/soci/pull/548) ([vadz](https://github.com/vadz))
- Use defaults for unsupported types in ODBC backend [\#545](https://github.com/SOCI/soci/pull/545) ([snikulov](https://github.com/snikulov))
- moved to latest Catch UT Framework [\#544](https://github.com/SOCI/soci/pull/544) ([snikulov](https://github.com/snikulov))
- disable autosetting of SOCI\_CXX\_C11 to OFF [\#541](https://github.com/SOCI/soci/pull/541) ([ckaminski](https://github.com/ckaminski))
- Pull request for issues 511 and 473 [\#536](https://github.com/SOCI/soci/pull/536) ([ddowling](https://github.com/ddowling))
- Fixing uninitialized gotData\_ [\#535](https://github.com/SOCI/soci/pull/535) ([csteifel](https://github.com/csteifel))
- Corrections in README.md [\#534](https://github.com/SOCI/soci/pull/534) ([mutcher](https://github.com/mutcher))
- Firebird blob bug [\#524](https://github.com/SOCI/soci/pull/524) ([ravselj](https://github.com/ravselj))
- Add JSON support to the MySQL backend [\#517](https://github.com/SOCI/soci/pull/517) ([ayllon](https://github.com/ayllon))
- Add missing declspec to properly export exception classes [\#510](https://github.com/SOCI/soci/pull/510) ([mloskot](https://github.com/mloskot))
- Added bigstring \(XML and CLOB\) support. [\#509](https://github.com/SOCI/soci/pull/509) ([msobczak](https://github.com/msobczak))
- Added uniform offset for BLOB read/write operations. [\#508](https://github.com/SOCI/soci/pull/508) ([msobczak](https://github.com/msobczak))
- export cmake package [\#503](https://github.com/SOCI/soci/pull/503) ([wisk](https://github.com/wisk))
- Fix travis-ci build [\#494](https://github.com/SOCI/soci/pull/494) ([snikulov](https://github.com/snikulov))
- Fixed \#468 [\#493](https://github.com/SOCI/soci/pull/493) ([snikulov](https://github.com/snikulov))
- Fixed driver name and passwd for PostgreSQL ODBC driver on AppVeyor [\#492](https://github.com/SOCI/soci/pull/492) ([snikulov](https://github.com/snikulov))
- Fixed MinGW build with proper URL on AppVeyor [\#491](https://github.com/SOCI/soci/pull/491) ([snikulov](https://github.com/snikulov))
- MSSQL ODBC // fixed \#383 - long lines insert/select [\#489](https://github.com/SOCI/soci/pull/489) ([snikulov](https://github.com/snikulov))
- Bulk iterators [\#487](https://github.com/SOCI/soci/pull/487) ([msobczak](https://github.com/msobczak))
- Added failover callback for Oracle and PostgreSQL. [\#486](https://github.com/SOCI/soci/pull/486) ([msobczak](https://github.com/msobczak))
- Added support for portable DDL statements. [\#484](https://github.com/SOCI/soci/pull/484) ([msobczak](https://github.com/msobczak))
- Added singlerows mode for PostgreSQL. [\#482](https://github.com/SOCI/soci/pull/482) ([msobczak](https://github.com/msobczak))
- Portable metadata queries. [\#480](https://github.com/SOCI/soci/pull/480) ([msobczak](https://github.com/msobczak))
- fixed \#478 [\#479](https://github.com/SOCI/soci/pull/479) ([snikulov](https://github.com/snikulov))
- coverity // Fixed uninited local std::tm structs [\#475](https://github.com/SOCI/soci/pull/475) ([snikulov](https://github.com/snikulov))
- Adding example of a oracle connection to a remote server without need of tnsnames.ora [\#474](https://github.com/SOCI/soci/pull/474) ([wdavilaneto](https://github.com/wdavilaneto))
- Travis-CI: allowed failure for DB2 backend [\#471](https://github.com/SOCI/soci/pull/471) ([snikulov](https://github.com/snikulov))
- Appveyour now using MySQL 5.7 [\#470](https://github.com/SOCI/soci/pull/470) ([snikulov](https://github.com/snikulov))
- Documentation. exchange.md cleaned from typos [\#459](https://github.com/SOCI/soci/pull/459) ([shelomentsevd](https://github.com/shelomentsevd))
- compilation fix for msvc2012 [\#455](https://github.com/SOCI/soci/pull/455) ([snikulov](https://github.com/snikulov))
- added Address Sanitizer to expose memory errors [\#454](https://github.com/SOCI/soci/pull/454) ([snikulov](https://github.com/snikulov))
- updated catch.hpp version to 1.3.3 [\#453](https://github.com/SOCI/soci/pull/453) ([snikulov](https://github.com/snikulov))
- Define cxx\_details::auto\_ptr\<\> to get rid of preprocessor checks [\#452](https://github.com/SOCI/soci/pull/452) ([vadz](https://github.com/vadz))
- Include soci/soci-platform.h instead of soci-config.h [\#451](https://github.com/SOCI/soci/pull/451) ([vadz](https://github.com/vadz))
- Avoid recursive inclusion between soci-{config,platform}.h [\#450](https://github.com/SOCI/soci/pull/450) ([vadz](https://github.com/vadz))
- fixed \#447 [\#449](https://github.com/SOCI/soci/pull/449) ([snikulov](https://github.com/snikulov))
- Handle MSVS 2015 \(and 2013, to some extent\) as C++11 compiler [\#448](https://github.com/SOCI/soci/pull/448) ([vadz](https://github.com/vadz))
- CMake read version from version.h [\#446](https://github.com/SOCI/soci/pull/446) ([ArnaudD-FR](https://github.com/ArnaudD-FR))
- postgres library built as static would not install unless also buildi… [\#443](https://github.com/SOCI/soci/pull/443) ([julien-lecomte](https://github.com/julien-lecomte))
- DB2: Switch session from SQLConnect ot SQLDriverConnect [\#438](https://github.com/SOCI/soci/pull/438) ([mloskot](https://github.com/mloskot))
- CMake generates soci/version.h [\#436](https://github.com/SOCI/soci/pull/436) ([ArnaudD-FR](https://github.com/ArnaudD-FR))
- Specify definitions in soci-config.h [\#435](https://github.com/SOCI/soci/pull/435) ([ArnaudD-FR](https://github.com/ArnaudD-FR))
- Add Vagrant configuration [\#434](https://github.com/SOCI/soci/pull/434) ([mloskot](https://github.com/mloskot))
- \[SQLITE3\] Add reset API to reset sqlite3 statement [\#430](https://github.com/SOCI/soci/pull/430) ([ArnaudD-FR](https://github.com/ArnaudD-FR))
- reset count of affected rows \(sqlite3\) [\#428](https://github.com/SOCI/soci/pull/428) ([MonsieurNicolas](https://github.com/MonsieurNicolas))
- Fixed Coverity issues for SQLite3: 12644, 12645, 12646 [\#427](https://github.com/SOCI/soci/pull/427) ([snikulov](https://github.com/snikulov))
- Enabled mysql/postgresql odbc tests - fixed \#407 [\#426](https://github.com/SOCI/soci/pull/426) ([snikulov](https://github.com/snikulov))
- moved SOCI\_CXX\_C11 define to common section [\#425](https://github.com/SOCI/soci/pull/425) ([snikulov](https://github.com/snikulov))
- Clang: fixed \#374 [\#422](https://github.com/SOCI/soci/pull/422) ([snikulov](https://github.com/snikulov))
- add ignore of cmake generated dsn file for access [\#421](https://github.com/SOCI/soci/pull/421) ([jeking3](https://github.com/jeking3))
- add a unit test for the postgresql uuid data type [\#420](https://github.com/SOCI/soci/pull/420) ([jeking3](https://github.com/jeking3))
- Travis-CI: added valgrind check [\#419](https://github.com/SOCI/soci/pull/419) ([snikulov](https://github.com/snikulov))
- fixed get\_affected\_rows\(\) to pass test thats broken since \#414 [\#418](https://github.com/SOCI/soci/pull/418) ([hw-dwalter](https://github.com/hw-dwalter))
- coverity: updated .travis.yml [\#417](https://github.com/SOCI/soci/pull/417) ([snikulov](https://github.com/snikulov))
- Travis-CI: try add Coverity tool [\#416](https://github.com/SOCI/soci/pull/416) ([snikulov](https://github.com/snikulov))
- AppVeyor: enable MSSQL ODBC connection [\#415](https://github.com/SOCI/soci/pull/415) ([snikulov](https://github.com/snikulov))
- added test to demonstrate bug \#221 [\#414](https://github.com/SOCI/soci/pull/414) ([hw-dwalter](https://github.com/hw-dwalter))
- Appveyor: added build for MySQL backend [\#410](https://github.com/SOCI/soci/pull/410) ([snikulov](https://github.com/snikulov))
- Appveyor: added PosgreSQL 9.4 backend [\#409](https://github.com/SOCI/soci/pull/409) ([snikulov](https://github.com/snikulov))
- Appveyor: Added SQLite to build [\#408](https://github.com/SOCI/soci/pull/408) ([snikulov](https://github.com/snikulov))
- appvr: added db services to build workers [\#406](https://github.com/SOCI/soci/pull/406) ([snikulov](https://github.com/snikulov))
- ODBC: test updates [\#405](https://github.com/SOCI/soci/pull/405) ([snikulov](https://github.com/snikulov))
- fixed typo [\#403](https://github.com/SOCI/soci/pull/403) ([DraconPern](https://github.com/DraconPern))
- Name struct to avoid clang error/warning \(issue \#374\) [\#402](https://github.com/SOCI/soci/pull/402) ([ArnaudD-FR](https://github.com/ArnaudD-FR))
- Appveyor: added Boost libraries to build [\#401](https://github.com/SOCI/soci/pull/401) ([snikulov](https://github.com/snikulov))
- fix for \#370 [\#400](https://github.com/SOCI/soci/pull/400) ([snikulov](https://github.com/snikulov))
- Update README.md [\#399](https://github.com/SOCI/soci/pull/399) ([snikulov](https://github.com/snikulov))
- mingw: not use ms extension for MinGW G++ compilation [\#398](https://github.com/SOCI/soci/pull/398) ([snikulov](https://github.com/snikulov))
- cmake: generate verbose build [\#397](https://github.com/SOCI/soci/pull/397) ([snikulov](https://github.com/snikulov))
- connection-pool: moved common part out of \#ifdef [\#395](https://github.com/SOCI/soci/pull/395) ([snikulov](https://github.com/snikulov))
- Restore using -pedantic but use -Wno-pedantic-ms-format too [\#392](https://github.com/SOCI/soci/pull/392) ([vadz](https://github.com/vadz))
- initial integration with AppVeyor-CI [\#391](https://github.com/SOCI/soci/pull/391) ([snikulov](https://github.com/snikulov))
- boost: disable autolink, because soci controls required libs itself [\#389](https://github.com/SOCI/soci/pull/389) ([snikulov](https://github.com/snikulov))
- cmake: updated FindODBC.cmake to search right sqlext.h on Windows [\#387](https://github.com/SOCI/soci/pull/387) ([snikulov](https://github.com/snikulov))
- sqlite3\_close moved after sqlite3\_errmsg is called. [\#381](https://github.com/SOCI/soci/pull/381) ([ravselj](https://github.com/ravselj))
- Build system: Replacing CMAKE\_SOURCE\_DIR with CMAKE\_CURRENT\_SOURCE\_DIR [\#380](https://github.com/SOCI/soci/pull/380) ([dgrafe](https://github.com/dgrafe))
- Memory leak fix in sqlite3 backend [\#378](https://github.com/SOCI/soci/pull/378) ([ravselj](https://github.com/ravselj))
- CMake debug postfix [\#376](https://github.com/SOCI/soci/pull/376) ([ravselj](https://github.com/ravselj))
- Sqlite backend fetch bug [\#375](https://github.com/SOCI/soci/pull/375) ([ravselj](https://github.com/ravselj))
- Fixed ambiguous 'session' reference [\#373](https://github.com/SOCI/soci/pull/373) ([musopr](https://github.com/musopr))
- Include SOCI\_CXX\_VERSION\_FLAGS when compiling with Clang [\#372](https://github.com/SOCI/soci/pull/372) ([musopr](https://github.com/musopr))
- CMake changes [\#368](https://github.com/SOCI/soci/pull/368) ([ravselj](https://github.com/ravselj))
- MSVC warnings in SQLite backend [\#365](https://github.com/SOCI/soci/pull/365) ([ravselj](https://github.com/ravselj))
- Fix connection-parameters options bug [\#364](https://github.com/SOCI/soci/pull/364) ([ravselj](https://github.com/ravselj))
- Allow setting ORACLE\_HOME directly in CMake GUI [\#363](https://github.com/SOCI/soci/pull/363) ([ravselj](https://github.com/ravselj))
- Sqlite3 optimization \[\#2\] [\#362](https://github.com/SOCI/soci/pull/362) ([ArnaudD-FR](https://github.com/ArnaudD-FR))
- Add dt\_blob [\#361](https://github.com/SOCI/soci/pull/361) ([ArnaudD-FR](https://github.com/ArnaudD-FR))
- Split Statement::clean\_up into bind\_clean\_up and clean\_up [\#358](https://github.com/SOCI/soci/pull/358) ([ArnaudD-FR](https://github.com/ArnaudD-FR))
- Improve ODBC error messages. [\#357](https://github.com/SOCI/soci/pull/357) ([vadz](https://github.com/vadz))
- Set CMake variable SOCI\_CORE\_TARGET at PARENT\_SCOPE [\#352](https://github.com/SOCI/soci/pull/352) ([ravselj](https://github.com/ravselj))
- Updated classic Makefile for PostgreSQL backend. [\#348](https://github.com/SOCI/soci/pull/348) ([msobczak](https://github.com/msobczak))
- Make it easier to override SOCI\_LIBDIR. [\#347](https://github.com/SOCI/soci/pull/347) ([jsonn](https://github.com/jsonn))
- Updated classic Makefiles for Oracle Express 11.2. [\#346](https://github.com/SOCI/soci/pull/346) ([msobczak](https://github.com/msobczak))
- Markdown Documentation [\#344](https://github.com/SOCI/soci/pull/344) ([OniDaito](https://github.com/OniDaito))
- Minor C++11 Pragma bugfix and Inlining C++11 test pragmas [\#343](https://github.com/SOCI/soci/pull/343) ([OniDaito](https://github.com/OniDaito))
- Fully qualify uses of session class with namespace soci::session [\#341](https://github.com/SOCI/soci/pull/341) ([mloskot](https://github.com/mloskot))
- Added the C++11 changes back in. Replaces \#327 [\#336](https://github.com/SOCI/soci/pull/336) ([OniDaito](https://github.com/OniDaito))
- Add -Wl,-flat\_namespace -Wl,-undefined -Wl,suppress to LINK\_FLAGS on Apple/OSX [\#335](https://github.com/SOCI/soci/pull/335) ([mloskot](https://github.com/mloskot))
- Restore Oracle setup on Travis CI server [\#326](https://github.com/SOCI/soci/pull/326) ([mloskot](https://github.com/mloskot))
- Use parameter names from query in the error messages. [\#318](https://github.com/SOCI/soci/pull/318) ([vadz](https://github.com/vadz))
- Small cleanup remaining from the attempt to fix timezone handling [\#316](https://github.com/SOCI/soci/pull/316) ([vadz](https://github.com/vadz))
- Updated FindMySQL.cmake to work under 64-bit windows. [\#314](https://github.com/SOCI/soci/pull/314) ([piotaixr](https://github.com/piotaixr))
- Don't add DB2\_INCLUDE\_DIR to global include directories. [\#313](https://github.com/SOCI/soci/pull/313) ([vadz](https://github.com/vadz))
- Add postgression service to Travis CI setup [\#306](https://github.com/SOCI/soci/pull/306) ([mloskot](https://github.com/mloskot))
- Merging master \(SOCI 3.2.3\) into develop [\#304](https://github.com/SOCI/soci/pull/304) ([mloskot](https://github.com/mloskot))
## [3.2.3](https://github.com/SOCI/soci/tree/3.2.3) (2015-04-08)
[Full Changelog](https://github.com/SOCI/soci/compare/3.2.2...3.2.3)
**Closed issues:**
- I want adaptable dumper. [\#299](https://github.com/SOCI/soci/issues/299)
- ODBC Connection parameter SQL\_DRIVER\_NOPROMPT throws std::logic\_error [\#273](https://github.com/SOCI/soci/issues/273)
- Problems with UTF-8 encoding while using std::strings in soci::use [\#269](https://github.com/SOCI/soci/issues/269)
- Build failure on Visual C++ 2013 due to strtoll\(\) and strtoull\(\) functions [\#262](https://github.com/SOCI/soci/issues/262)
- soci odbi-backend spelling error Commiting -\> Committing [\#260](https://github.com/SOCI/soci/issues/260)
- Assignment operator := needs to be treated specially when parsing the MySQL query [\#259](https://github.com/SOCI/soci/issues/259)
- ORA-00932: inconsistent datatypes: expected NUMBER got TIMESTAMP [\#252](https://github.com/SOCI/soci/issues/252)
- Oracle Connection to Cluster via TNS description [\#250](https://github.com/SOCI/soci/issues/250)
- can't generate vc7.1 project [\#227](https://github.com/SOCI/soci/issues/227)
- Memory leak after using open/creating soci::session with std::string [\#222](https://github.com/SOCI/soci/issues/222)
- Uncaughtable exception [\#219](https://github.com/SOCI/soci/issues/219)
- SOCI\_LIBDIR ends up being hard-coded to 'lib64' [\#212](https://github.com/SOCI/soci/issues/212)
- Add SOCI to Upstream Tracker [\#210](https://github.com/SOCI/soci/issues/210)
- Set CMake 2.8.8 as minimum required [\#200](https://github.com/SOCI/soci/issues/200)
- CMake 2.8.7 cannot set include\_directories per target [\#199](https://github.com/SOCI/soci/issues/199)
- Set up postgression service for Travis CI [\#167](https://github.com/SOCI/soci/issues/167)
- Implement new source tree layout [\#125](https://github.com/SOCI/soci/issues/125)
- Buried headers and includes cleanup [\#25](https://github.com/SOCI/soci/issues/25)
- Deadlock in non-windows implementation of soci::connection\_pool::try\_lease [\#284](https://github.com/SOCI/soci/issues/284)
- Patch for Visual Studio 2013 \(VC12\) [\#272](https://github.com/SOCI/soci/issues/272)
- Patch for using Oracle Instantclient v. 12 [\#271](https://github.com/SOCI/soci/issues/271)
- Avoid exception from destructor while stack unwinding [\#256](https://github.com/SOCI/soci/issues/256)
- git flow hotfix finish 3.2.3 [\#235](https://github.com/SOCI/soci/issues/235)
- git flow hotfix start 3.2.3 [\#234](https://github.com/SOCI/soci/issues/234)
- Compiling SOCI on Visual Studio 2013 Express [\#233](https://github.com/SOCI/soci/issues/233)
- Add git-flow support branch for 3.2 releases [\#206](https://github.com/SOCI/soci/issues/206)
- Clarify bulk examples [\#204](https://github.com/SOCI/soci/issues/204)
**Merged pull requests:**
- Provide error context in the exceptions. [\#302](https://github.com/SOCI/soci/pull/302) ([vadz](https://github.com/vadz))
- Add helper exchange\_type\_cast\<\>\(\) template function. [\#301](https://github.com/SOCI/soci/pull/301) ([vadz](https://github.com/vadz))
- Use a base-class member instead of shadowing it. [\#297](https://github.com/SOCI/soci/pull/297) ([nbougalis](https://github.com/nbougalis))
- Fix for the issue \#169: cleaner way to include headers. [\#294](https://github.com/SOCI/soci/pull/294) ([denisarnaud](https://github.com/denisarnaud))
- Don't start implicit transaction too eagerly in Firebird backend. [\#292](https://github.com/SOCI/soci/pull/292) ([vadz](https://github.com/vadz))
- Fix PostgreSQL unit test to pass with PostgreSQL \< 9.0. [\#242](https://github.com/SOCI/soci/pull/242) ([vadz](https://github.com/vadz))
- Include all public headers using "soci/" prefix inside SOCI itself. [\#239](https://github.com/SOCI/soci/pull/239) ([vadz](https://github.com/vadz))
- Add helper cstring\_to\_double\(\) and use it in PostgreSQL backend. [\#238](https://github.com/SOCI/soci/pull/238) ([vadz](https://github.com/vadz))
- Fix compilation of ODBC-specific SOCI header with new include paths. [\#237](https://github.com/SOCI/soci/pull/237) ([vadz](https://github.com/vadz))
- Add get\_last\_insert\_id for sqlite3 and mysql backends [\#216](https://github.com/SOCI/soci/pull/216) ([dgrambow](https://github.com/dgrambow))
- Fix in soci::oracle to allow spaces in the params [\#213](https://github.com/SOCI/soci/pull/213) ([ayllon](https://github.com/ayllon))
- Adding cmake SOCI\_SHARED option and lowercasing windows.h [\#286](https://github.com/SOCI/soci/pull/286) ([bingmann](https://github.com/bingmann))
- fixed deadlock in soci::connection\_pool::try\_lease [\#285](https://github.com/SOCI/soci/pull/285) ([javerskulpa](https://github.com/javerskulpa))
- Add missing include for std::max [\#278](https://github.com/SOCI/soci/pull/278) ([mika-fischer](https://github.com/mika-fischer))
- Two enhancements for SOCI 3.2.3 hotfix, PostgreSQL UUID column support and SQLITE3 error code in exception [\#263](https://github.com/SOCI/soci/pull/263) ([Alex-Vol](https://github.com/Alex-Vol))
- Spelling fix Comiting -\> Comitting \(Fixes \#260\) [\#261](https://github.com/SOCI/soci/pull/261) ([coldtobi](https://github.com/coldtobi))
- vs2013 got strtoll/strtoull [\#217](https://github.com/SOCI/soci/pull/217) ([fly2xj](https://github.com/fly2xj))
## [3.2.2](https://github.com/SOCI/soci/tree/3.2.2) (2013-09-10)
[Full Changelog](https://github.com/SOCI/soci/compare/3.2.1...3.2.2)
**Closed issues:**
- sqlite3 backend abstract on build [\#139](https://github.com/SOCI/soci/issues/139)
- sqlite3: sqlite3\_prepare will return SQLITE\_SCHEMA, please use sqlite3\_prepare\_v2 [\#188](https://github.com/SOCI/soci/issues/188)
- CMake option SQLITE3\_LIBRARIES not handled correctly [\#182](https://github.com/SOCI/soci/issues/182)
- noexcept on once\_temp\_type [\#181](https://github.com/SOCI/soci/issues/181)
- git flow hotfix finish 3.2.2 [\#180](https://github.com/SOCI/soci/issues/180)
- Wrong GCC\_VERSION for commandline-overriden GCC [\#178](https://github.com/SOCI/soci/issues/178)
- Separate Travis CI builds per backend [\#171](https://github.com/SOCI/soci/issues/171)
- MSVC build of ODBC with UNICODE enabled fails on error handling [\#163](https://github.com/SOCI/soci/issues/163)
- git flow hotfix start 3.2.2 [\#159](https://github.com/SOCI/soci/issues/159)
- Calling undefine\_and\_bind and then define\_and\_bind causes a leak. [\#154](https://github.com/SOCI/soci/issues/154)
- Uninitialized soci::indicator values in type conversion specialisations [\#152](https://github.com/SOCI/soci/issues/152)
- Incorrect sscanf format strings on windows [\#149](https://github.com/SOCI/soci/issues/149)
- db2\_standard\_use\_type\_backend don't detect correctly size changes in string parameters [\#141](https://github.com/SOCI/soci/issues/141)
- db2\_standard\_use\_type\_backend doesn't detect correctly size changes in parameters [\#140](https://github.com/SOCI/soci/issues/140)
- Problem doing a cast because of the colon parsing [\#121](https://github.com/SOCI/soci/issues/121)
- Documentation for specializing type\_conversion\<\> doesn't fully explain indicators [\#102](https://github.com/SOCI/soci/issues/102)
- get\_affected\_rows\(\) returns -1 for bulk operations [\#83](https://github.com/SOCI/soci/issues/83)
- Undefined behaviour when use unitialized indicator [\#28](https://github.com/SOCI/soci/issues/28)
**Merged pull requests:**
- Handle SQLITE3\_LIBRARIES by find\_package\_handle\_standard\_args [\#193](https://github.com/SOCI/soci/pull/193) ([mloskot](https://github.com/mloskot))
- Specify once\_temp\_type dtor with noexcept\(false\) [\#192](https://github.com/SOCI/soci/pull/192) ([mloskot](https://github.com/mloskot))
- Replace sqlite3\_prepare with sqlite3\_prepare\_v2 [\#191](https://github.com/SOCI/soci/pull/191) ([mloskot](https://github.com/mloskot))
- fixed wrong size parameter in final memcpy\(\) [\#185](https://github.com/SOCI/soci/pull/185) ([ghost](https://github.com/ghost))
- In Unix System cmake could not find ORACLE\_NNZ\_LIBRARY for Oracle 12g.li... [\#183](https://github.com/SOCI/soci/pull/183) ([cngzhnp](https://github.com/cngzhnp))
- Travis matrix builds [\#174](https://github.com/SOCI/soci/pull/174) ([mloskot](https://github.com/mloskot))
- Explicitly include stdarg.h pulled in by namespace-protected sqlite.h. [\#172](https://github.com/SOCI/soci/pull/172) ([jsonn](https://github.com/jsonn))
- A more compatible test for issue \#154, make firebird run it. [\#165](https://github.com/SOCI/soci/pull/165) ([ricardofandrade](https://github.com/ricardofandrade))
- ODBC: Reviewed the local use of the rows\_processed [\#161](https://github.com/SOCI/soci/pull/161) ([ricardofandrade](https://github.com/ricardofandrade))
- Fixes the compilation of the firebird tests with the backend as a DLL. [\#147](https://github.com/SOCI/soci/pull/147) ([ricardofandrade](https://github.com/ricardofandrade))
- Handle PostgreSQL's UNKNOWNOID type as a string into row [\#135](https://github.com/SOCI/soci/pull/135) ([ricardofandrade](https://github.com/ricardofandrade))
- Don't allow exceptions escape from postgresql\_statement\_backend dtor. [\#134](https://github.com/SOCI/soci/pull/134) ([vadz](https://github.com/vadz))
- Implement session::get\_next\_sequence\_value\(\) for PostgreSQL backend. [\#133](https://github.com/SOCI/soci/pull/133) ([vadz](https://github.com/vadz))
- Fix harmless warning about signed/unsigned comparison. [\#132](https://github.com/SOCI/soci/pull/132) ([vadz](https://github.com/vadz))
- Some trivial optimizations in ODBC statement preparation code. [\#111](https://github.com/SOCI/soci/pull/111) ([vadz](https://github.com/vadz))
## [3.2.1](https://github.com/SOCI/soci/tree/3.2.1) (2013-04-12)
[Full Changelog](https://github.com/SOCI/soci/compare/3.2.0...3.2.1)
**Closed issues:**
- MySQL Backend issues on Mac OS X [\#130](https://github.com/SOCI/soci/issues/130)
- git flow hotfix finish 3.2.1 [\#131](https://github.com/SOCI/soci/issues/131)
- Incorrect usage of numeric\_limits trait in Oracle backed [\#126](https://github.com/SOCI/soci/issues/126)
- SOCI 3.2.0 does not build on Windows [\#123](https://github.com/SOCI/soci/issues/123)
- Clean up names and use of SOCI\_POSTGRESQL\_NOPARAMS [\#120](https://github.com/SOCI/soci/issues/120)
- Prepared insert statement with data exchange and custom type does not work [\#117](https://github.com/SOCI/soci/issues/117)
- deallocate\_prepared\_statement called for non-existing statement [\#116](https://github.com/SOCI/soci/issues/116)
- Query transformation not working with sessions from pool [\#113](https://github.com/SOCI/soci/issues/113)
- Add common tests to DB2 [\#94](https://github.com/SOCI/soci/issues/94)
**Merged pull requests:**
- DB2 backend patches [\#97](https://github.com/SOCI/soci/pull/97) ([toonen](https://github.com/toonen))
## [3.2.0](https://github.com/SOCI/soci/tree/3.2.0) (2013-03-26)
[Full Changelog](https://github.com/SOCI/soci/compare/3.1.0...3.2.0)
**Closed issues:**
- Run time error: what\(\): Malformed connection string. [\#20](https://github.com/SOCI/soci/issues/20)
- Unexpected behavior when making multiple calls to rowset's begin\(\) and end\(\) [\#17](https://github.com/SOCI/soci/issues/17)
- git flow finish release 3.2.0 [\#109](https://github.com/SOCI/soci/issues/109)
- Run common tests against DB2 [\#106](https://github.com/SOCI/soci/issues/106)
- Re-enable g++ testing on travis-ci [\#96](https://github.com/SOCI/soci/issues/96)
- Update CHANGES for 3.2.0 [\#93](https://github.com/SOCI/soci/issues/93)
- Add testing against clang on travis-ci [\#92](https://github.com/SOCI/soci/issues/92)
- Mark Makefile.basic as deprecated [\#91](https://github.com/SOCI/soci/issues/91)
- Build failure with Oracle Instant Client 11.2.0.3.0 [\#89](https://github.com/SOCI/soci/issues/89)
- SOCI\_COMPILER\_NAME not determined for VS2012 [\#87](https://github.com/SOCI/soci/issues/87)
- postgresql backend leaks a PGResult\* when an exception is thrown [\#86](https://github.com/SOCI/soci/issues/86)
- Update documentation for 3.2.0 release [\#85](https://github.com/SOCI/soci/issues/85)
- Binding procedure IN/OUT parameter has no out effect [\#81](https://github.com/SOCI/soci/issues/81)
- Add CMake option SOCI\_STATIC [\#80](https://github.com/SOCI/soci/issues/80)
- Patch with DB2 backend [\#70](https://github.com/SOCI/soci/issues/70)
- Allocated statement backend memory leaks on exception [\#67](https://github.com/SOCI/soci/issues/67)
- Add query transformation callback feature [\#66](https://github.com/SOCI/soci/issues/66)
- Add Firebird support to Travis-CI configuration [\#64](https://github.com/SOCI/soci/issues/64)
- Add missing ODBC tests to CMake configuration [\#62](https://github.com/SOCI/soci/issues/62)
- Add CMake configuration for Firebird [\#57](https://github.com/SOCI/soci/issues/57)
- Add ODBC support to Travis-CI configuration [\#49](https://github.com/SOCI/soci/issues/49)
- Incorrect assertion in postgresql::get\_error\_details [\#48](https://github.com/SOCI/soci/issues/48)
- Update code examples [\#47](https://github.com/SOCI/soci/issues/47)
- Placeholder at the last position of statement causing crash [\#44](https://github.com/SOCI/soci/issues/44)
- warning: comparing floating point with == or != is unsafe [\#42](https://github.com/SOCI/soci/issues/42)
- Bump SOCI version in master to 3.2.0 [\#39](https://github.com/SOCI/soci/issues/39)
- FindODBC.cmake deviates from soci\_backend\(\) conventions [\#32](https://github.com/SOCI/soci/issues/32)
- Building with Visual Studio 2010: identifier strtoull not found [\#27](https://github.com/SOCI/soci/issues/27)
- CMake ignores -DWITH\_\<dep\> option [\#23](https://github.com/SOCI/soci/issues/23)
- make install - Fedora 17 [\#21](https://github.com/SOCI/soci/issues/21)
- Server-side memory leak in PostgreSQL [\#19](https://github.com/SOCI/soci/issues/19)
- Apply Git workflow: GitFlow [\#18](https://github.com/SOCI/soci/issues/18)
- FindMySQL.cmake update for custom mysqlclient location [\#16](https://github.com/SOCI/soci/issues/16)
- Premature deallocation of prepared statement [\#13](https://github.com/SOCI/soci/issues/13)
**Merged pull requests:**
- Fix int and long mismatch for vector in ODBC [\#103](https://github.com/SOCI/soci/pull/103) ([mloskot](https://github.com/mloskot))
- Fix OUT direction of IN/OUT procedure parameter [\#88](https://github.com/SOCI/soci/pull/88) ([mloskot](https://github.com/mloskot))
- Implementation of query transformation callback feature [\#82](https://github.com/SOCI/soci/pull/82) ([mloskot](https://github.com/mloskot))
- Fix Firebird tests: test\_get\_affected\_rows\(\) [\#74](https://github.com/SOCI/soci/pull/74) ([vnaydionov](https://github.com/vnaydionov))
- Fix connection parsing in SOCI Firebird backend to handle spaces in values. [\#73](https://github.com/SOCI/soci/pull/73) ([vadz](https://github.com/vadz))
- Firebird backend specific: add option to fetch decimals as strings [\#71](https://github.com/SOCI/soci/pull/71) ([vnaydionov](https://github.com/vnaydionov))
- Improve fixes in pull \#5 [\#69](https://github.com/SOCI/soci/pull/69) ([mloskot](https://github.com/mloskot))
- Fix memory leak of statement backend \(issue \#67\) [\#68](https://github.com/SOCI/soci/pull/68) ([mloskot](https://github.com/mloskot))
- Improve input parameter binding in Firebird backend. [\#65](https://github.com/SOCI/soci/pull/65) ([vnaydionov](https://github.com/vnaydionov))
- Add missing ODBC tests to CMake configuration \(issue \#62\) [\#63](https://github.com/SOCI/soci/pull/63) ([mloskot](https://github.com/mloskot))
- Add PostgreSQL test for bytea to pull request \#46 [\#61](https://github.com/SOCI/soci/pull/61) ([mloskot](https://github.com/mloskot))
- Added CMake scripts for Firebird backend and fixed it to pass all the tests [\#60](https://github.com/SOCI/soci/pull/60) ([vnaydionov](https://github.com/vnaydionov))
- Fix to build the Firebird backend [\#56](https://github.com/SOCI/soci/pull/56) ([vnaydionov](https://github.com/vnaydionov))
- Properly compute LIBDIR on \(modern\) Debian [\#55](https://github.com/SOCI/soci/pull/55) ([hasselmm](https://github.com/hasselmm))
- Support reading bytea data in PostgreSQL backend as another string type [\#46](https://github.com/SOCI/soci/pull/46) ([hobu](https://github.com/hobu))
- Patch received from Daniel Beaudoin \(Optel Vision\) on 23/07/2012\) [\#45](https://github.com/SOCI/soci/pull/45) ([mloskot](https://github.com/mloskot))
- For Visual C++, defined std::strtoll in terms of \_strtoi64\(\) [\#43](https://github.com/SOCI/soci/pull/43) ([mloskot](https://github.com/mloskot))
- Bumped version number to 3.2.0 [\#40](https://github.com/SOCI/soci/pull/40) ([mloskot](https://github.com/mloskot))
- handle WITH\_{dependency} switch to turn on/off deps [\#38](https://github.com/SOCI/soci/pull/38) ([snikulov](https://github.com/snikulov))
- qualify strtoull/strtoll with std namespace [\#37](https://github.com/SOCI/soci/pull/37) ([avg-I](https://github.com/avg-I))
- FindSoci.cmake: fix couple of minor issues [\#36](https://github.com/SOCI/soci/pull/36) ([avg-I](https://github.com/avg-I))
- FindODBC.cmake: rename ODBC\_INCLUDE\_DIRECTORIES to ODBC\_INCLUDE\_DIR [\#35](https://github.com/SOCI/soci/pull/35) ([avg-I](https://github.com/avg-I))
- README update and minimal CMake version update [\#34](https://github.com/SOCI/soci/pull/34) ([mloskot](https://github.com/mloskot))
- backends/oracle: support working in multithreaded programs [\#31](https://github.com/SOCI/soci/pull/31) ([avg-I](https://github.com/avg-I))
- Set INSTALL\_NAME\_DIR as used on OS X [\#30](https://github.com/SOCI/soci/pull/30) ([arsenm](https://github.com/arsenm))
- cmake: FindSQLite3 - add handling of SQLITE\_ROOT\_DIR [\#29](https://github.com/SOCI/soci/pull/29) ([snikulov](https://github.com/snikulov))
- Fix proposal for issue SOCI/soci\#13 [\#14](https://github.com/SOCI/soci/pull/14) ([mloskot](https://github.com/mloskot))
- This makes possible to disable empty backend build [\#11](https://github.com/SOCI/soci/pull/11) ([krieger-od](https://github.com/krieger-od))
- OSX clang std::getline bug [\#10](https://github.com/SOCI/soci/pull/10) ([hobu](https://github.com/hobu))
- cmake: updated backends build [\#8](https://github.com/SOCI/soci/pull/8) ([snikulov](https://github.com/snikulov))
- SQLite database path may contain spaces if enclosed in quotes. [\#6](https://github.com/SOCI/soci/pull/6) ([belobrov-andrey](https://github.com/belobrov-andrey))
- Backend is not set properly with connection pool [\#5](https://github.com/SOCI/soci/pull/5) ([ghost](https://github.com/ghost))
- Fixed a compile error in FreeBSD 8.2, using the lates GCC version 4.2.1 [\#2](https://github.com/SOCI/soci/pull/2) ([jamercee](https://github.com/jamercee))
- Implement get\_affected\_rows for SQLite3 backend [\#1](https://github.com/SOCI/soci/pull/1) ([mika-fischer](https://github.com/mika-fischer))
## [3.1.0](https://github.com/SOCI/soci/tree/3.1.0) (2011-10-20)
[Full Changelog](https://github.com/SOCI/soci/compare/v3.1.0...3.1.0)
## [v3.1.0](https://github.com/SOCI/soci/tree/v3.1.0) (2011-10-20)
[Full Changelog](https://github.com/SOCI/soci/compare/soci-3.1.0.zip...v3.1.0)
## [soci-3.1.0.zip](https://github.com/SOCI/soci/tree/soci-3.1.0.zip) (2011-10-08)
[Full Changelog](https://github.com/SOCI/soci/compare/v3.0.0...soci-3.1.0.zip)
## [v3.0.0](https://github.com/SOCI/soci/tree/v3.0.0) (2008-07-09)
[Full Changelog](https://github.com/SOCI/soci/compare/soci-3.0.0.zip...v3.0.0)
## [soci-3.0.0.zip](https://github.com/SOCI/soci/tree/soci-3.0.0.zip) (2008-07-08)
[Full Changelog](https://github.com/SOCI/soci/compare/soci-2.2.0.zip...soci-3.0.0.zip)
## [soci-2.2.0.zip](https://github.com/SOCI/soci/tree/soci-2.2.0.zip) (2006-12-02)
[Full Changelog](https://github.com/SOCI/soci/compare/soci-2.1.0.zip...soci-2.2.0.zip)
## [soci-2.1.0.zip](https://github.com/SOCI/soci/tree/soci-2.1.0.zip) (2006-05-12)
[Full Changelog](https://github.com/SOCI/soci/compare/soci-2.0.1.zip...soci-2.1.0.zip)
## [soci-2.0.1.zip](https://github.com/SOCI/soci/tree/soci-2.0.1.zip) (2006-02-15)
[Full Changelog](https://github.com/SOCI/soci/compare/soci-2.0.0.zip...soci-2.0.1.zip)
## [soci-2.0.0.zip](https://github.com/SOCI/soci/tree/soci-2.0.0.zip) (2006-01-15)
[Full Changelog](https://github.com/SOCI/soci/compare/soci-1.2.1.zip...soci-2.0.0.zip)
## [soci-1.2.1.zip](https://github.com/SOCI/soci/tree/soci-1.2.1.zip) (2005-10-13)
[Full Changelog](https://github.com/SOCI/soci/compare/soci-1.2.0.zip...soci-1.2.1.zip)
## [soci-1.2.0.zip](https://github.com/SOCI/soci/tree/soci-1.2.0.zip) (2005-10-02)
[Full Changelog](https://github.com/SOCI/soci/compare/soci-1.1.0.zip...soci-1.2.0.zip)
## [soci-1.1.0.zip](https://github.com/SOCI/soci/tree/soci-1.1.0.zip) (2005-02-27)
[Full Changelog](https://github.com/SOCI/soci/compare/soci-1.0.1.zip...soci-1.1.0.zip)
## [soci-1.0.1.zip](https://github.com/SOCI/soci/tree/soci-1.0.1.zip) (2004-10-16)
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*

View File

@@ -6,6 +6,7 @@ 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().
- Add helpers for generating portable DDL and DML statements.
- Firebird
-- Add SOCI_FIREBIRD_EMBEDDED option to allow building with embedded library.

View File

@@ -10,10 +10,20 @@
###############################################################################
# General settings
###############################################################################
cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
project(SOCI)
###############################################################################
# Build features and variants
##############################################################################
option(SOCI_SHARED "Enable build of shared libraries" ON)
option(SOCI_STATIC "Enable build of static libraries" ON)
option(SOCI_TESTS "Enable build of collection of SOCI tests" ON)
option(SOCI_ASAN "Enable address sanitizer on GCC v4.8+/Clang v 3.1+" OFF)
###############################################################################
# SOCI CMake modules
###############################################################################
@@ -32,24 +42,20 @@ colormsg(_HIBLUE_ "Configuring SOCI:")
###############################################################################
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)
soci_version()
###############################################################################
# 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)
boost_report_value(SOCI_ASAN)
# from SociConfig.cmake
boost_report_value(SOCI_CXX_C11)
boost_report_value(LIB_SUFFIX)
# Put the libaries and binaries that get built into directories at the
# top of the build tree rather than in hard-to-find leaf
@@ -69,7 +75,7 @@ set(SOCI_CORE_DEPS_LIBS)
include(SociDependencies)
get_property(SOCI_INCLUDE_DIRS DIRECTORY ${CMAKE_SOURCE_DIR}
get_property(SOCI_INCLUDE_DIRS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
PROPERTY INCLUDE_DIRECTORIES)
if(Threads_FOUND)
@@ -86,21 +92,20 @@ if(NOT MSVC)
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}
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
PROPERTY COMPILE_DEFINITIONS)
list(APPEND SOCI_COMPILE_DEFINITIONS "HAVE_BOOST=1")
set(SOCI_HAVE_BOOST ON)
list(APPEND SOCI_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB")
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")
set(SOCI_HAVE_BOOST_DATE_TIME ON)
endif()
list(APPEND SOCI_INCLUDE_DIRS ${Boost_INCLUDE_DIRS})
@@ -110,11 +115,17 @@ if(Boost_FOUND)
set_property(DIRECTORY ${SOCI_SOURCE_DIR}
PROPERTY COMPILE_DEFINITIONS "${SOCI_COMPILE_DEFINITIONS}")
else()
set(SOCI_HAVE_BOOST OFF)
set(SOCI_HAVE_BOOST_DATE_TIME OFF)
endif()
set(SOCI_HAVE_BOOST ${SOCI_HAVE_BOOST} CACHE INTERNAL "Boost library")
set(SOCI_HAVE_BOOST_DATE_TIME ${SOCI_HAVE_BOOST_DATE_TIME} CACHE INTERNAL "Boost date_time library")
list(APPEND SOCI_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR})
set_property(DIRECTORY ${CMAKE_SOURCE_DIR}
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
PROPERTY
INCLUDE_DIRECTORIES ${SOCI_INCLUDE_DIRS})
@@ -136,24 +147,61 @@ 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
# Configuration files
###############################################################################
enable_testing()
# Configure for testing with dashboard submissions to CDash
#include(CTest) # disabled as unused
set(CONFIG_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/include)
install(DIRECTORY ${CONFIG_INCLUDE_DIR}/soci DESTINATION ${INCLUDEDIR})
set(CONFIG_FILE_IN "include/soci/soci-config.h.in")
set(CONFIG_FILE_OUT "${CONFIG_INCLUDE_DIR}/soci/soci-config.h")
# 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)
include_directories(${SOCI_SOURCE_DIR}/include ${CONFIG_INCLUDE_DIR})
add_subdirectory(src)
add_subdirectory(tests)
if(SOCI_TESTS)
###############################################################################
# Enable tests
###############################################################################
enable_testing()
file(TO_NATIVE_PATH ${PROJECT_SOURCE_DIR} TEST_ACCESS_PATH)
configure_file(${PROJECT_SOURCE_DIR}/cmake/configs/test-access.cmake ${PROJECT_SOURCE_DIR}/tests/odbc/test-access.dsn @ONLY)
set(MYSQL_DRIVER_NAME "MySQL")
if(WIN32)
set(MYSQL_DRIVER_NAME "MySQL ODBC 5.3 ANSI Driver")
endif()
configure_file(${PROJECT_SOURCE_DIR}/cmake/configs/test-mysql.cmake ${PROJECT_SOURCE_DIR}/tests/odbc/test-mysql.dsn @ONLY)
# Define "make check" as alias for "make test"
add_custom_target(check COMMAND ctest)
add_subdirectory(tests)
endif()
###############################################################################
# build config file
###############################################################################
get_cmake_property(ALL_VARIABLES CACHE_VARIABLES)
set(CONFIGURED_VARIABLES)
foreach(v ${ALL_VARIABLES})
if (v MATCHES "^SOCI_HAVE.*")
get_property(CACHE_HELPSTRING CACHE ${v} PROPERTY HELPSTRING)
set(CONFIGURED_VARIABLES "${CONFIGURED_VARIABLES}\n// ${CACHE_HELPSTRING}\n")
if (${${v}})
set(CONFIGURED_VARIABLES "${CONFIGURED_VARIABLES}#define ${v}\n")
else()
set(CONFIGURED_VARIABLES "${CONFIGURED_VARIABLES}/* #undef ${v} */\n")
endif()
endif()
endforeach()
configure_file("${CONFIG_FILE_IN}" "${CONFIG_FILE_OUT}")
message(STATUS "")

View File

@@ -1,13 +0,0 @@
## This file should be placed in the root directory of your project.
## Then modify the CMakeLists.txt file in the root directory of your
## project to incorporate the testing dashboard.
## # The following are required to uses Dart and the Cdash dashboard
## ENABLE_TESTING()
## INCLUDE(CTest)
set(CTEST_PROJECT_NAME "SOCI")
set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=SOCI")
set(CTEST_DROP_SITE_CDASH TRUE)

View File

@@ -1,43 +1,24 @@
SOCI - The C++ Database Access Library
======================================
# SOCI - The C++ Database Access Library
Website: http://soci.sourceforge.net
[![GitHub release](https://img.shields.io/github/tag/SOCI/soci.svg)](https://github.com/SOCI/soci/releases/tag/3.2.3)
[![GitHub commits](https://img.shields.io/github/commits-since/SOCI/soci/3.2.3.svg)](https://github.com/SOCI/soci/tree/master)
GitHub hosts SOCI source code repository, issues tracker and wiki:
https://github.com/SOCI
[![Website](https://img.shields.io/website-up-down-green-red/http/shields.io.svg?label=soci.sourceforge.net)](http://soci.sourceforge.net)
[![SourceForge](https://img.shields.io/sourceforge/dm/soci.svg)](https://sourceforge.net/projects/soci/files/)
Downloads and mailing lists at
http://sourceforge.net/projects/soci/
[![Gitter](https://img.shields.io/gitter/room/SOCI/soci.svg)](https://gitter.im/SOCI/soci)
[![Mailing Lists](https://img.shields.io/badge/mailing--lists-ok-yellowgreen.svg)](https://sourceforge.net/p/soci/mailman/)
[![StackExchange](https://img.shields.io/stackexchange/stackoverflow/t/soci.svg)](https://stackoverflow.com/questions/tagged/soci)
Travis CI service at https://travis-ci.org/SOCI/soci
## Build Status
[![Build Status](https://api.travis-ci.org/SOCI/soci.png)](https://travis-ci.org/SOCI/soci)
| Branches | Travis-CI | AppVeyor-CI | Coverity Scan | Documentation |
|-------------|-----------|-------------|----------------|---------------|
| master | [![Build Status](https://travis-ci.org/SOCI/soci.svg?branch=master)](https://travis-ci.org/SOCI/soci) | [![Build status](https://ci.appveyor.com/api/projects/status/dtp5mvbeyu9aqupr/branch/master?svg=true)](https://ci.appveyor.com/project/SOCI/soci/branch/master) | [![Coverage](https://scan.coverity.com/projects/6581/badge.svg)](https://scan.coverity.com/projects/soci-soci) | [![Docs Status](https://circleci.com/gh/SOCI/soci.svg?style=shield&circle-token=5d31c692ed5fcffa5c5fc6b7fe2257b34d78f3c9)](https://circleci.com/gh/SOCI/soci) |
| release/3.2 | [![Build Status](https://travis-ci.org/SOCI/soci.svg?branch=release%2F3.2)](https://travis-ci.org/SOCI/soci) | | | |
License
-------
## History
The SOCI library is distributed under the terms of the [Boost Software License](http://www.boost.org/LICENSE_1_0.txt).
Requirements
------------
Core:
* C++ compiler
* Boost C++ Libraries (optional, headers and Boost.DateTime)
Backend specific client libraries for:
* DB2
* Firebird
* MySQL
* ODBC with specific database driver
* Oracle
* PostgreSQL
* SQLite 3
See documentation at http://soci.sourceforge.net for details
Brief History
-------------
Originally, SOCI was developed by [Maciej Sobczak](http://www.msobczak.com/)
at [CERN](http://www.cern.ch/) as abstraction layer for Oracle,
a **Simple Oracle Call Interface**.
@@ -50,3 +31,29 @@ or something similar.
> layer in some of the control system components."
-- Maciej Sobczak at [Inspirel](http://www.inspirel.com/users.html)
## License
SOCI library is distributed under the terms of the [Boost Software License](http://www.boost.org/LICENSE_1_0.txt).
## Requirements
Core:
* C++ compiler
* Boost C++ Libraries (optional, headers and Boost.DateTime)
Backend specific client libraries for:
* DB2
* Firebird
* MySQL
* ODBC with specific database driver
* Oracle
* PostgreSQL
* SQLite 3
See documentation at [soci.sourceforge.net](http://soci.sourceforge.net) for details
[BSL](http://www.boost.org/LICENSE_1_0.txt) &copy;
[Maciej Sobczak](http://github.com/msobczak) and [contributors](https://github.com/SOCI/soci/graphs/contributors).

View File

@@ -1,4 +1,4 @@
$Id: ideas.txt,v 1.8 2006/12/12 07:39:22 msobczak Exp $
TODO
This file contains a raw bunch of ideas for future releases.
Not all of these ideas will necessarily make sense - they are here to get them together.
@@ -10,17 +10,6 @@ http://lists.boost.org/Archives/boost/2006/12/113961.php
---
RAII for transactions.
---
bjam
Add JamFile files
---
Refactoring of core, more fine-grained file structure.
---
Session constructor overload that accepts map<string,string> for param=value pairs.
This should rather be provided as a separate function?
---
Query construction utilities (kind of Ultimate++) - can be easily incorporated into SOCI by just making them streamable.
@@ -50,13 +39,6 @@ Note: default is a reserved word.
---
Provide statement-wide flag for eNoData case (because actually it *is* statement-wide, not field-wide). With this, boost.optional would handle the eNull case and the indicators could be dropped.
---
Session sql("mysql://user:password@host/database");
So that Session tries to find backend_mysql.(dll|so) if not yet registered.
---
number of rows affected (insert/update + select?)
---
query backend for supported featureset at runtime
@@ -65,9 +47,6 @@ query backend for supported featureset at runtime
Rowset<tuple>
---
boost::optional?
---
Rowset<T>, including Rowset<tuple> - way to indicate nulls?
Additional pair based val/indicator interface?
@@ -129,6 +108,3 @@ rowset<Row> rs = (s.prepare << "firstname='John' AND age > 28") // multi-fields
- very simple home-made SQL parser or SQL-like queries support (see OGR utils from http://www.gdal.org)
---
Session::reconnect (should connect again with the same params).
Why not also Session::open/close?

56
src/soci/Vagrantfile vendored Normal file
View File

@@ -0,0 +1,56 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrant virtual development environments for SOCI
Vagrant.configure(2) do |config|
config.vm.box = "bento/ubuntu-14.04"
config.vm.box_check_update = true
# Main SOCI development box with build essentials, FOSS DBs
config.vm.define "soci", primary: true do |soci|
soci.vm.hostname = "vmsoci"
soci.vm.network "private_network", type: "dhcp"
soci.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--memory", "1024"]
end
scripts = [
"bootstrap.sh",
"devel.sh",
"db2cli.sh",
"firebird.sh",
"mysql.sh",
"postgresql.sh",
"build.sh"
]
scripts.each { |script|
soci.vm.provision :shell, privileged: false, :path => "scripts/vagrant/" << script
}
end
# Database box with IBM DB2 Express-C
config.vm.define "db2", autostart: false do |db2|
db2.vm.hostname = "vmdb2"
db2.vm.network "private_network", type: "dhcp"
# Access to DB2 instance from host
db2.vm.network :forwarded_port, host: 50000, guest: 50000
db2.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--memory", "1024"]
end
scripts = [
"bootstrap.sh",
"db2.sh"
]
scripts.each { |script|
db2.vm.provision :shell, privileged: false, :path => "scripts/vagrant/" << script
}
end
# Database box with Oracle XE
# config.vm.define "oracle", autostart: false do |oracle|
# oracle.vm.provision "database", type: "shell" do |s|
# s.inline = "echo Installing Oracle'"
# end
# end
end

104
src/soci/appveyor.yml Normal file
View File

@@ -0,0 +1,104 @@
version: 4.0.0.{build}
configuration: Release
environment:
MINGW_ARCHIVE: C:\projects\mingw\x86_64-4.8.3-release-posix-seh-rt_v3-rev2.7z
MINGW_URL: https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.8.3/threads-posix/seh/x86_64-4.8.3-release-posix-seh-rt_v3-rev2.7z/download
matrix:
- G: "Visual Studio 15 2017 Win64"
BOOST_ROOT: C:\Libraries\boost_1_59_0
POSTGRESQL_ROOT: C:\Program Files\PostgreSQL\9.6
MYSQL_DIR: C:\Program Files\MySql\MySQL Server 5.7
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- G: "Visual Studio 14 2015 Win64"
BOOST_ROOT: C:\Libraries\boost_1_59_0
POSTGRESQL_ROOT: C:\Program Files\PostgreSQL\9.4
MYSQL_DIR: C:\Program Files\MySql\MySQL Server 5.7
- G: "Visual Studio 12 2013 Win64"
BOOST_ROOT: C:\Libraries\boost_1_58_0
POSTGRESQL_ROOT: C:\Program Files\PostgreSQL\9.4
MYSQL_DIR: C:\Program Files\MySql\MySQL Server 5.7
- G: "Visual Studio 11 2012 Win64"
BOOST_ROOT: C:\Libraries\boost_1_58_0
POSTGRESQL_ROOT: C:\Program Files\PostgreSQL\9.4
MYSQL_DIR: C:\Program Files\MySql\MySQL Server 5.7
- G: "MinGW Makefiles"
MINGW_ROOT: C:\projects\mingw\4.8.3\mingw64\bin
BOOST_ROOT: C:\Libraries\boost_1_59_0
POSTGRESQL_ROOT: C:\Program Files\PostgreSQL\9.4
MYSQL_DIR: C:\Program Files\MySql\MySQL Server 5.7
services:
- mssql2014
- mysql
- postgresql
cache:
- C:\projects\mingw
install:
- ps: |
if ($env:G -eq "MinGW Makefiles")
{
if (!(Test-Path C:\projects\mingw))
{
mkdir C:\projects\mingw
}
if (!(Test-Path $env:MINGW_ARCHIVE))
{
(new-object net.webclient).DownloadFile("$env:MINGW_URL", "$env:MINGW_ARCHIVE")
7z x -y -oC:\projects\mingw\4.8.3\ $env:MINGW_ARCHIVE > $null
}
}
Import-Module C:\projects\soci\scripts\windows\Get-ODBCList.ps1
Get-ODBCList
- git clone https://github.com/snikulov/sqlite.cmake.build.git C:\projects\sqlite\src
before_build:
# dirty little hack - remove sh from Git to make generator happy
- ps: |
if ($env:G -eq "MinGW Makefiles")
{
$shellPath = (Get-Command sh.exe).definition
if ($shellPath)
{
if (Test-Path $shellPath)
{
Remove-Item $shellPath
}
}
}
- cd C:\projects\sqlite\src
- mkdir build
- cd build
- set SQLITE_ROOT=C:\projects\sqlite\sqlite
- set PATH=%MINGW_ROOT%;%PATH%;%SQLITE_ROOT%\bin;%POSTGRESQL_ROOT%\bin;%MYSQL_DIR%\bin;%MYSQL_DIR%\lib
- echo %PATH%
- cmake --version
- set PGUSER=postgres
- set PGPASSWORD=Password12!
- createdb soci_test
- set MYSQL_PWD=Password12!
- set USER=root
- mysql -e "create database soci_test;" --user=root
- sqlcmd -U sa -P Password12! -S (local)\SQL2014 -i C:\projects\soci\scripts\windows\mssql_db_create.sql
- cmake .. -G"%G%" -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_INSTALL_PREFIX=C:\projects\sqlite\sqlite
- cmake --build . --config %CONFIGURATION% --target install
build_script:
- cd C:\projects\soci
- mkdir build
- cd build
- cmake .. -G"%G%" -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_VERBOSE_MAKEFILE=ON
- cmake --build . --config %CONFIGURATION% --clean-first
test_script:
- ctest -V --output-on-failure -R "soci_empty|soci_postgresql|soci_sqlite3|soci_odbc_test_mssql|soci_mysql|soci_odbc_test_mysql|soci_odbc_test_postgresql"
notifications:
- provider: Webhook
url: https://webhooks.gitter.im/e/2038138a652d952f9372
on_build_success: true
on_build_failure: true
on_build_status_changed: true

View File

@@ -1,123 +0,0 @@
#!/bin/bash
# Script performs non-interactive installation of Oracle XE 10g on Debian
#
# Based on oracle10g-update.sh from HTSQL project:
# https://bitbucket.org/prometheus/htsql
#
# Modified by Mateusz Loskot <mateusz@loskot.net>
# 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 <butkovic@gmail.com> 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
#
# 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
}
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 <<EOF > /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 <<END
8080
1521
admin
admin
y
END
# 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
# Increase the number of connections.
echo "ALTER SYSTEM SET PROCESSES=200 SCOPE=SPFILE;" | \
sqlplus -S -L sys/admin AS SYSDBA
# need to restart, to apply connection number update
sudo /etc/init.d/oracle-xe restart
# Set Oracle environment variables on login.
# NOTE, mloskot: On Travis CI, fails with Permission denied
#sudo cat <<END >>/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

View File

@@ -1,14 +0,0 @@
# Definitions used by SOCI when building Oracle backend at travis-ci.org
#
# Copyright (c) 2015 Vadim Zeitlin <vz-soci@zeitlins.org>
#
# 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

View File

@@ -1,47 +0,0 @@
#!/bin/bash -e
# Builds and tests SOCI backend PostgreSQL at travis-ci.org
#
# Copyright (C) 2014 Vadim Zeitlin
# Copyright (C) 2015 Mateusz Loskot <mateusz@loskot.net>
#
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

View File

@@ -22,7 +22,6 @@ macro(soci_backend_deps_found NAME DEPS SUCCESS)
# Determine required dependencies
set(DEPS_INCLUDE_DIRS)
set(DEPS_LIBRARIES)
set(DEPS_DEFS)
set(DEPS_NOT_FOUND)
# CMake 2.8+ syntax only:
@@ -33,10 +32,13 @@ macro(soci_backend_deps_found NAME DEPS SUCCESS)
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})
if( ${DEPU}_INCLUDE_DIR )
list(APPEND DEPS_INCLUDE_DIRS ${${DEPU}_INCLUDE_DIR})
endif()
if( ${DEPU}_INCLUDE_DIRS )
list(APPEND DEPS_INCLUDE_DIRS ${${DEPU}_INCLUDE_DIRS})
endif()
list(APPEND DEPS_LIBRARIES ${${DEPU}_LIBRARIES})
list(APPEND DEPS_DEFS HAVE_${DEPU}=1)
endif()
endforeach()
@@ -47,7 +49,6 @@ macro(soci_backend_deps_found NAME DEPS SUCCESS)
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()
@@ -83,8 +84,7 @@ macro(soci_backend NAME)
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:")
colormsg(_RED_ "WARNING: Some required dependencies of ${NAME} backend not found:")
if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} LESS 2.8)
foreach(dep ${DEPENDS_NOT_FOUND})
@@ -214,18 +214,23 @@ macro(soci_backend NAME)
if (SOCI_SHARED)
install(TARGETS ${THIS_BACKEND_TARGET}
RUNTIME DESTINATION ${BINDIR}
LIBRARY DESTINATION ${LIBDIR}
ARCHIVE DESTINATION ${LIBDIR})
EXPORT SOCI
RUNTIME DESTINATION ${BINDIR}
LIBRARY DESTINATION ${LIBDIR}
ARCHIVE DESTINATION ${LIBDIR})
endif()
if (SOCI_SHARED)
if (SOCI_STATIC)
install(TARGETS ${THIS_BACKEND_TARGET_STATIC}
RUNTIME DESTINATION ${BINDIR}
LIBRARY DESTINATION ${LIBDIR}
ARCHIVE DESTINATION ${LIBDIR})
EXPORT SOCI
RUNTIME DESTINATION ${BINDIR}
LIBRARY DESTINATION ${LIBDIR}
ARCHIVE DESTINATION ${LIBDIR}
)
endif()
install(EXPORT SOCI NAMESPACE SOCI:: DESTINATION cmake)
else()
colormsg(HIRED "${NAME}" RED "backend disabled, since")
endif()
@@ -320,8 +325,7 @@ macro(soci_backend_test)
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")
colormsg(_RED_ "WARNING: Some dependencies of ${THIS_TEST_BACKEND} test not found")
endif()
set(TEST_CONNSTR_VAR ${TEST_FULL_NAME}_CONNSTR)
@@ -330,8 +334,13 @@ macro(soci_backend_test)
if(NOT ${TEST_CONNSTR_VAR} AND THIS_TEST_CONNSTR)
set(${TEST_CONNSTR_VAR} ${THIS_TEST_CONNSTR})
if(${TEST_CONNSTR_VAR} MATCHES ".dsn")
set(_dsnpath "${CMAKE_CURRENT_SOURCE_DIR}/${${TEST_CONNSTR_VAR}}")
set(${TEST_CONNSTR_VAR} "FILEDSN=${_dsnpath}")
endif()
endif()
boost_report_value(${TEST_CONNSTR_VAR})
boost_message_value(${TEST_CONNSTR_VAR})
if( SOCI_SHARED )
# Shared libraries test
@@ -362,8 +371,8 @@ macro(soci_backend_test)
target_link_libraries(${TEST_TARGET_STATIC}
${SOCI_CORE_DEPS_LIBS}
${THIS_TEST_DEPENDS_LIBRARIES}
soci_core_static
soci_${BACKENDL}_static)
soci_${BACKENDL}_static
soci_core_static)
add_test(${TEST_TARGET_STATIC}
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TEST_TARGET_STATIC}
@@ -375,7 +384,7 @@ macro(soci_backend_test)
add_dependencies(check ${TEST_TARGET_STATIC})
endif(SOCI_STATIC)
# Group source files for IDE source explorers (e.g. Visual Studio)
source_group("Source Files" FILES ${THIS_TEST_SOURCE})

View File

@@ -23,47 +23,71 @@ else(WIN32)
check_cxx_symbol_exists("__arm__" "" SOCI_TARGET_ARCH_ARM)
endif(WIN32)
if(NOT DEFINED LIB_SUFFIX)
if(SOCI_TARGET_ARCH_X64)
set(_lib_suffix "64")
else()
set(_lib_suffix "")
endif()
set(LIB_SUFFIX ${_lib_suffix} CACHE STRING "Specifies suffix for the lib directory")
endif()
#
# C++11 Option
#
set (SOCI_CXX_C11 OFF CACHE BOOL "Build to the C++11 standard")
if(NOT SOCI_CXX_C11)
set (SOCI_CXX_C11 OFF CACHE BOOL "Build to the C++11 standard")
endif()
#
# Force compilation flags and set desired warnings level
#
if (MSVC)
if (MSVC80 OR MSVC90 OR MSVC10)
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_CRT_NONSTDC_NO_WARNING)
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
endif()
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_CRT_NONSTDC_NO_WARNING)
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
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")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /we4266")
endif()
else()
set(SOCI_GCC_CLANG_COMMON_FLAGS
"-pedantic -Werror -Wall -Wpointer-arith -Wcast-align -Wcast-qual -Wfloat-equal -Wredundant-decls -Wno-long-long")
"-pedantic -Werror -Wno-error=parentheses -Wall -Wextra -Wpointer-arith -Wcast-align -Wcast-qual -Wfloat-equal -Woverloaded-virtual -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)
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_CXX_COMPILER}" MATCHES "clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC ${SOCI_GCC_CLANG_COMMON_FLAGS} ${SOCI_CXX_VERSION_FLAGS} ")
if(NOT CMAKE_CXX_COMPILER_VERSION LESS 3.1 AND SOCI_ASAN)
set(SOCI_GCC_CLANG_COMMON_FLAGS "${SOCI_GCC_CLANG_COMMON_FLAGS} -fsanitize=address")
endif()
# enforce C++11 for Clang
set(SOCI_CXX_C11 ON)
set(SOCI_CXX_VERSION_FLAGS "-std=c++11")
add_definitions(-DCATCH_CONFIG_CPP11_NO_IS_ENUM)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SOCI_GCC_CLANG_COMMON_FLAGS} ${SOCI_CXX_VERSION_FLAGS}")
elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
if(NOT CMAKE_CXX_COMPILER_VERSION LESS 4.8 AND SOCI_ASAN)
set(SOCI_GCC_CLANG_COMMON_FLAGS "${SOCI_GCC_CLANG_COMMON_FLAGS} -fsanitize=address")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${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}")
@@ -72,12 +96,11 @@ else()
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} ${SOCI_CXX_VERSION_FLAGS}")
else()
message(WARNING "Unknown toolset - using default flags to build SOCI")
endif()
endif()
# Set SOCI_HAVE_* variables for soci-config.h generator
set(SOCI_HAVE_CXX_C11 ${SOCI_CXX_C11} CACHE INTERNAL "Enables C++11 support")

View File

@@ -44,24 +44,22 @@ colormsg(_HIBLUE_ "Looking for SOCI dependencies:")
macro(boost_external_report NAME)
set(VARNAME ${NAME})
set(SUCCESS ${${VARNAME}_FOUND})
string(TOUPPER ${NAME} VARNAMEU)
set(VARNAMES ${ARGV})
list(REMOVE_AT VARNAMES 0)
# Test both, given original name and uppercase version too
if(NOT SUCCESS)
string(TOUPPER ${NAME} VARNAME)
set(SUCCESS ${${VARNAME}_FOUND})
if(NOT SUCCESS)
colormsg(_RED_ "WARNING:")
colormsg(RED "${NAME} not found, some libraries or features will be disabled.")
colormsg(RED "See the documentation for ${NAME} or manually set these variables:")
endif()
if(NOT ${VARNAME}_FOUND AND NOT ${VARNAMEU}_FOUND)
colormsg(_RED_ "WARNING: ${NAME} libraries not found, some features will be disabled.")
endif()
foreach(variable ${VARNAMES})
boost_report_value(${VARNAME}_${variable})
if(${VARNAMEU}_FOUND)
boost_report_value(${VARNAMEU}_${variable})
elseif(${VARNAME}_FOUND)
boost_report_value(${VARNAME}_${variable})
endif()
endforeach()
endmacro()

View File

@@ -301,6 +301,14 @@ function(boost_report_value NAME)
colormsg("${NAME}${varpadding} = ${${NAME}}")
endfunction()
function(boost_message_value NAME)
string(LENGTH "${NAME}" varlen)
math(EXPR padding_len 40-${varlen})
string(SUBSTRING " "
0 ${padding_len} varpadding)
message(STATUS "${NAME}${varpadding} = ${${NAME}}")
endfunction()
function(trace NAME)
if(BOOST_CMAKE_TRACE)
string(LENGTH "${NAME}" varlen)

View File

@@ -20,14 +20,19 @@
# MAJOR.MINOR version is used to set SOVERSION
#
macro(soci_version)
parse_arguments(THIS_VERSION "MAJOR;MINOR;PATCH;"
""
${ARGN})
# get version from soci/version.h
file(
STRINGS
"${PROJECT_SOURCE_DIR}/include/soci/version.h"
_VERSION
REGEX
"#define SOCI_VERSION ([0-9]+)"
)
string(REGEX MATCH "([0-9]+)" _VERSION "${_VERSION}")
# Set version components
set(${PROJECT_NAME}_VERSION_MAJOR ${THIS_VERSION_MAJOR})
set(${PROJECT_NAME}_VERSION_MINOR ${THIS_VERSION_MINOR})
set(${PROJECT_NAME}_VERSION_PATCH ${THIS_VERSION_PATCH})
math(EXPR ${PROJECT_NAME}_VERSION_MAJOR "${_VERSION} / 100000")
math(EXPR ${PROJECT_NAME}_VERSION_MINOR "${_VERSION} / 100 % 1000")
math(EXPR ${PROJECT_NAME}_VERSION_PATCH "${_VERSION} % 100")
# Set VERSION string
set(${PROJECT_NAME}_VERSION

View File

@@ -1,5 +1,5 @@
[ODBC]
DRIVER=Microsoft Access Driver (*.mdb)
DRIVER=Microsoft Access Driver (*.mdb, *.accdb)
UID=admin
UserCommitSync=Yes
Threads=3
@@ -9,5 +9,5 @@ MaxScanRows=8
MaxBufferSize=2048
FIL=MS Access
DriverId=25
DefaultDir=.\
DBQ=.\soci_test.mdb
DefaultDir=@TEST_ACCESS_PATH@\tests\odbc
DBQ=@TEST_ACCESS_PATH@\tests\odbc\soci_test.mdb

View File

@@ -1,4 +1,4 @@
[ODBC]
DRIVER=MySQL
DRIVER=@MYSQL_DRIVER_NAME@
DATABASE=soci_test
OPTION=0

View File

@@ -2,4 +2,4 @@ set(PostgreSQL_FIND_QUIETLY TRUE)
find_package(PostgreSQL)
boost_external_report(PostgreSQL INCLUDE_DIR LIBRARIES VERSION)
boost_external_report(PostgreSQL INCLUDE_DIRS LIBRARIES VERSION)

View File

@@ -19,12 +19,14 @@ if(UNIX)
/opt/ibm/db2/V10.1
/opt/ibm/db2/V9.7
/opt/ibm/db2/V9.5
/opt/ibm/db2/V9.1)
/opt/ibm/db2/V9.1
/opt/ibm/clidriver
/opt/clidriver)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(DB2_LIBDIRS "lib32" "lib")
else()
set(DB2_LIBDIRS "lib64")
set(DB2_LIBDIRS "lib64" "lib")
endif()
set(DB2_FIND_INCLUDE_PATHS)
@@ -70,11 +72,15 @@ endif()
find_path(DB2_INCLUDE_DIR sqlcli1.h
$ENV{DB2_INCLUDE_DIR}
$ENV{DB2_DIR}/include
$ENV{DB2_HOME}
$ENV{IBM_DB_INCLUDE}
${DB2_FIND_INCLUDE_PATHS})
find_library(DB2_LIBRARY
NAMES db2 db2api
PATHS
$ENV{DB2LIB}
$ENV{IBM_DB_LIB}
${DB2_FIND_LIB_PATHS}
${DB2_FIND_LIB_NO_LIB})

View File

@@ -67,7 +67,7 @@ if(WIN32)
$ENV{SystemDrive}/MySQL/*/lib/opt
$ENV{ProgramW6432}/MySQL/*/lib
)
find_library(MYSQL_LIBRARIES NAMES mysqlclient libmysql
find_library(MYSQL_LIBRARIES NAMES libmysql
PATHS
${MYSQL_LIB_PATHS}
)

View File

@@ -17,21 +17,25 @@
# ODBC_LIBRARY, where to find the ODBC driver manager library.
set(ODBC_FOUND FALSE)
include(CheckIncludeFiles)
check_include_files("windows.h;sqlext.h" HAVE_SQLEXT_H)
find_path(ODBC_INCLUDE_DIR sql.h
/usr/include
/usr/include/odbc
/usr/local/include
/usr/local/include/odbc
/usr/local/odbc/include
"C:/Program Files (x86)/Windows Kits/8.0/include/um"
"C:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A/Include"
"C:/Program Files/ODBC/include"
"C:/Program Files/Microsoft SDKs/Windows/v7.0/include"
"C:/Program Files/Microsoft SDKs/Windows/v6.0a/include"
"C:/ODBC/include"
DOC "Specify the directory containing sql.h."
)
if(NOT HAVE_SQLEXT_H)
find_path(ODBC_INCLUDE_DIR sqlext.h
/usr/include
/usr/include/odbc
/usr/local/include
/usr/local/include/odbc
/usr/local/odbc/include
"C:/Program Files (x86)/Windows Kits/8.0/include/um"
"C:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A/Include"
"C:/Program Files/ODBC/include"
"C:/Program Files/Microsoft SDKs/Windows/v7.0/include"
"C:/Program Files/Microsoft SDKs/Windows/v6.0a/include"
"C:/ODBC/include"
DOC "Specify the directory containing sql.h."
)
endif()
if(MSVC)
# msvc knows where to find sdk libs
@@ -54,7 +58,7 @@ else()
endif()
if(ODBC_LIBRARY)
if(ODBC_INCLUDE_DIR)
if(ODBC_INCLUDE_DIR OR HAVE_SQLEXT_H)
set( ODBC_FOUND 1 )
endif()
endif()

View File

@@ -23,47 +23,52 @@
###############################################################################
# First check for CMAKE variable
if( NOT ORACLE_HOME )
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)
endif()
endif()
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
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
# instant client from rpm
/usr/include/oracle/*/client${LIB_SUFFIX})
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
${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
# Instant client from rpm
/usr/lib/oracle/*/client${LIB_SUFFIX}/lib)
find_library(ORACLE_OCI_LIBRARY
NAMES ${ORACLE_OCI_NAMES} PATHS ${ORACLE_LIB_DIR})
NAMES ${ORACLE_OCI_NAMES} PATHS ${ORACLE_LIB_DIR})
find_library(ORACLE_OCCI_LIBRARY
NAMES ${ORACLE_OCCI_NAMES} PATHS ${ORACLE_LIB_DIR})
NAMES ${ORACLE_OCCI_NAMES} PATHS ${ORACLE_LIB_DIR})
find_library(ORACLE_NNZ_LIBRARY
NAMES ${ORACLE_NNZ_NAMES} PATHS ${ORACLE_LIB_DIR})
NAMES ${ORACLE_NNZ_NAMES} PATHS ${ORACLE_LIB_DIR})
set(ORACLE_LIBRARY
${ORACLE_OCI_LIBRARY}
${ORACLE_OCCI_LIBRARY}
${ORACLE_NNZ_LIBRARY})
${ORACLE_OCI_LIBRARY}
${ORACLE_OCCI_LIBRARY}
${ORACLE_NNZ_LIBRARY})
if(NOT WIN32)
set(ORACLE_LIBRARY ${ORACLE_LIBRARY} ${ORACLE_CLNTSH_LIBRARY})
set(ORACLE_LIBRARY ${ORACLE_LIBRARY} ${ORACLE_CLNTSH_LIBRARY})
endif(NOT WIN32)
set(ORACLE_LIBRARIES ${ORACLE_LIBRARY})

View File

@@ -1,83 +1,176 @@
# - Find PostgreSQL
# Find the PostgreSQL includes and client library
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#.rst:
# FindPostgreSQL
# --------------
#
# Find the PostgreSQL installation.
#
# This module defines
# POSTGRESQL_INCLUDE_DIR, where to find libpq-fe.h
# POSTGRESQL_LIBRARIES, libraries needed to use PostgreSQL
# POSTGRESQL_VERSION, if found, version of PostgreSQL
# POSTGRESQL_FOUND, if false, do not try to use PostgreSQL
#
# Copyright (c) 2010, Mateusz Loskot, <mateusz@loskot.net>
# Copyright (c) 2006, Jaroslaw Staniek, <js@iidea.pl>
# ::
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# POSTGRESQL_LIBRARIES - the PostgreSQL libraries needed for linking
# POSTGRESQL_INCLUDE_DIRS - the directories of the PostgreSQL headers
# POSTGRESQL_LIBRARY_DIRS - the link directories for PostgreSQL libraries
# POSTGRESQL_VERSION_STRING - the version of PostgreSQL found (since CMake 2.8.8)
find_program(PG_CONFIG NAMES pg_config
PATHS
/usr/bin
/usr/local/bin
$ENV{ProgramFiles}/PostgreSQL/*/bin
$ENV{SystemDrive}/PostgreSQL/*/bin
DOC "Path to pg_config utility")
# ----------------------------------------------------------------------------
# History:
# This module is derived from the module originally found in the VTK source tree.
#
# ----------------------------------------------------------------------------
# Note:
# POSTGRESQL_ADDITIONAL_VERSIONS is a variable that can be used to set the
# version mumber of the implementation of PostgreSQL.
# In Windows the default installation of PostgreSQL uses that as part of the path.
# E.g C:\Program Files\PostgreSQL\8.4.
# Currently, the following version numbers are known to this module:
# "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0"
#
# To use this variable just do something like this:
# set(POSTGRESQL_ADDITIONAL_VERSIONS "9.2" "8.4.4")
# before calling find_package(PostgreSQL) in your CMakeLists.txt file.
# This will mean that the versions you set here will be found first in the order
# specified before the default ones are searched.
#
# ----------------------------------------------------------------------------
# You may need to manually set:
# POSTGRESQL_INCLUDE_DIR - the path to where the PostgreSQL include files are.
# POSTGRESQL_LIBRARY_DIR - The path to where the PostgreSQL library files are.
# If FindPostgreSQL.cmake cannot find the include files or the library files.
#
# ----------------------------------------------------------------------------
# The following variables are set if PostgreSQL is found:
# POSTGRESQL_FOUND - Set to true when PostgreSQL is found.
# POSTGRESQL_INCLUDE_DIRS - Include directories for PostgreSQL
# POSTGRESQL_LIBRARY_DIRS - Link directories for PostgreSQL libraries
# POSTGRESQL_LIBRARIES - The PostgreSQL libraries.
#
# ----------------------------------------------------------------------------
# If you have installed PostgreSQL in a non-standard location.
# (Please note that in the following comments, it is assumed that <Your Path>
# points to the root directory of the include directory of PostgreSQL.)
# Then you have three options.
# 1) After CMake runs, set POSTGRESQL_INCLUDE_DIR to <Your Path>/include and
# POSTGRESQL_LIBRARY_DIR to wherever the library pq (or libpq in windows) is
# 2) Use CMAKE_INCLUDE_PATH to set a path to <Your Path>/PostgreSQL<-version>. This will allow find_path()
# to locate POSTGRESQL_INCLUDE_DIR by utilizing the PATH_SUFFIXES option. e.g. In your CMakeLists.txt file
# set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "<Your Path>/include")
# 3) Set an environment variable called ${POSTGRESQL_ROOT} that points to the root of where you have
# installed PostgreSQL, e.g. <Your Path>.
#
# ----------------------------------------------------------------------------
if(PG_CONFIG)
exec_program(${PG_CONFIG}
ARGS "--version"
OUTPUT_VARIABLE PG_CONFIG_VERSION)
set(POSTGRESQL_INCLUDE_PATH_DESCRIPTION "top-level directory containing the PostgreSQL include directories. E.g /usr/local/include/PostgreSQL/8.4 or C:/Program Files/PostgreSQL/8.4/include")
set(POSTGRESQL_INCLUDE_DIR_MESSAGE "Set the POSTGRESQL_INCLUDE_DIR cmake cache entry to the ${POSTGRESQL_INCLUDE_PATH_DESCRIPTION}")
set(POSTGRESQL_LIBRARY_PATH_DESCRIPTION "top-level directory containing the PostgreSQL libraries.")
set(POSTGRESQL_LIBRARY_DIR_MESSAGE "Set the POSTGRESQL_LIBRARY_DIR cmake cache entry to the ${POSTGRESQL_LIBRARY_PATH_DESCRIPTION}")
set(POSTGRESQL_ROOT_DIR_MESSAGE "Set the POSTGRESQL_ROOT system variable to where PostgreSQL is found on the machine E.g C:/Program Files/PostgreSQL/8.4")
if(${PG_CONFIG_VERSION} MATCHES "^[A-Za-z]+[ ](.*)$")
string(REGEX REPLACE "^[A-Za-z]+[ ](.*)$" "\\1" POSTGRESQL_VERSION "${PG_CONFIG_VERSION}")
set(POSTGRESQL_KNOWN_VERSIONS ${POSTGRESQL_ADDITIONAL_VERSIONS}
"9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0")
# Define additional search paths for root directories.
set( POSTGRESQL_ROOT_DIRECTORIES
ENV POSTGRESQL_ROOT
${POSTGRESQL_ROOT}
)
foreach(suffix ${POSTGRESQL_KNOWN_VERSIONS})
if(WIN32)
list(APPEND POSTGRESQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES
"PostgreSQL/${suffix}/lib")
list(APPEND POSTGRESQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES
"PostgreSQL/${suffix}/include")
list(APPEND POSTGRESQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES
"PostgreSQL/${suffix}/include/server")
endif()
if(UNIX)
list(APPEND POSTGRESQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES
"pgsql-${suffix}/lib")
list(APPEND POSTGRESQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES
"pgsql-${suffix}/include")
list(APPEND POSTGRESQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES
"postgresql/${suffix}/server"
"pgsql-${suffix}/include/server")
endif()
endforeach()
exec_program(${PG_CONFIG}
ARGS "--includedir"
OUTPUT_VARIABLE PG_CONFIG_INCLUDEDIR)
exec_program(${PG_CONFIG}
ARGS "--libdir"
OUTPUT_VARIABLE PG_CONFIG_LIBDIR)
else()
set(POSTGRESQL_VERSION "unknown")
endif()
find_path(POSTGRESQL_INCLUDE_DIR libpq-fe.h
${PG_CONFIG_INCLUDEDIR}
/usr/include/server
/usr/include/pgsql/server
/usr/local/include/pgsql/server
/usr/include/postgresql
/usr/include/postgresql/server
/usr/include/postgresql/*/server
$ENV{ProgramFiles}/PostgreSQL/*/include
$ENV{SystemDrive}/PostgreSQL/*/include)
find_library(POSTGRESQL_LIBRARIES NAMES pq libpq
#
# Look for an installation.
#
find_path(POSTGRESQL_INCLUDE_DIR
NAMES libpq-fe.h
PATHS
${PG_CONFIG_LIBDIR}
/usr/lib
/usr/local/lib
/usr/lib/postgresql
/usr/lib64
/usr/local/lib64
/usr/lib64/postgresql
$ENV{ProgramFiles}/PostgreSQL/*/lib
$ENV{SystemDrive}/PostgreSQL/*/lib
$ENV{ProgramFiles}/PostgreSQL/*/lib/ms
$ENV{SystemDrive}/PostgreSQL/*/lib/ms)
# Look in other places.
${POSTGRESQL_ROOT_DIRECTORIES}
PATH_SUFFIXES
pgsql
postgresql
include
${POSTGRESQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES}
# Help the user find it if we cannot.
DOC "The ${POSTGRESQL_INCLUDE_DIR_MESSAGE}"
)
if(POSTGRESQL_INCLUDE_DIR AND POSTGRESQL_LIBRARIES)
set(POSTGRESQL_FOUND TRUE)
else()
set(POSTGRESQL_FOUND FALSE)
# The PostgreSQL library.
set (POSTGRESQL_LIBRARY_TO_FIND pq)
# Setting some more prefixes for the library
set (POSTGRESQL_LIB_PREFIX "")
if ( WIN32 )
set (POSTGRESQL_LIB_PREFIX ${POSTGRESQL_LIB_PREFIX} "lib")
set (POSTGRESQL_LIBRARY_TO_FIND ${POSTGRESQL_LIB_PREFIX}${POSTGRESQL_LIBRARY_TO_FIND})
endif()
# Handle the QUIETLY and REQUIRED arguments and set POSTGRESQL_FOUND to TRUE
# if all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PostgreSQL
DEFAULT_MSG
POSTGRESQL_INCLUDE_DIR
POSTGRESQL_LIBRARIES
POSTGRESQL_VERSION)
find_library(POSTGRESQL_LIBRARY
NAMES ${POSTGRESQL_LIBRARY_TO_FIND}
PATHS
${POSTGRESQL_ROOT_DIRECTORIES}
PATH_SUFFIXES
lib
${POSTGRESQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES}
# Help the user find it if we cannot.
DOC "The ${POSTGRESQL_LIBRARY_DIR_MESSAGE}"
)
get_filename_component(POSTGRESQL_LIBRARY_DIR ${POSTGRESQL_LIBRARY} PATH)
mark_as_advanced(POSTGRESQL_INCLUDE_DIR POSTGRESQL_LIBRARIES)
if (POSTGRESQL_INCLUDE_DIR)
# Some platforms include multiple pg_config.hs for multi-lib configurations
# This is a temporary workaround. A better solution would be to compile
# a dummy c file and extract the value of the symbol.
file(GLOB _PG_CONFIG_HEADERS "${POSTGRESQL_INCLUDE_DIR}/pg_config*.h")
foreach(_PG_CONFIG_HEADER ${_PG_CONFIG_HEADERS})
if(EXISTS "${_PG_CONFIG_HEADER}")
file(STRINGS "${_PG_CONFIG_HEADER}" pgsql_version_str
REGEX "^#define[\t ]+PG_VERSION[\t ]+\".*\"")
if(pgsql_version_str)
string(REGEX REPLACE "^#define[\t ]+PG_VERSION[\t ]+\"([^\"]*)\".*"
"\\1" POSTGRESQL_VERSION_STRING "${pgsql_version_str}")
break()
endif()
endif()
endforeach()
unset(pgsql_version_str)
endif()
# Did we find anything?
# <SOCI>
#include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
include(FindPackageHandleStandardArgs)
# </SOCI>
find_package_handle_standard_args(PostgreSQL
REQUIRED_VARS POSTGRESQL_LIBRARY POSTGRESQL_INCLUDE_DIR
VERSION_VAR POSTGRESQL_VERSION_STRING)
set(POSTGRESQL_FOUND ${POSTGRESQL_FOUND})
# Now try to get the include and library path.
if(POSTGRESQL_FOUND)
set(POSTGRESQL_INCLUDE_DIRS ${POSTGRESQL_INCLUDE_DIR})
set(POSTGRESQL_LIBRARY_DIRS ${POSTGRESQL_LIBRARY_DIR})
set(POSTGRESQL_LIBRARIES ${POSTGRESQL_LIBRARY})
set(POSTGRESQL_VERSION ${POSTGRESQL_VERSION_STRING})
endif()
mark_as_advanced(POSTGRESQL_INCLUDE_DIR POSTGRESQL_LIBRARY)

View File

@@ -1,177 +1,207 @@
## Backends reference
# 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.
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 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 of function 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.
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.
```cpp
// 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
};
// 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 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
};
// 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) {}
struct cstring_descriptor
{
cstring_descriptor(char * str, std::size_t bufSize)
: str_(str), bufSize_(bufSize) {}
char * str_;
std::size_t 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);
};
```
// 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 `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 `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 `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 `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 `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.
```cpp
class standard_into_type_backend
{
public:
standard_into_type_backend() {}
virtual ~standard_into_type_backend() {}
class standard_into_type_backend
{
public:
standard_into_type_backend() {}
virtual ~standard_into_type_backend() {}
virtual void define_by_pos(int& position, void* data, exchange_type type) = 0;
virtual void 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 pre_fetch() = 0;
virtual void post_fetch(bool gotData, bool calledFromFetch, indicator* ind) = 0;
virtual void clean_up() = 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.
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.
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() {}
```cpp
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 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 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 resize(std::size_t sz) = 0;
virtual std::size_t size() = 0;
virtual void clean_up() = 0;
};
virtual void clean_up() = 0;
};
```
The `vector_into_type_back_end` has similar structure and purpose as the previous one, but is used for vectors (bulk data retrieval).
The `data` pointer points to the variable of type `std::vector<T>;` (and *not* to its internal buffer), `resize` is supposed to really resize the user-provided vector and `size`
is supposed to return the current size of this vector. The important difference with regard to the previous class is that `ind` points (if not `NULL`) to the beginning of the *array* of indicators. The backend should fill this array according to the actual state of the retrieved data.
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.
* `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.
* `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.
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
```cpp
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.
```cpp
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
{
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;
ef_success,
ef_no_data
};
virtual exec_fetch_result execute(int number) = 0;
virtual exec_fetch_result fetch(int number) = 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.
virtual long long get_affected_rows() = 0;
virtual int get_number_of_rows() = 0;
class statement_backend
{
public:
statement_backend() {}
virtual ~statement_backend() {}
virtual std::string rewrite_for_procedure_call(std::string const& query) = 0;
virtual void alloc() = 0;
virtual void clean_up() = 0;
virtual int prepare_for_describe() = 0;
virtual void describe_column(int colNum, data_type& dtype,
std::string& column_name) = 0;
virtual void prepare(std::string const& query, statement_type eType) = 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;
};
```
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.
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.
@@ -185,53 +215,59 @@ The `statement_backend` type implements the internals of the `statement` objects
* `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
**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() {}
};
```cpp
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() {}
```cpp
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;
};
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() {}
```cpp
class session_backend
{
public:
virtual ~session_backend() {}
virtual void begin() = 0;
virtual void commit() = 0;
virtual void rollback() = 0;
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 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 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;
};
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.
@@ -239,13 +275,15 @@ The object of the class derived from `session_backend` implements the internals
* `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() {}
```cpp
struct backend_factory
{
virtual ~backend_factory() {}
virtual details::session_backend * make_session(
std::string const& connectString) const = 0;
};
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).
@@ -253,21 +291,23 @@ The actual backend factory object is supposed to be provided by the backend impl
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;
```cpp
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"
{
extern "C"
{
// for dynamic backend loading
backend_factory const * factory_postgresql();
// for dynamic backend loading
backend_factory const * factory_postgresql();
} // extern "C"
} // 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.
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.

File diff suppressed because it is too large Load Diff

View File

@@ -1,90 +1,93 @@
## DB2 Backend Reference
# 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)
SOCI backend for accessing IBM DB2 database.
### <a name="prerequisites"></a> Prerequisites
#### <a name="versions"></a> Supported Versions
## Prerequisites
The SOCI DB2 backend.
### Supported Versions
#### <a name="platforms"></a> Tested Platforms
See [Tested Platforms](#tested-platforms).
<table>
<tbody>
<tr><th>DB2 version</th><th>Operating System</th><th>Compiler</th></tr>
<tr><td>-</td><td>Linux PPC64</td><td>GCC</td></tr>
<tr><td>9.1</td><td>Linux</td><td>GCC</td></tr>
<tr><td>9.5</td><td>Linux</td><td>GCC</td></tr>
<tr><td>9.7</td><td>Linux</td><td>GCC</td></tr>
<tr><td>10.1</td><td>Linux</td><td>GCC</td></tr>
<tr><td>10.1</td><td>Windows 8</td><td>Visual Studio 2012</td></tr>
</tbody>
</table>
### Tested Platforms
#### <a name="required"></a> Required Client Libraries
|DB2 |OS|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|
The SOCI DB2 backend requires IBM DB2 Call Level Interface (CLI) library.
### Required Client Libraries
#### <a name="connecting"></a> Connecting to the Database
The SOCI DB2 backend requires client library from the [IBM Data Server Driver Package (DS Driver)](https://www-01.ibm.com/support/docview.wss?uid=swg21385217).
## 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
```console
. ~/db2inst1/sqllib/db2profile
```
To establish a connection to the DB2 database, create a session object using the <code>DB2</code> backend factory together with the database file name:
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");
```cpp
soci::session sql(soci::db2, "your DB2 connection string here");
```
### <a name="features"></a> SOCI Feature Support
## SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### Dynamic Binding
TODO
#### <a name="bulk"></a> Bulk Operations
### Bulk Operations
Supported, but with caution as it hasn't been extensively tested.
#### <a name="transactions"></a> Transactions
### Transactions
Currently, not supported.
#### <a name="blob"></a> BLOB Data Type
### BLOB Data Type
Currently, not supported.
#### <a name="nested"></a> Nested Statements
### Nested Statements
Nesting statements are not processed by SOCI in any special way and they work as implemented by the DB2 database.
Nesting statements are not processed by SOCI in any special way and they work as implemented
by the DB2 database.
#### <a name="stored"></a> Stored Procedures
### Stored Procedures
Stored procedures are supported, with <code>CALL</code> statement.
Stored procedures are supported, with `CALL` statement.
### <a name="native"></a> Acessing the native database API
## Native API Access
TODO
### <a name="backend"></a> Backend-specific extensions
## Backend-specific extensions
None.
### <a name="config"></a> Configuration options
## Configuration options
None.
This backend supports `db2_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:
```cpp
connection_parameters parameters("db2", "DSN=sample");
parameters.set_option(db2_option_driver_complete, "0" /* SQL_DRIVER_NOPROMPT */);
session sql(parameters);
```
Note, `db2_option_driver_complete` controls driver completion specific to the IBM DB2 driver
for ODBC and CLI.

View File

@@ -1,58 +1,45 @@
## Firebird Backend Reference
# 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)
SOCI backend for accessing Firebird database.
### <a name="prerequisites"></a> Prerequisites
## Prerequisites
#### <a name="versions"></a> Supported Versions
### 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 <tt>SOCI_FIREBIRD_EMBEDDED</tt> CMake option to <tt>ON</tt> value when building.
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.
#### <a name="tested"></a> Tested Platforms
### Tested Platforms
<table>
<tbody>
<tr><th>Firebird version</th><th>Operating System</th><th>Compiler</th></tr>
<tr><td>1.5.2.4731</td><td>SunOS 5.10</td><td>g++ 3.4.3</td></tr>
<tr><td>1.5.2.4731</td><td>Windows XP</td><td>Visual C++ 8.0</td></tr>
<tr><td>1.5.3.4870</td><td>Windows XP</td><td>Visual C++ 8.0 Professional</td></tr>
<tr><td>2.5.2.26540</td><td>Debian GNU/Linux 7</td><td>g++ 4.7.2</td></tr>
</tbody>
</table>
|Firebird |OS|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|
#### <a name="required"></a> Required Client Libraries
### Required Client Libraries
The Firebird backend requires Firebird's `libfbclient` client library.
For example, on Ubuntu Linux, for example, `firebird-dev` package and its dependencies are required.
### <a name="connecting"></a> Connecting to the Database
## 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:
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");
```cpp
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");
```cpp
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:
@@ -62,139 +49,106 @@ The set of parameters used in the connection string for Firebird is:
* role
* charset
The following parameters have to be provided as part of the connection string : *service*, *user*, *password*. Role and charset parameters are optional.
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:
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);
```cpp
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.)
(See the [SOCI basics](../basics.html) and [exchanging data](../exchange.html) documentation
for general information on using the `session` class.)
## SOCI Feature Support
### <a name="features"></a> SOCI Feature Support
### Dynamic Binding
#### <a name="dynamic"></a> 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.
The Firebird backend supports the use of the SOCI `Row` class, which facilitates retrieval of data whose type is not known at compile time.
When calling `row::get<T>()`, the type you should pass as T depends upon the underlying database type.
For the Firebird backend, this type mapping is:
When calling `Row::get<T>()`, the type you should pass as T depends upon the underlying database type. For the Firebird backend, this type mapping is:
|Firebird Data Type|SOCI Data Type|`row::get<T>` specializations|
|--- |--- |--- |
|numeric, decimal (where scale > 0)|eDouble|double|
|numeric, decimal [^1] (where scale = 0)|eInteger, eDouble|int, double|
|double precision, float|eDouble|double|
|smallint, integer|eInteger|int|
|char, varchar|eString|std::string|
|date, time, timestamp|eDate|std::tm|
<table>
<tbody>
<tr>
<th>Firebird Data Type</th>
<th>SOCI Data Type</th>
<th><code>Row::get&lt;T&gt;</code> specializations</th>
</tr>
<tr>
<td>numeric, decimal <br />*(where scale &gt; 0)*</td>
<td><code>eDouble</code></td>
<td><code>double</code></td>
</tr>
<tr>
<td>numeric, decimal <sup>[<a href="#note1">1</a>]</sup><br />*(where scale = 0)*</td>
<td><code>eInteger, eDouble</code></td>
<td><code>int, double</code></td>
</tr>
<tr>
<td>double precision, float</td>
<td><code>eDouble</code></td>
<td><code>double</code></td>
</tr>
<tr>
<td>smallint, integer</td>
<td><code>eInteger</code></td>
<td><code>int</code></td>
</tr>
<tr>
<td>char, varchar</td>
<td><code>eString</code></td>
<td><code>std::string</code></td>
</tr>
<tr>
<td>date, time, timestamp</td>
<td><code>eDate</code></td>
<td><code>std::tm</code></code></code></td>
</tr>
</tbody>
</table>
<a name="note1" />&nbsp;<sup>[1]</sup> &nbsp;There is also 64bit integer type for larger values which 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.)
(See the [dynamic resultset binding](../exchange.html#dynamic) documentation for general information
on using the `Row` class.)
### Binding by Name
#### <a name="binding"></a> 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:
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.
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.
#### <a name="bulk"></a> Bulk Operations
### Bulk Operations
The Firebird backend has full support for SOCI's [bulk operations](../statements.html#bulk) interface. This feature is also supported by emulation.
The Firebird backend has full support for SOCI [bulk operations](../statements.html#bulk) interface.
This feature is also supported by emulation.
#### <a name="transactions"></a> Transactions
### 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 <tt>begin()</tt> before. The current transaction is automatically committed in `Session's` destructor.
[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` destructor.
#### <a name="blob"></a> BLOB Data Type
### BLOB Data Type
The Firebird backend supports working with data stored in columns of type Blob, via SOCI's `[BLOB](../exchange.html#blob)` class.
The Firebird backend supports working with data stored in columns of type Blob,
via SOCI `[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.
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.
#### <a name="rowid"></a> RowID Data Type
### RowID Data Type
This feature is not supported by Firebird backend.
#### <a name="nested"></a> Nested Statements
### Nested Statements
This feature is not supported by Firebird backend.
#### <a name="stored"></a> Stored Procedures
### Stored Procedures
Firebird stored procedures can be executed by using SOCI's [Procedure](../statements.html#procedures) class.
Firebird stored procedures can be executed by using SOCI [Procedure](../statements.html#procedures) class.
## Native API Access
### <a name="native"></a> 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.
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:
<table>
<tbody>
<tr>
<th>Accessor Function</th>
<th>Concrete Class</th>
</tr>
<tr>
<td><code>SessionBackEnd* Session::getBackEnd()</code></td>
<td><code>FirebirdSessionBackEnd</code></td>
</tr>
<tr>
<td><code>StatementBackEnd* Statement::getBackEnd()</code></td>
<td><code>FirebirdStatementBackEnd</code></td>
</tr>
<tr>
<td><code>BLOBBackEnd* BLOB::getBackEnd()</code></td>
<td><code>FirebirdBLOBBackEnd</code></td>
</tr>
<tr>
<td><code>RowIDBackEnd* RowID::getBackEnd()</code></td>
<td<>code>FirebirdRowIDBackEnd</code></td>
</tr>
</tbody>
</table>
|Accessor Function|Concrete Class|
|--- |--- |
|SessionBackEnd* Session::getBackEnd()|FirebirdSessionBackEnd|
|StatementBackEnd* Statement::getBackEnd()|FirebirdStatementBackEnd|
|BLOBBackEnd* BLOB::getBackEnd()|FirebirdBLOBBackEnd|
|RowIDBackEnd* RowID::getBackEnd()|
### <a name="extensions"></a> Backend-specific extensions
## Backend-specific extensions
#### <a name="firebirdsocierror"></a> FirebirdSOCIError
### 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.
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.

View File

@@ -1,101 +1,14 @@
## Existing backends and supported platforms
# Supported Backends and Features
### Supported Features
Follow the links to learn more about each backend and detailed supported features.
(Follow the links to learn more about each backend.)
<table>
<tbody>
<tr>
<th></th>
<th><a href="oracle.html">Oracle</a></th>
<th><a href="postgresql.html">PostgreSQL</a></th>
<th><a href="mysql.html">MySQL</a></th>
<th><a href="sqlite3.html">SQLite3</a></th>
<th><a href="firebird.html">Firebird</a></th>
<th><a href="odbc.html">ODBC</a></th>
<th><a href="db2.html">DB2</a></th>
</tr>
<tr>
<td>Binding by Name</td>
<td>YES</td>
<td><a href="postgresql.html#bindingbyname">YES (>=8.0)</a></td>
<td><a href="mysql.html#bindingbyname">YES</a></td>
<td>YES</td>
<td><a href="firebird.html#bindingbyname">YES</a></td>
<td>YES</td>
<td>YES</td>
</tr>
<tr>
<td>Dynamic Binding</td>
<td><a href="oracle.html#dynamic">YES</a></td>
<td><a href="postgresql.html#dynamic">YES</a></td>
<td><a href="mysql.html#dynamic">YES</a></td>
<td>YES</td>
<td>YES</td>
<td>YES</td>
<td></td>
</tr>
<tr>
<td>Bulk Operations</td>
<td>YES</td>
<td>YES</td>
<td>YES</td>
<td>YES</td>
<td><a href="firebird.html#bulk">YES</a></td>
<td>YES</td>
<td>YES</td>
</tr>
<tr>
<td>Transactions</td>
<td>YES</td>
<td>YES</td>
<td><a href="mysql.html#transactions">YES</a>
(with servers that support them, usually >=&nbsp;4.0)</td>
<td>YES</td>
<td><a href="firebird.html#transactions">YES</a></td>
<td>YES</td>
<td>YES</td>
</tr>
<tr>
<td>BLOB Data Type</td>
<td>YES</td>
<td><a href="postgresql.html#blob">YES</a></td>
<td>MySQL's BLOB type is mapped to <code>std::string</code></td>
<td>YES</td>
<td><a href="firebird.html#blob">YES</a></td>
<td>NO</td>
<td>NO</td>
</tr>
<tr>
<td>RowID Data Type</td>
<td>YES</td>
<td>YES</td>
<td>NO</td>
<td>NO</td>
<td>NO</td>
<td>NO</td>
<td>NO</td>
</tr>
<tr>
<td>Nested Statements</td>
<td>YES</td>
<td>NO</td>
<td>NO</td>
<td>NO</td>
<td>NO</td>
<td>NO</td>
<td>YES</td>
</tr>
<tr>
<td>Stored Procedures</td>
<td>YES</td>
<td>YES</td>
<td><a href="mysql.html#procedures">NO (but stored functions, YES)</a></td>
<td>NO</td>
<td>YES</td>
<td>NO</td>
<td>YES</td>
</tr>
</tbody>
</table>
|Oracle|PostgreSQL|MySQL|SQLite3|Firebird|ODBC|DB2|
|--- |--- |--- |--- |--- |--- |--- |
|Binding by Name|YES|YES (>=8.0)|YES|YES|YES|YES|YES|
|Dynamic Binding|YES|YES|YES|YES|YES|YES|
|Bulk Operations|YES|YES|YES|YES|YES|YES|YES|
|Transactions|YES|YES|YES (>=4.0)|YES|YES|YES|YES|
|BLOB Data Type|YES|YES|YES (mapped to `std::string`)|YES|YES|NO|NO|
|RowID Data Type|YES|YES|NO|NO|NO|NO|NO|
|Nested Statements|YES|NO|NO|NO|NO|NO|YES|
|Stored Procedures|YES|YES|NO (but stored functions, YES)|NO|YES|NO|YES|

View File

@@ -1,53 +1,31 @@
## MySQL Backend Reference
# 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)
SOCI backend for accessing MySQL database.
## Prerequisites
### Supported Versions
### <a name="prerequisites"></a> Prerequisites
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.
#### <a name="versions"></a> Supported Versions
### Tested Platforms
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.
|MySQL|OS|Compiler|
|--- |--- |--- |
|8.0.1|Windows 10|Visual Studio 2017 (15.3.3)|
|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)|
#### <a name="tested"></a> Tested Platforms
### Required Client Libraries
<table>
<tbody>
<tr><th>MySQL version</th><th>Operating System</th><th>Compiler</th></tr>
<tr><td>5.5.28</td><td>OS X 10.8.2</td><td>Apple LLVM version 4.2
(clang-425.0.24)</td></tr>
<tr><td>5.0.96</td><td>Ubuntu 8.04.4 LTS (Hardy Heron)</td>
<td>g++ (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu4)</td>
</tr>
</tbody>
</table>
#### <a name="required"></a> Required Client Libraries
The SOCI MySQL backend requires MySQL's `libmysqlclient` client library.
The SOCI MySQL backend requires MySQL's `libmysqlclient` client library from the [MySQL Connector/C](https://dev.mysql.com/downloads/connector/c/).
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
### <a name="connecting"></a> Connecting to the Database
## 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:
@@ -77,69 +55,30 @@ Once you have created a `session` object as shown above, you can use it to acces
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
### <a name="support"></a> SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### 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&lt;T&gt;()`, the type you should pass as `T` depends upon the underlying database type.
For the MySQL backend, this type mapping is:
<table>
<tbody>
<tr>
<th>MySQL Data Type</th>
<th>SOCI Data Type</th>
<th><code>row::get&lt;T&gt;</code> specializations</th>
</tr>
<tr>
<td>FLOAT, DOUBLE, DECIMAL and synonyms</td>
<td><code>dt_double</code></td>
<td><code>double</code></td>
</tr>
<tr>
<td>TINYINT, TINYINT UNSIGNED, SMALLINT, SMALLINT UNSIGNED, INT</td>
<td><code>dt_integer</code></td>
<td><code>int</code></td>
</tr>
<tr>
<td>INT UNSIGNED</td>
<td><code>dt_long_long</code></td>
<td><code>long long</code> or </code>unsigned</code></td>
</tr>
<tr>
<td>BIGINT</td>
<td><code>dt_long_long</code></td>
<td><code>long long</code></td>
</tr>
<tr>
<td>BIGINT UNSIGNED</td>
<td><code>dt_unsigned_long_long</code></td>
<td><code>unsigned long long</code></td>
</tr>
<tr>
<td>CHAR, VARCHAR, BINARY, VARBINARY, TINYBLOB, MEDIUMBLOB, BLOB,
LONGBLOB, TINYTEXT, MEDIUMTEXT, TEXT, LONGTEXT, ENUM</td>
<td><code>dt_string</code></td>
<td><code>std::string</code></td>
</tr>
<tr>
<td>TIMESTAMP (works only with MySQL >=&nbsp;5.0), DATE,
TIME, DATETIME</td>
<td><code>dt_date</code></td>
<td><code>std::tm</code></td>
</tr>
</tbody>
</table>
|MySQL Data Type|SOCI Data Type|`row::get<T>` specializations|
|--- |--- |--- |
|FLOAT, DOUBLE, DECIMAL and synonyms|dt_double|double|
|TINYINT, TINYINT UNSIGNED, SMALLINT, SMALLINT UNSIGNED, INT|dt_integer|int|
|INT UNSIGNED|dt_long_long|long long or unsigned|
|BIGINT|dt_long_long|long long|
|BIGINT UNSIGNED|dt_unsigned_long_long|unsigned long long|
|CHAR, VARCHAR, BINARY, VARBINARY, TINYBLOB, MEDIUMBLOB, BLOB,LONGBLOB, TINYTEXT, MEDIUMTEXT, TEXT, LONGTEXT, ENUM|dt_string|std::string|
|TIMESTAMP (works only with MySQL >= 5.0), DATE, TIME, DATETIME|dt_date|std::tm|
(See the [dynamic resultset binding](../exchange.html#dynamic) documentation for general information on using the `Row` class.)
#### <a name="name"></a> Binding by Name
### 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:
@@ -149,56 +88,43 @@ In addition to [binding by position](../exchange.html#bind_position), the MySQL
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.
#### <a name="bulk"></a> Bulk Operations
### 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.
#### <a name="blob"></a> BLOB Data Type
### 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.
#### <a name="rowid"></a> RowID Data Type
### RowID Data Type
The `rowid` functionality is not supported by the MySQL backend.
#### <a name="nested"></a> Nested Statements
### Nested Statements
Nested statements are not supported by the MySQL backend.
#### <a name="stored"></a> Stored Procedures
### 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.
### <a name="native"></a> Accessing the native database API
## Native API Access
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:
<table>
<tbody>
<tr>
<th>Accessor Function</th>
<th>Concrete Class</th>
</tr>
<tr>
<td><code>session_backend * session::get_backend()</code></td>
<td><code>mysql_session_backend</code></td>
</tr>
<tr>
<td><code>statement_backend * statement::get_backend()</code></td>
<td><code>mysql_statement_backend</code></td>
</tr>
</tbody>
</table>
|Accessor Function|Concrete Class|
|--- |--- |
|session_backend * session::get_backend()|mysql_session_backend|
|statement_backend * statement::get_backend()|mysql_statement_backend|
### <a name="extensions"></a> Backend-specific extensions
## Backend-specific extensions
None.
### <a name="configuration"></a> Configuration options
## Configuration options
None.
None.

View File

@@ -1,252 +1,173 @@
## ODBC Backend Reference
# 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)
SOCI backend for accessing variety of databases via ODBC API.
## Prerequisites
### <a name="prerequisites"></a> Prerequisites
#### <a name="versions"></a> Supported Versions
### Supported Versions
The SOCI ODBC backend is supported for use with ODBC 3.
#### <a name="tested"></a> Tested Platforms
### Tested Platforms
<table>
<tbody>
<tr><th>ODBC version</th><th>Operating System</th><th>Compiler</th></tr>
<tr><td>3</td><td>Linux (Ubuntu 12.04)</td><td>g++ 4.6.3</td></tr>
<tr><td>3</td><td>Linux (Ubuntu 12.04)</td><td>clang 3.2</td></tr>
<tr><td>3.8</td><td>Windows 8</td><td>Visual Studio 2012</td></tr>
<tr><td>3</td><td>Windows 7</td><td>Visual Studio 2010</td></tr>
<tr><td>3</td><td>Windows XP</td><td>Visual Studio 2005 (express)</td></tr>
<tr><td>3</td><td>Windows XP</td><td>Visual C++ 8.0 Professional</td></tr>
<tr><td>3</td><td>Windows XP</td><td>g++ 3.3.4 (Cygwin)</td></tr>
</tbody>
</table>
|ODBC|OS|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)|
#### <a name="required"></a> Required Client Libraries
### Required Client Libraries
The SOCI ODBC backend requires the ODBC client library.
### <a name="connecting"></a> Connecting to the Database
## 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&amp; backEnd = odbc;
session sql(backEnd, "filedsn=c:\\my.dsn");
```cpp
backend_factory const&amp; backEnd = odbc;
session sql(backEnd, "filedsn=c:\\my.dsn");
```
or simply:
session sql(odbc, "filedsn=c:\\my.dsn");
```cpp
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.
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);
```cpp
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.)
### <a name="support"></a> SOCI Feature Support
## SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### Dynamic Binding
The ODBC backend supports the use of the SOCI `row` class, which facilitates retrieval of data whose type is not known at compile time.
When calling `row::get<T>()`, the type you should pass as T depends upon the underlying database type.
For the ODBC backend, this type mapping is:
<table>
<tbody>
<tr>
<th>ODBC Data Type</th>
<th>SOCI Data Type</th>
<th><code>row::get&lt;T&gt;</code> specializations</th>
</tr>
<tr>
<td>SQL_DOUBLE
, SQL_DECIMAL
, SQL_REAL
, SQL_FLOAT
, SQL_NUMERIC
</td>
<td><code>dt_double</code></td>
<td><code>double</code></td>
</tr>
<tr>
<td>SQL_TINYINT
, SQL_SMALLINT
, SQL_INTEGER
, SQL_BIGINT</td>
<td><code>dt_integer</code></td>
<td><code>int</code></td>
</tr>
<tr>
<td>SQL_CHAR, SQL_VARCHAR</td>
<td><code>dt_string</code></td>
<td><code>std::string</code></td>
</tr>
<tr>
<td>SQL_TYPE_DATE
, SQL_TYPE_TIME
, SQL_TYPE_TIMESTAMP</td>
<td><code>dt_date</code></td>
<td><code>std::tm</code></code></code></td>
</tr>
</tbody>
</table>
|ODBC Data Type|SOCI Data Type|`row::get<T>` specializations|
|--- |--- |--- |
|SQL_DOUBLE, SQL_DECIMAL, SQL_REAL, SQL_FLOAT, SQL_NUMERIC|dt_double|double|
|SQL_TINYINT, SQL_SMALLINT, SQL_INTEGER, SQL_BIGINT|dt_integer|int|
|SQL_CHAR, SQL_VARCHAR|dt_string|std::string|
|SQL_TYPE_DATE, SQL_TYPE_TIME, SQL_TYPE_TIMESTAMP|dt_date|std::tm|
Not all ODBC drivers support all datatypes.
(See the [dynamic resultset binding](../exchange.html#dynamic) documentation for general information on using the `row` class.)
#### <a name="name"></a> Binding by Name
### 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")
```cpp
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);
```cpp
int i = 7;
int j = 8;
sql << "insert into t(x, y) values(?, ?)", use(i), use(j);
```
#### <a name="bulk"></a> Bulk Operations
### 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:
<table>
<tbody>
<tr>
<th>ODBC Driver</th>
<th>Bulk Read</th>
<th>Bulk Insert</th>
</tr>
<tr>
<td>MS SQL Server 2005</td>
<td>YES</td>
<td>YES</td>
</tr>
<tr>
<td>MS Access 2003</td>
<td>YES</td>
<td>NO</td>
</tr>
<tr>
<td>PostgresQL 8.1</td>
<td>YES</td>
<td>YES</td>
</tr>
<tr>
<td>MySQL 4.1</td>
<td>NO</td>
<td>NO</td>
</tr>
</tbody>
</table>
|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|
#### <a name="transactions"></a> Transactions
### 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
### BLOB Data Type
Not currently supported.
#### RowID Data Type
### RowID Data Type
Not currently supported.
#### Nested Statements
### Nested Statements
Not currently supported.
#### Stored Procedures
### Stored Procedures
Not currently supported.
### <a name="native"></a> Acessing the native database API
## Native API Access
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:
<table>
<tbody>
<tr>
<th>Accessor Function</th>
<th>Concrete Class</th>
</tr>
<tr>
<td><code>session_backend* session::get_backend()</code></td>
<td><code>odbc_statement_backend</code></td>
</tr>
<tr>
<td><code>statement_backend* statement::get_backend()</code></td>
<td><code>odbc_statement_backend</code></td>
</tr>
<tr>
<td><code>rowid_backend* rowid::get_backend()</code></td>
<td><code>odbc_rowid_backend</code></td>
</tr>
</tbody>
</table>
|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|
### <a name="extensions"></a> Backend-specific extensions
## Backend-specific extensions
#### <a name="odbcsocierror"></a> odbc_soci_error
### 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()
```cpp
int main()
{
try
{
try
{
// regular code
}
catch (soci::odbc_soci_error const&amp; 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 &amp;e)
{
cerr << "Some other error: " << e.what() << endl;
}
// regular code
}
catch (soci::odbc_soci_error const&amp; 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 &amp;e)
{
cerr << "Some other error: " << e.what() << endl;
}
}
```
#### <a name="getconenctionstring"></a> get_connection_string()
### 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.
### <a name="configuration"></a> Configuration options
## 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);
```cpp
connection_parameters parameters("odbc", "DSN=mydb");
parameters.set_option(odbc_option_driver_complete, "0" /* SQL_DRIVER_NOPROMPT */);
session sql(parameters);
```

View File

@@ -1,219 +1,171 @@
## Oracle Backend Reference
# 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)
SOCI backend for accessing Oracle database.
## Prerequisites
### <a name="prerequisites"></a> Prerequisites
#### <a name="versions"></a> Supported Versions
### 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.
#### <a name="tested"></a> Tested Platforms
### Tested Platforms
<table>
<tbody>
<tr><th>Oracle version</th><th>Operating System</th><th>Compiler</th></tr>
<tr><td>10.2.0 (XE)</td><td>RedHat 5</td><td>g++ 4.3</td></tr>
</tbody>
</table>
|Oracle|OS|Compiler|
|--- |--- |--- |
|10.2.0 (XE)|RedHat 5|g++ 4.3|
|11.2.0 (XE)|Ubuntu 12.04|g++ 4.6.3|
#### <a name="required"></a> Required Client Libraries
### 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
```console
-lsoci_core -lsoci_oracle -ldl -lclntsh -lnnz10
```
#### <a name="connecting"></a> Connecting to the Database
### 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");
```cpp
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");
// or:
session sql("oracle://service=orcl user=scott password=tiger");
// or:
session sql("oracle://service=orcl user=scott password=tiger");
// or:
session sql(oracle, "service=//your_host:1521/your_sid user=scott password=tiger");
```
The set of parameters used in the connection string for Oracle is:
* `service`
* `user`
* `password`
* `mode` (optional)
* `mode` (optional; valid values are `sysdba`, `sysoper` and `default`)
* `charset` and `ncharset` (optional; valid values are `utf8`, `utf16`, `we8mswin1252` and `win1252`)
If both `user` and `password` are provided, the session will authenticate using the database credentials, whereas if none of them is set, then external Oracle credentials will be used - this allows integration with so called Oracle wallet authentication.
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);
```cpp
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.)#
### <a name="features"></a> SOCI Feature Support
## SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### Dynamic Binding
The Oracle backend supports the use of the SOCI `row` class, which facilitates retrieval of data which type is not known at compile time.
When calling `row::get<T>()`, the type you should pass as `T` depends upon the nderlying database type.<br/> For the Oracle backend, this type mapping is:
<table>
<tbody>
<tr>
<th>Oracle Data Type</th>
<th>SOCI Data Type</th>
<th><code>row::get&lt;T&gt;</code> specializations</th>
</tr>
<tr>
<td>number <i>(where scale &gt; 0)</i></td>
<td><code>dt_double</code></td>
<td><code>double</code></td>
</tr>
<tr>
<td>number<br /><i>(where scale = 0 and precision &le; std::numeric_limits&lt;int&gt;::digits10)</i></td>
<td><code>dt_integer</code></td>
<td><code>int</code></td>
</tr>
<tr>
<td>number</td>
<td><code>dt_long_long</code></td>
<td><code>long long</code></td>
</tr>
<tr>
<td>char, varchar, varchar2</td>
<td><code>dt_string</code></td>
<td><code>std::string</code></td>
</tr>
<tr>
<td>date</td>
<td><code>dt_date</code></td>
<td><code>std::tm</code></td>
</tr>
</tbody>
</table>
When calling `row::get<T>()`, 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.)
#### <a name="name"></a> Binding by Name
### 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")
```cpp
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.
#### <a name="bulk"></a> Bulk Operations
### Bulk Operations
The Oracle backend has full support for SOCI's [bulk operations](../statements.html#bulk) interface.
#### <a name="transactions"></a> Transactions
### 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.
#### <a name="blob"></a> blob Data Type
### blob Data Type
The Oracle backend supports working with data stored in columns of type Blob, via SOCI's [blob](../exchange.html#blob) class.
#### <a name="rowid"></a> rowid Data Type
### rowid Data Type
Oracle rowid's are accessible via SOCI's [rowid](../reference.html#rowid) class.
#### <a name="nested"></a> Nested Statements
### 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();
```cpp
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';
}
while (stInner.fetch())
{
std::cout << name << '\n';
}
```
#### <a name="stored"></a> Stored Procedures
### Stored Procedures
Oracle stored procedures can be executed by using SOCI's [procedure](../statements.html#procedures) class.
### <a name="native"></a> Acessing the native database API
## Native API Access
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:
<table>
<tbody>
<tr>
<th>Accessor Function</th>
<th>Concrete Class</th>
</tr>
<tr>
<td><code>session_backend * session::get_backend()</code></td>
<td><code>oracle_session_backend</code></td>
</tr>
<tr>
<td><code>statement_backend * statement::get_backend()</code></td>
<td><code>oracle_statement_backend</code></td>
</tr>
<tr>
<td><code>blob_backend * blob::get_backend()</code></td>
<td><code>oracle_blob_backend</code></td>
</tr>
<tr>
<td><code>rowid_backend * rowid::get_backend()</code></td>
<td><code>oracle_rowid_backend</code></td>
</tr>
</tbody>
</table>
|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|
### <a name="extensions"></a> Backend-specific extensions
## Backend-specific extensions
#### <a name="oraclesocierror"></a> oracle_soci_error
### 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()
```cpp
int main()
{
try
{
try
{
// regular code
}
catch (oracle_soci_error const &amp; e)
{
cerr << "Oracle error: " << e.err_num_
<< " " << e.what() << endl;
}
catch (exception const &amp;e)
{
cerr << "Some other error: "<< e.what() << endl;
}
}
// regular code
}
catch (oracle_soci_error const &amp; e)
{
cerr << "Oracle error: " << e.err_num_
<< " " << e.what() << endl;
}
catch (exception const &amp;e)
{
cerr << "Some other error: "<< e.what() << endl;
}
}
```

View File

@@ -1,204 +1,171 @@
## PostgreSQL Backend Reference
# 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)
SOCI backend for accessing PostgreSQL database.
### <a name="prerequisites"></a> Prerequisites
## Prerequisites
#### <a name="versions"></a> Supported Versions
### 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.
#### <a name="tested"></a> Tested Platforms
### Tested Platforms
<table>
<tbody>
<tr><th>PostgreSQL version</th><th>Operating System</th><th>Compiler</th></tr>
<tr><td>9.0</td><td>Mac OS X 10.6.6</td><td>g++ 4.2</td></tr>
<tr><td>8.4</td><td>FreeBSD 8.2</td><td>g++ 4.1</td></tr>
<tr><td>8.4</td><td>Debian 6</td><td>g++ 4.3</td></tr>
<tr><td>8.4</td><td>RedHat 5</td><td>g++ 4.3</td></tr>
</tbody>
</table>
|PostgreSQL|OS|Compiler|
|--- |--- |--- |
|9.6|Windows Server 2016|MSVC++ 14.1|
|9.4|Windows Server 2012 R2|MSVC++ 14.0|
|9.4|Windows Server 2012 R2|MSVC++ 12.0|
|9.4|Windows Server 2012 R2|MSVC++ 11.0|
|9.4|Windows Server 2012 R2|Mingw-w64/GCC 4.8|
|9.3|Ubuntu 12.04|g++ 4.6.3|
|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|
#### <a name="required"></a> Required Client Libraries
### 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
```console
-lsoci_core -lsoci_postgresql -ldl -lpq
```
#### <a name="connecting"></a> Connecting to the Database
### 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:
```cpp
session sql(postgresql, "dbname=mydatabase");
session sql(postgresql, "dbname=mydatabase");
// or:
session sql("postgresql", "dbname=mydatabase");
// or:
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.
In addition to standard PostgreSQL connection parameters, the following can be set:
* `singlerow` or `singlerows`
For example:
```cpp
session sql(postgresql, "dbname=mydatabase singlerows=true");
```
If the `singlerows` parameter is set to `true` or `yes`, then queries will be executed in the single-row mode, which prevents the client library from loading full query result set into memory and instead fetches rows one by one, as they are requested by the statement's fetch() function. This mode can be of interest to those users who want to make their client applications more responsive (with more fine-grained operation) by avoiding potentially long blocking times when complete query results are loaded to client's memory.
Note that in the single-row operation:
* bulk queries are not supported, and
* in order to fulfill the expectations of the underlying client library, the complete rowset has to be exhausted before executing further queries on the same session.
Also please note that single rows mode requires PostgreSQL 9 or later, both at
compile- and run-time. If you need to support earlier versions of PostgreSQL,
you can define `SOCI_POSTGRESQL_NOSINLGEROWMODE` when building the library to
disable it.
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);
```cpp
int count;
sql << "select count(*) from invoices", into(count);
```
(See the [exchanging data](../basics.html">SOCI basics</a> and <a href="../exchange.html) documentation for general information on using the `session` class.)
### <a name="features"></a> SOCI Feature Support
## SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### Dynamic Binding
The PostgreSQL backend supports the use of the SOCI `row` class, which facilitates retrieval of data whose type is not known at compile time.
When calling `row::get<T>()`, the type you should pass as `T` depends upon the underlying database type.<br/> For the PostgreSQL backend, this type mapping is:
When calling `row::get<T>()`, the type you should pass as `T` depends upon the underlying database type. For the PostgreSQL backend, this type mapping is:
<table>
<tbody>
<tr>
<th>PostgreSQL Data Type</th>
<th>SOCI Data Type</th>
<th><code>row::get&lt;T&gt;</code> specializations</th>
</tr>
<tr>
<td>numeric, real, double</td>
<td><code>dt_double</code></td>
<td><code>double</code></td>
</tr>
<tr>
<td>boolean, smallint, integer</td>
<td><code>dt_integer</code></td>
<td><code>int</code></td>
</tr>
<tr>
<td>int8</td>
<td><code>dt_long_long</code></td>
<td><code>long long</code></td>
</tr>
<tr>
<td>oid</td>
<td><code>dt_integer</code></td>
<td><code>unsigned long</code></td>
</tr>
<tr>
<td>char, varchar, text, cstring, bpchar</td>
<td><code>dt_string</code></td>
<td><code>std::string</code></td>
</tr>
<tr>
<td>abstime, reltime, date, time, timestamp, timestamptz, timetz</td>
<td><code>dt_date</code></td>
<td><code>std::tm</code></code></code></td>
</tr>
</tbody>
</table>
|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.)
#### <a name="name"></a> Binding by Name
### 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")
```cpp
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);
```cpp
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.
#### <a name="bulk"></a> Bulk Operations
### Bulk Operations
The PostgreSQL backend has full support for SOCI's [bulk operations](../statements.html#bulk) interface.
#### <a name="transactions"></a> Transactions
### Transactions
[Transactions](../statements.html#transactions) are also fully supported by the PostgreSQL backend.
#### <a name="blob"></a> blob Data Type
### 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.
#### <a name="rowid"></a> rowid Data Type
### rowid Data Type
The concept of row identifier (OID in PostgreSQL) is supported via SOCI's [rowid](../reference.html#rowid) class.
#### <a name="nested"></a> Nested Statements
### Nested Statements
Nested statements are not supported by PostgreSQL backend.
#### <a name="stored"></a> Stored Procedures
### Stored Procedures
PostgreSQL stored procedures can be executed by using SOCI's [procedure](../statements.html#procedures) class.
### <a name="native"></a> Acessing the native database API
## Native API Access
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:
<table>
<tbody>
<tr>
<th>Accessor Function</th>
<th>Concrete Class</th>
</tr>
<tr>
<td><code>session_backend * session::get_backend()</code></td>
<td><code>postgresql_session_backend</code></td>
</tr>
<tr>
<td><code>statement_backend * statement::get_backend()</code></td>
<td><code>postgresql_statement_backend</code></td>
</tr>
<tr>
<td><code>blob_backend * blob::get_backend()</code></td>
<td><code>postgresql_blob_backend</code></td>
</tr>
<tr>
<td><code>rowid_backend * rowid::get_backend()</code></td>
<td><code>postgresql_rowid_backend</code></td>
</tr>
</tbody>
</table>
|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
### <a name="extensions"></a> Backend-specific extensions
#### <a name="uuid"></a> uuid Data Type
### 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.
### <a name="configuration"></a> Configuration options
## Configuration options
To support older PostgreSQL versions, the following configuration macros are recognized:
* `SOCI_POSTGRESQL_NOBINDBYNAME` - switches off the query rewriting.
* `SOCI_POSTGRESQL_NOPARAMS` - disables support for parameterized queries (binding of use elements),automatically imposes also the `SOCI_POSTGRESQL_NOBINDBYNAME` macro. It is necessary for PostgreSQL 7.3.
* `SOCI_POSTGRESQL_NOPREPARE` - disables support for separate query preparation, which in this backend is significant only in terms of optimization. It is necessary for PostgreSQL 7.3 and 7.4.
* `SOCI_POSTGRESQL_NOPREPARE` - disables support for separate query preparation, which in this backend is significant only in terms of optimization. It is necessary for PostgreSQL 7.3 and 7.4.
* `SOCI_POSTGRESQL_NOSINLGEROWMODE` - disable single mode retrieving query results row-by-row. It is necessary for PostgreSQL prior to version 9.

View File

@@ -1,61 +1,48 @@
## SQLite3 Backend Reference
# 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)
SOCI backend for accessign SQLite 3 database.
## Prerequisites
### <a name="prerequisites"></a> Prerequisites
#### <a name="versions"></a> Supported Versions
### Supported Versions
The SOCI SQLite3 backend is supported for use with SQLite3 >= 3.1
#### <a name="tested"></a> Tested Platforms
### Tested Platforms
<table>
<tbody>
<tr><th>SQLite3 version</th><th>Operating System</th><th>Compiler</th></tr>
<tr><td>3.5.2</td><td>Mac OS X 10.5</td><td>g++ 4.0.1</td></tr>
<tr><td>3.1.3</td><td>Mac OS X 10.4</td><td>g++ 4.0.1</td></tr>
<tr><td>3.2.1</td><td>Linux i686 2.6.10-gentoo-r6</td><td>g++ 3.4.5</td></tr>
<tr><td>3.3.4</td><td>Ubuntu 5.1</td><td>g++ 4.0.2</td></tr>
<tr><td>3.3.4</td><td>Windows XP</td><td>(cygwin) g++ 3.3.4</td></tr>
<tr><td>3.3.4</td><td>Windows XP</td><td>Visual C++ 2005 Express Edition</td></tr>
<tr><td>3.3.8</td><td>Windows XP</td><td>Visual C++ 2005 Professional</td></tr>
<tr><td>3.4.0</td><td>Windows XP</td><td>(cygwin) g++ 3.4.4</td></tr>
<tr><td>3.4.0</td><td>Windows XP</td><td>Visual C++ 2005 Express Edition</td></tr>
</tbody>
</table>
|SQLite3|OS|Compiler|
|--- |--- |--- |
|3.12.1|Windows Server 2016|MSVC++ 14.1|
|3.12.1|Windows Server 2012 R2|MSVC++ 14.0|
|3.12.1|Windows Server 2012 R2|MSVC++ 12.0|
|3.12.1|Windows Server 2012 R2|MSVC++ 11.0|
|3.12.1|Windows Server 2012 R2|Mingw-w64/GCC 4.8|
|3.7.9|Ubuntu 12.04|g++ 4.6.3|
|3.4.0|Windows XP|(cygwin) g++ 3.4.4|
|3.4.0|Windows XP|Visual C++ 2005 Express Edition|
|3.3.8|Windows XP|Visual C++ 2005 Professional|
|3.5.2|Mac OS X 10.5|g++ 4.0.1|
|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.2.1|Linux i686 2.6.10-gentoo-r6|g++ 3.4.5|
|3.1.3|Mac OS X 10.4|g++ 4.0.1|
#### <a name="required"></a> Required Client Libraries
### Required Client Libraries
The SOCI SQLite3 backend requires SQLite3's `libsqlite3` client library.
#### <a name="connecting"></a> Connecting to the Database
### 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");
```cpp
session sql(sqlite3, "database_filename");
// or:
// or:
session sql("sqlite3", "db=db.sqlite timeout=2 shared_cache=true");
session sql("sqlite3", "db=db.sqlite timeout=2 shared_cache=true");
```
The set of parameters used in the connection string for SQLite is:
@@ -66,14 +53,16 @@ The set of parameters used in the connection string for SQLite is:
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);
```cpp
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.)
### <a name="features"></a> SOCI Feature Support
## SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### 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.
@@ -81,120 +70,78 @@ When calling `row::get<T>()`, the type you should pass as T depends upon the und
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:
<table>
<tbody>
<tr>
<th>SQLite3 Data Type</th>
<th>SOCI Data Type</th>
<th><code>row::get&lt;T&gt;</code> specializations</th>
</tr>
<tr>
<td>*float*, *double*</td>
<td><code>dt_double</code></td>
<td><code>double</code></td>
</tr>
<tr>
<td>*int8*, *bigint*</td>
<td><code>dt_long_long</code></td>
<td><code>long long</code></td>
</tr>
<tr>
<td>*unsigned big int*</td>
<td><code>dt_unsigned_long_long</code></td>
<td><code>unsigned long long</code></td>
</tr>
<tr>
<td>*int*, *boolean*</td>
<td><code>dt_integer</code></td>
<td><code>int</code></td>
</tr>
<tr>
<td>*text, *char*</td>
<td><code>dt_string</code></td>
<td><code>std::string</code></td>
</tr>
<tr>
<td>*date*, *time*</td>
<td><code>dt_date</code></td>
<td><code>std::tm</code></code></code></td>
</tr>
</tbody>
</table>
|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.)
#### <a name="name"></a> Binding by Name
### 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")
```cpp
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);
```cpp
int i = 7;
int j = 8;
sql << "insert into t(x, y) values(?, ?)", use(i), use(j);
```
#### <a name="bulk"></a> Bulk Operations
### 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.
#### <a name="transactions"></a> Transactions
### Transactions
[Transactions](../statements.html#transactions) are also fully supported by the SQLite3 backend.
#### <a name="blob"></a> BLOB Data Type
### 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.
#### <a name="rowid"></a> RowID Data 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)
#### <a name="nested"></a> Nested Statements
### Nested Statements
Nested statements are not supported by SQLite3 backend.
#### <a name="stored"></a> Stored Procedures
### Stored Procedures
Stored procedures are not supported by SQLite3 backend
### <a name="native"></a> Acessing the native database API
## Native API Access
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:
<table>
<tbody>
<tr>
<th>Accessor Function</th>
<th>Concrete Class</th>
</tr>
<tr>
<td><code>session_backend* session::get_backend()</code></td>
<td><code>sqlie3_session_backend</code></td>
</tr>
<tr>
<td><code>statement_backend* statement::get_backend()</code></td>
<td><code>sqlite3_statement_backend</code></td>
</tr>
<tr>
<td><code>rowid_backend* rowid::get_backend()</code></td>
<td><code>sqlite3_rowid_backend</code></td>
</tr>
</tbody>
</table>
|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|
### <a name="extensions"></a> Backend-specific extensions
## Backend-specific extensions
#### <a name="sqlite3result"></a> SQLite3 result code support
### 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.
### <a name="configuration"></a> Configuration options
## Configuration options
None
None

View File

@@ -1,75 +1,89 @@
## Beyond standard SQL
# Beyond standard SQL
Sometimes the standard SQL is not enough and database-specific syntax needs to be used. When possible and practical, SOCI provides wrappers hiding the differences between the backends and this section describes these wrappers. And if this is still not enough, you can use the backend-specific methods directly as described below.
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
## Affected rows
It can be useful to know how many rows were affected by the last SQL statement, most often when using <tt>INSERT</tt>, <tt>UPDATE</tt> or <tt>DELETE</tt>. SOCI provides `statement::get_affected_rows()` method allowing to do this:
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);
```cpp
statement st = (sql.prepare << "update some_table ...");
st.execute(true);
if ( !st.get_affected_rows() )
{
... investigate why no rows were modified ...
}
if ( !st.get_affected_rows() )
{
... investigate why no rows were modified ...
}
```
---
#####Portability note:
### Portability note
This method is currently not supported by the Oracle backend. It is however
supported when using Oracle database via ODBC backend.
---
This method behaviour in case of partially executed update, i.e. when some records were updated or inserted while some other have failed to be updated or inserted, depends on the exact backend and, in the case of ODBC backend, on the exact ODBC driver used.
It can return `-1`, meaning that the number of rows is unknown, the number of rows actually updated or the total number of affected rows.
### Working with sequences
## 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`.
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);
```cpp
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 ...
}
// 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
---
##### Portability note:
These methods are currently only implemented in Firebird, MySQL, ODBC, PostgreSQL and SQLite3 backends.
---
## Beyond SOCI API
### 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
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.
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);
```cpp
blob b(sql);
oracle_session_back_end * sessionBackEnd = static_cast<oracle_session_back_end *>(sql.get_back_end());
oracle_blob_back_end * blobBackEnd = static_cast<oracle_blob_back_end *>(b.get_back_end());
oracle_session_back_end * sessionBackEnd = static_cast<oracle_session_back_end *>(sql.get_back_end());
oracle_blob_back_end * blobBackEnd = static_cast<oracle_blob_back_end *>(b.get_back_end());
OCILobDisableBuffering(sessionBackEnd->svchp_, sessionBackEnd->errhp_, blobBackEnd->lobp_);
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.
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.
Please see the header file related to the given backend to learn what low-level handles and descriptors are available.

184
src/soci/docs/binding.md Normal file
View File

@@ -0,0 +1,184 @@
# Data Binding
SOCI provides mechanisms to bind local buffers for input and output data.
**Note:** The Oracle documentation uses two terms: *defining* (for instructing the library where the *output* data should go) and *binding* (for the *input* data and *input/output* PL/SQL parameters). For the sake of simplicity, SOCI uses the term *binding* for both of these.
## Binding output data (into)
The `into` expression is used to add binding information to
the statement:
```cpp
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 (use)
The `use` expression associates the SQL placeholder (written with colon) with the local data:
```cpp
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:
```cpp
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.
### 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:
```cpp
// 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:
```cpp
// 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:
```cpp
// Safe and efficient code
string getNameFromSomewhere();
string const& name = getNameFromSomewhere();
sql << "insert into person(name) values(:n)", use(name);
```
### 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:
```cpp
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:
```cpp
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:
```cpp
string addr = "...";
sql << "update person"
" set mainaddress = :addr, contactaddress = :addr"
" where id = 7",
use(addr, "addr");
```
### 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.
## Bulk operations
Bulk operations allow the user to bind, as into or use element, whole vectors of objects.
This allows the database backend to optimize access and data transfer and benefit from the fact that `std::vector` stores data in contiguous memory blocks (the actual optimization depends on the backend and the capability of the underlying data base server).
It is possible to `use` the vector as a data source:
```cpp
std::vector<int> v;
// ...
sql << "insert into t ...", use(v);
```
as well as a destination:
```cpp
std::vector<int> v;
v.resize(100);
sql << "select ...", into(v);
```
In the latter case the initial size of the vector defines the maximum number of data elements that the user is willing to accept and after executing the query the vector will be automatically resized to reflect that actual number of rows that were read and transmitted.
That is, the vector will be automatically shrunk if the amount of data that was available was smaller than requested.
It is also possible to operate on the chosen sub-range of the vector:
```cpp
std::vector<int> v;
// ...
std::size_t begin = ...;
std::size_t end = ...;
sql << "insert into t ...", use(v, begin, end);
// or:
sql << "select ...", into(v, begin, end);
```
Above, only the sub-range of the vector is used for data transfer and in the case of `into` operation, the `end` variable will be automatically adjusted to reflect the amount of data that was actually transmitted, but the vector object as a whole will retain its initial size.
Bulk operations can also involve indicators, see below.
Bulk operations support user-defined data types, if they have appropriate conversion routines defined.

View File

@@ -1,8 +1,21 @@
## Integration with Boost
# Boost Integration
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.
The SOCI user code can be easily integrated with the [Boost library](http://www.boost.org/) thanks to the very flexible type conversion facility.
####boost::optional<T>
The integration with Boost types is optional and is *not* enabled by default, which means that SOCI can also 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:
```cpp
#include <boost-optional.h>
#include <boost-tuple.h>
#include <boost-fusion.h>
#include <boost-gregorian-date.h>
```
or to define the `SOCI_USE_BOOST` macro before including the `soci.h` main header file.
## Boost.Optional
`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.
@@ -10,69 +23,61 @@ The `boost::optional<T>` objects can be used everywhere where the regular user p
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
}
```cpp
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
`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.
boost::tuple<string, string, int> person;
```cpp
boost::tuple<string, string, int> person;
sql << "select name, phone, salary from persons where ...",
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 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;
```cpp
boost::tuple<string, boost::optional<string>, int> person;
sql << "select name, phone, salary from persons where ...",
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
}
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, ...>
## Boost.Fusion
The `boost::fusion::vector` types are supported in the same way as tuples.
**Note:** Support for `boost::fusion::vector` is enabled only if the detected Boost version is at least 1.35.
####boost::gregorian::date
## Boost.DateTime
The `boost::gregorian::date` is provided as a conversion for base type `std::tm` and can be used as a replacement for it.
---
#####Optional integration:
The integration with Boost types is optional and *not* enabled by default, which means that SOCI can be compiled and used without any dependency on Boost.
---
In order to enable the support for any of the above types, the user needs to either include one of these headers:
#include <boost-optional.h>
#include <boost-tuple.h>
#include <boost-fusion.h>
#include <boost-gregorian-date.h>
or to define the `SOCI_USE_BOOST` macro before including the `soci.h` main header file. Note that in this case the support for `boost::fusion::vector` is enabled only if the detected Boost version is at least 1.35.

View File

@@ -1,75 +1,111 @@
## Connections and simple queries
### Connecting to the database
# Connections
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.
## Using backend factory
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");
```cpp
session sql(oracle, "service=orcl user=scott password=tiger");
```
Another example might be:
session sql(postgresql, "dbname=mydb");
```cpp
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:
### Portability note
session sql("postgresql", "dbname=mydb");
In case of SOCI linked against DLLs on Windows, the factory objects are not exported from the DLLs.
In order to avoid linker errors, access factory objects via dedicated backend functions
provided (eg. `factory_postgresql()`).
## Using loadable backends
Dynamically loadable backends are compiled as shared libraries and allow to select backends at run-time by name.
The usage is similar to the above, but instead of providing the factory object, the backend name is expected:
```cpp
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");
```cpp
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 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:
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.
connection_parameters parameters("odbc", "DSN=mydb");
parameters.set_option(odbc_option_driver_complete, "0" /* SQL_DRIVER_NOPROMPT */);
session sql(parameters);
For example, to suppress any interactive prompts when using ODBC backend you could do:
Notice that you need to `#include &lt;soci-odbc.h&gt;` to obtain the option name declaration. The existing options are described in the backend-specific part of the documentation.
```cpp
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.
IBM DB2 driver for ODBC and CLI also support the driver completion requests.
So, the DB2 backend provides similar option `db2_option_driver_complete` with `#include <soci-db1.h>` required to obtain the option name.
### 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 `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.
## Using registered backends
The run-time selection of backends is also supported with libraries linked statically.
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:
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");
```cpp
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.
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;
```cpp
session sql;
// some time later:
sql.open(postgresql, "dbname=mydb");
// some time later:
sql.open(postgresql, "dbname=mydb");
// or:
sql.open("postgresql://dbname=mydb");
// or:
sql.open("postgresql://dbname=mydb");
// or also:
connection_parameters parameters("postgresql", "dbname=mydb");
sql.open(parameters);
// 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.
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.
@@ -87,4 +123,40 @@ 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"`)
* [firebird](backends/firebird.html) (requires `#include "soci-firebird.h"`)
## Connection failover
The `failover_callback` interface can be used as a callback channel for notifications of events that are automatically processed when the session is forcibly closed due to connectivity problems. The user can override the following methods:
```cpp
// Called when the failover operation has started,
// after discovering connectivity problems.
virtual void started();
// Called after successful failover and creating a new connection;
// the sql parameter denotes the new connection and allows the user
// to replay any initial sequence of commands (like session configuration).
virtual void finished(session & sql);
// Called when the attempt to reconnect failed,
// if the user code sets the retry parameter to true,
// then new connection will be attempted;
// the newTarget connection string is a hint that can be ignored
// by external means.
virtual void failed(bool & retry, std::string & newTarget);
// Called when there was a failure that prevents further failover attempts.
virtual void aborted();
```
The user-provided callback implementation can be installed (or reset) with:
```cpp
sql.set_failover_callback(myCallback);
```
### Portability note
The `failover_callback` functionality is currently supported only by PostgreSQL and Oracle backends (in the latter case the failover mechanism is governed by the Oracle-specific cluster configuration settings).
Other backends allow the callback object to be installed, but will ignore it and will not generate notification calls.

View File

@@ -1,82 +1,99 @@
## Errors
# Errors
All DB-related errors manifest themselves as exceptions of type `soci_error`, which is derived from `std::runtime_error`.
This allows to handle database errors within the standard exception framework:
int main()
```cpp
int main()
{
try
{
try
{
// regular code
}
catch (std::exception const & e)
{
cerr << "Bang! " << e.what() << endl;
}
// regular code
}
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()
catch (std::exception const & e)
{
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;
}
cerr << "Bang! " << e.what() << endl;
}
}
```
#### Portability note:
The `soci_error` class exposes two public functions:
The `get_error_message() const` function returns `std::string` with a brief error message, without any additional information that can be present in the full error message returned by `what()`.
The `get_error_category() const` function returns one of the `error_category` enumeration values, which allows the user to portably react to some subset of common errors.
For example, `connection_error` or `constraint_violation` have meanings that are common across different database backends, even though the actual mechanics might differ.
## Portability
Error categories are not universally supported and there is no claim that all possible errors that are reported by the database server are covered or interpreted.
If the error category is not recognized by the backend, it defaults to `unknown`.
## MySQL
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()
```cpp
int main()
{
try
{
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;
}
// 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:
## Oracle
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:
```cpp
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;
}
}
```
## PostgreSQL
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()
```cpp
int main()
{
try
{
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;
}
}
// 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;
}
}
```

View File

@@ -1,536 +0,0 @@
## 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)
### <a name="bind_local"></a> 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).
#### <a name="bind_local"></a> 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).
#### <a name="bind_input"></a> 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.
#### <a name="bind_position"></a> 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.
#### <a name="bind_name"></a> 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.
### <a name="data_states"></a> Handling nulls and other conditions
#### <a name="indicators"></a> Indicators
In order to support null values and other conditions which are not real errors, the concept of *indicator* is provided.
For example, when the following SQL query is executed:
select name from person where id = 7
there are three possible outcomes:
1. there is a person with id = 7 and his name is returned
2. there is a person with id = 7, but he has no name (his name is null in the database table)
3. there is no such person
Whereas the first alternative is easy to handle, the other two are more complex. Moreover, they are not necessarily errors from the application's point of view and what's more interesting, they are *different* and the application may wish to detect which is the case.
The following example does this:
string name;
indicator ind;
sql << "select name from person where id = 7", into(name, ind);
if (sql.got_data())
{
switch (ind)
{
case i_ok:
// the data was returned without problems
break;
case i_null:
// there is a person, but he has no name (his name is null)
break;
case i_truncated:
// the name was returned only in part,
// because the provided buffer was too short
// (not possible with std::string, but possible with char* and char[])
break;
}
}
else
{
// no such person in the database
}
The use of indicator variable is optional, but if it is not used and the result would be `i_null`,
then the exception is thrown. This means that you should use indicator variables everywhere where the application logic (and database schema) allow the "attribute not set" condition.
Indicator variables can be also used when binding input data, to control whether the data is to be used as provided, or explicitly overrided to be null:
int id = 7;
string name;
indicator ind = i_null;
sql << "insert into person(id, name) values(:id, :name)",
use(id), use(name, ind);
In the above example, the row is inserted with `name` attribute set to null.
Indicator variables can also be used in conjunction with vector based insert, update, and select statements:
vector<string< names(100);
vector<indicator< inds;
sql << "select name from person where id = 7", into(names, inds);
The above example retrieves first 100 rows of data (or less). The initial size of `names` vector provides the (maximum) number of rows that should be read. Both vectors will be automatically resized according to the number of rows that were actually read.
The following example inserts null for each value of name:
vector<int< ids;
vector<string< names;
vector<indicator< nameIndicators;
for (int i = 0; i != 10; ++i)
{
ids.push_back(i);
names.push_back("");
nameIndicators.push_back(i_null);
}
sql << "insert into person(id, name) values(:id, :name)",
use(ids), use(name, nameIndicators);
See also [Integration with Boost](boost.html) to learn how the Boost.Optional library can be used to handle null data conditions in a more natural way.
### <a name="types"></a> Types
#### <a name="static"></a> 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.
#### <a name="static_bulk"></a> 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::vector`s of the types listed above.
#### <a name="dynamic"></a> Dynamic resultset binding
For certain applications it is desirable to be able to select data from arbitrarily structured tables (e.g. via "`select * from ...`") and format the resulting data based upon its type. SOCI supports this through the `soci::row` and `soci::column_properties` classes.
Data is selected into a `row` object, which holds `column_properties` objects describing
the attributes of data contained in each column. Once the data type for each column is known, the data can be formatted appropriately.
For example, the code below creates an XML document from a selected row of data from an arbitrary table:
row r;
sql << "select * from some_table", into(r);
std::ostringstream doc;
doc << "<row<" << std::endl;
for(std::size_t i = 0; i != r.size(); ++i)
{
const column_properties & props = r.get_properties(i);
doc << '<' << props.get_name() << '<';
switch(props.get_data_type())
{
case dt_string:
doc << r.get<std::string<(i);
break;
case dt_double:
doc << r.get<double<(i);
break;
case dt_integer:
doc << r.get<int<(i);
break;
case dt_long_long:
doc << r.get<long long<(i);
break;
case dt_unsigned_long_long:
doc << r.get<unsigned long long<(i);
break;
case dt_date:
std::tm when = r.get<std::tm<(i);
doc << asctime(&when);
break;
}
doc << "</" << props.get_name() << '<' << std::endl;
}
doc << "</row<";
The type `T` parameter that should be passed to `row::get<T<()` depends on the SOCI data type that is returned from `column_properties::get_data_type()`.
`row::get<T<()` throws an exception of type `std::bad_cast` if an incorrect type `T` is requested.
#####SOCI Data Type
`row::get<T<` specialization
*dt_double - double
*dt_integer - int
*dt_long_long - long long
*dt_unsigned_long_long - unsigned long long
*dt_string - std::string
*dt_date - std::tm
The mapping of underlying database column types to SOCI datatypes is database specific. See the [backend documentation](backends/index.html) 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.
#### <a name="custom_types"></a> 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](boost.html) 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](static_bulk)
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.
#### <a name="object_relational"></a> Object-relational mapping
SOCI provides a class called `values` specifically to enable object-relational mapping via `type_conversion` specializations.
For example, the following code maps a `Person` object to and from a database table containing columns `"ID"`, `"FIRST_NAME"`, `"LAST_NAME"`, and `"GENDER"`.
Note that the mapping is non-invasive - the `Person` object itself does not contain any SOCI-specific code:
struct Person
{
int id;
std::string firstName;
std::string lastName;
std::string gender;
};
namespace soci
{
template<<
struct type_conversion<Person<
{
typedef values base_type;
static void from_base(values const & v, indicator /* ind */, Person & p)
{
p.id = v.get<int<("ID");
p.firstName = v.get<std::string<("FIRST_NAME");
p.lastName = v.get<std::string<("LAST_NAME");
// p.gender will be set to the default value "unknown"
// when the column is null:
p.gender = v.get<std::string<("GENDER", "unknown");
// alternatively, the indicator can be tested directly:
// if (v.indicator("GENDER") == i_null)
// {
// p.gender = "unknown";
// }
// else
// {
// p.gender = v.get<std::string<("GENDER");
// }
}
static void to_base(const Person & p, values & v, indicator & ind)
{
v.set("ID", p.id);
v.set("FIRST_NAME", p.firstName);
v.set("LAST_NAME", p.lastName);
v.set("GENDER", p.gender, p.gender.empty() ? i_null : i_ok);
ind = i_ok;
}
};
}
With the above `type_conversion` specialization in place, it is possible to use `Person` directly with SOCI:
session sql(oracle, "service=db1 user=scott password=tiger");
Person p;
p.id = 1;
p.lastName = "Smith";
p.firstName = "Pat";
sql << "insert into person(id, first_name, last_name) "
"values(:ID, :FIRST_NAME, :LAST_NAME)", use(p);
Person p1;
sql << "select * from person", into(p1);
assert(p1.id == 1);
assert(p1.firstName + p.lastName == "PatSmith");
assert(p1.gender == "unknown");
p.firstName = "Patricia";
sql << "update person set first_name = :FIRST_NAME "
"where id = :ID", use(p);
##### Note:
The `values` class is currently not suited for use outside of `type_conversion`specializations. It is specially designed to facilitate object-relational mapping when used as shown above.
### <a name="blob"></a> 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.

View File

@@ -1,42 +1,44 @@
## Rationale FAQ
# FAQ
This part of the documentation is supposed to gather in a single place the usual questions (and answers) about SOCI with regard to the design decisions that have shaped it.
### Q: Why "SOCI"?
## 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.
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?
## 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);
/* ... */
}
```cpp
{
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, pecialized 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);
```cpp
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)
@@ -51,37 +53,41 @@ Everything else is just a couple of operators that allow to treat the whole as a
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.
## 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-*un*like) 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?
## 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");
```cpp
sql.exec("select a, b, c from some_table");
while (!sql.eof())
{
int a, b, c;
sql >> a >> b >> c;
// ...
}
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
```cpp
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"
// ...
}
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.
@@ -89,18 +95,17 @@ 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?
## 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<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.
## Q: Overloaded comma operator is just obfuscation, I don't like it.
Well, consider the following:
@@ -108,18 +113,17 @@ Well, consider the following:
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.
## 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?
## 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.
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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -1,71 +1,68 @@
# Documentation and tutorial
# SOCI - The C++ Database Access Library
* [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)
SOCI is a database access library written in C++ that makes an illusion of embedding
SQL queries in the regular C++ code, staying entirely within the Standard C++.
The following (complete!) example is purposedly provided without any explanation.
The idea is to provide C++ programmers a way to access SQL databases in the most natural and intuitive way.
If you find existing libraries too difficult for your needs or just distracting, SOCI can be a good alternative.
#include "soci.h"
#include "soci-oracle.h"
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <exception>
## Basic Syntax
using namespace soci;
using namespace std;
The simplest motivating code example for the SQL query that is supposed to retrieve a single row is:
bool get_name(string &name) {
cout << "Enter name: ";
return cin >> name;
}
```cpp
int id = ...;
string name;
int salary;
int main()
{
try
{
session sql(oracle, "service=mydb user=john password=secret");
sql << "select name, salary from persons where id = " << id,
into(name), into(salary);
```
int count;
sql << "select count(*) from phonebook", into(count);
## Basic ORM
cout << "We have " << count << " entries in the phonebook.\n";
The following benefits from extensive support for object-relational mapping:
string name;
while (get_name(name))
{
string phone;
indicator ind;
sql << "select phone from phonebook where name = :name",
into(phone, ind), use(name);
```cpp
int id = ...;
Person p;
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';
}
}
sql << "select first_name, last_name, date_of_birth "
"from persons where id = " << id, into(p);
```
## Integrations
Integration with STL is also supported:
```cpp
Rowset<string> rs = (sql.prepare << "select name from persons");
std::copy(rs.begin(), rs.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
```
SOCI offers also extensive [integration with Boost](boost.md) datatypes (optional, tuple and fusion) and flexible support for user-defined datatypes.
## Database Backends
Starting from its 2.0.0 release, SOCI uses the plug-in architecture for
backends - this allows to target various database servers.
Currently (SOCI 4.0.0), backends for following database systems are supported:
* [DB2](backends/db2.md)
* [Firebird](backends/firebird.md)
* [MySQL](backends/mysql.md)
* [ODBC](backends/odbc.md) (generic backend)
* [Oracle](backends/oracle.md)
* [PostgreSQL](backends/postgresql.md)
* [SQLite3](backends/sqlite3.md)
The intent of the library is to cover as many database technologies as possible.
For this, the project has to rely on volunteer contributions from other programmers,
who have expertise with the existing database interfaces and would like to help
writing dedicated backends.
## Langauge Bindings
Even though SOCI is mainly a C++ library, it also allows to use it from other programming languages.
Currently the package contains the Ada binding, with more bindings likely to come in the future.

102
src/soci/docs/indicators.md Normal file
View File

@@ -0,0 +1,102 @@
# Data Indicators
In order to support SQL NULL values and other conditions which are not real errors, the concept of *indicator* is provided.
## Select with NULL values
For example, when the following SQL query is executed:
```sql
select name from person where id = 7
```
there are three possible outcomes:
1. there is a person with id = 7 and her name is returned
2. there is a person with id = 7, but she has no name (her 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:
```cpp
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.
## Insert with NULL values
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:
```cpp
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.
## Bulk operations with NULL values
Indicator variables can also be used in conjunction with vector based insert, update, and select statements:
```cpp
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:
```cpp
vector<int> ids;
vector<string> names;
vector<indicator> nameIndicators;
for (int i = 0; i != 10; ++i)
{
ids.push_back(i);
names.push_back("");
nameIndicators.push_back(i_null);
}
sql << "insert into person(id, name) values(:id, :name)",
use(ids), use(name, nameIndicators);
```
See also [Integration with Boost](boost.html) to learn how the Boost.Optional library can be used to handle null data conditions in a more natural way.

View File

@@ -1,15 +1,6 @@
## Installation
# 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)
### <a name="requirements"></a> Requirements
## Requirements
Below is an overall list of SOCI core:
@@ -27,187 +18,204 @@ and backend-specific dependencies:
* [libpq](http://www.postgresql.org/docs/8.4/static/libpq.html) - C API to PostgreSQL
* [SQLite 3](http://www.sqlite.org/) library
### <a name="downloading"></a> Downloading
## Downloads
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.
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
```console
git clone git://github.com/SOCI/soci.git
```
### <a name="building"></a> Building using CMake
## Building with 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.
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.
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.
### Running CMake on Unix
#### List of a few essential CMake variables
Steps outline using GNU Make makefiles:
* 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)).
```console
mkdir build
cd build
cmake -G "Unix Makefiles" -DWITH_BOOST=OFF -DWITH_ORACLE=OFF (...) /path/to/soci-X.Y.Z
make
make install
```
#### List of variables to control common SOCI features and dependencies
### Running CMake on Windows
* 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.
Steps outline using Visual Studio 2010 and MSBuild:
#### IBM DB2
```console
mkdir build
cd build
cmake -G "Visual Studio 10" -DWITH_BOOST=OFF -DWITH_ORACLE=OFF (...) C:\path\to\soci-X.Y.Z
msbuild.exe SOCI.sln
```
#### SOCI DB2 backend configuration
### CMake 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"`
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 below.
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 below provide users with basic control of this behaviour.
The following sections 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.
#### Firebird
List of a few essential CMake variables:
##### SOCI Firebird backend configuration
* `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)).
* 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"`
List of variables to control common SOCI features and dependencies:
#### 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"`
* `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.
#### 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"`
* 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"`
#### IBM DB2
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.
* `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"`
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.
#### Firebird
#### <a name="unix"></a> Building using CMake on Unix
* `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"`
Short version using GNU Make makefiles:
#### MySQL
$ mkdir build
$ cd build
$ cmake -G "Unix Makefiles" -DWITH_BOOST=OFF -DWITH_ORACLE=OFF (...) ../soci-X.Y.Z
$ make
$ make install
* `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
#### <a name="windows"></a> Building using CMake on Windows
* `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/soci/build/test-postgresql.dsn"`
#### Oracle
Short version using Visual Studio 2010 and MSBuild:
* `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"`
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
#### PostgreSQL
* `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` - string - Connection string to PostgreSQL test database. Format of the string is explained PostgreSQL backend refernece. Example: `-DSOCI_POSTGRESQL_TEST_CONNSTR:STRING="dbname=mydb user=scott"`
### <a name="makefiles"></a> Building using classic Makefiles on Unix (deprecated)
#### SQLite 3
*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.*
* `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](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"` or `-DSOCI_SQLITE3_TEST_CONNSTR=":memory:"`.
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.
## Building with Makefiles on Unix
*NOTE: These (classic) 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/<i>name</i>` directory contains the backend part for each supported backend with the appropriate `Makefile.basic` and the `backends/<i>name</i>/test` directory contains the test program for the given backend.
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/<i>name</i>` directory contains the backend part for each supported backend with the appropriate `Makefile.basic` and the `backends/<i>name</i>/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:
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
```console
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.
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.
### <a name="regression"></a> Running regression tests
## Running 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).
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 lists 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.
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
```console
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.
### <a name="library"></a> Libraries usage
## Using library
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.
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.
In order to use SOCI in your program, you need to specify your project build configuration with paths to SOCI headers and libraries.
Then, tell the linker to link against the libraries you want to use in your program.

View File

@@ -1,74 +1,84 @@
## Interfaces
# 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
## 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:
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");
```cpp
session sql("postgresql://dbname=mydb");
int id = 123;
string name;
int id = 123;
string name;
sql &lt;&lt; "select name from persons where id = :id", into(name), use(id);
sql << "select name from persons where id = :id", into(name), use(id);
```
#### Core
## Core
The above example is equivalent to the following, more explicit sequence of calls:
session sql("postgresql://dbname=mydb");
```cpp
session sql("postgresql://dbname=mydb");
int id = 123;
string name;
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);
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.
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
## 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 *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 &lt;soci-simple.h&gt;
```cpp
#include <soci-simple.h>
// ...
session_handle sql = soci_create_session("postgresql://dbname=mydb");
// ...
session_handle sql = soci_create_session("postgresql://dbname=mydb");
statement_handle st = soci_create_statement(sql);
statement_handle st = soci_create_statement(sql);
soci_use_int(st, "id");
soci_set_use_int(st, "id", 123);
soci_use_int(st, "id");
soci_set_use_int(st, "id", 123);
int namePosition = soci_into_string(st);
int namePosition = soci_into_string(st);
soci_prepare(st, "select name from persons where id = :id");
soci_prepare(st, "select name from persons where id = :id");
soci_execute(st, true);
soci_execute(st, true);
char const * name = soci_get_into_string(st, namePosition);
char const * name = soci_get_into_string(st, namePosition);
printf("name is %s\n", name);
printf("name is %s\n", name);
soci_destroy_statement(st);
soci_destroy_session(sql);
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 *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
## 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.
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.

View File

@@ -1,6 +1,4 @@
# SOCI-Ada - manual
## Concepts
# Ada 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.
@@ -12,7 +10,6 @@ There are two kinds of objects that can be managed by the SOCI-Ada library:
* *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`
@@ -29,4 +26,4 @@ All statements are handled within the context of some *session*, which also supp
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.
All potential problems are signalled via exceptions that have some descriptive message attached to them.

View File

@@ -1,6 +1,4 @@
# SOCI-Ada - manual
## Common Idioms
# Ada 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.
@@ -10,251 +8,228 @@ The idioms below are provided as *complete programs* with the intent to make the
This type of query is useful for DDL commands and can be executed directly on the given session, without explicit statement management.
```ada
with SOCI;
with SOCI;
procedure My_Program is
procedure My_Program is
SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
begin
begin
SQL.Execute ("drop table some_table");
SQL.Execute ("drop table some_table");
end My_Program;
end My_Program;
<div class="note">
<span class="note">Note:</span>
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.
</div>
```
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.
```ada
with SOCI;
with Ada.Text_IO;
with SOCI;
with Ada.Text_IO;
procedure My_Program is
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;
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;
Num_Of_Persons : SOCI.DB_Integer;
begin
begin
Pos := St.Into_Integer;
St.Prepare ("select count(*) from persons");
St.Execute (True);
Pos := St.Into_Integer;
St.Prepare ("select count(*) from persons");
St.Execute (True);
Num_Of_Persons := St.Get_Into_Integer (Pos);
Num_Of_Persons := St.Get_Into_Integer (Pos);
Ada.Text_IO.Put_Line ("Number of persons: " & SOCI.DB_Integer'Image (Num_Of_Persons));
Ada.Text_IO.Put_Line ("Number of persons: " &amp; SOCI.DB_Integer'Image (Num_Of_Persons));
end My_Program;
<div class="note">
<span class="note">Note:</span>
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.
</div>
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;
```ada
with SOCI;
procedure My_Program is
procedure My_Program is
SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
St : SOCI.Statement := SOCI.Make_Statement (SQL);
SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
St : SOCI.Statement := SOCI.Make_Statement (SQL);
begin
begin
St.Use_Integer ("increase");
St.Set_Use_Integer ("increase", 1000);
St.Use_Integer ("increase");
St.Set_Use_Integer ("increase", 1000);
St.Prepare ("update persons set salary = salary + :increase");
St.Execute (True);
St.Prepare ("update persons set salary = salary + :increase");
St.Execute (True);
end My_Program;
<div class="note">
<span class="note">Note:</span>
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.
</div>
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.
```ada
with SOCI;
with SOCI;
procedure My_Program is
procedure My_Program is
SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
St : SOCI.Statement := SOCI.Make_Statement (SQL);
SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
St : SOCI.Statement := SOCI.Make_Statement (SQL);
begin
begin
St.Use_String ("name");
St.Use_String ("name");
St.Prepare ("insert into countries(country_name) values(:name)");
St.Prepare ("insert into countries(country_name) values(:name)");
St.Set_Use_String ("name", "Poland");
St.Execute (True);
St.Set_Use_String ("name", "Poland");
St.Execute (True);
St.Set_Use_String ("name", "Switzerland");
St.Execute (True);
St.Set_Use_String ("name", "Switzerland");
St.Execute (True);
St.Set_Use_String ("name", "France");
St.Execute (True);
St.Set_Use_String ("name", "France");
St.Execute (True);
end My_Program;
```
end My_Program;
<div class="note">
<span class="note">Note:</span>
Each time the query is executed, the *current* values of use elements are transferred to the database.
</div>
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;
```ada
with SOCI;
procedure My_Program is
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;
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;
use type SOCI.Vector_Index;
begin
begin
St.Use_Vector_String ("name");
St.Use_Vector_String ("name");
St.Use_Vectors_Resize (3);
St.Use_Vectors_Resize (3);
First := St.Use_Vectors_First_Index;
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.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);
St.Prepare ("insert into countries(country_name) values(:name)");
St.Execute (True);
end My_Program;
end My_Program;
```
<div class="note">
<span class="note">Note:</span>
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.
</div>
<div class="note">
<span class="note">Note:</span>
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.
</div>
## Simple query with many rows of results
This type of query requires simple into elements.
with SOCI;
with Ada.Text_IO;
```ada
with SOCI;
with Ada.Text_IO;
procedure My_Program is
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;
SQL : SOCI.Session := SOCI.Make_Session ("postgresql://dbname=my_database");
St : SOCI.Statement := SOCI.Make_Statement (SQL);
Pos : SOCI.Into_Position;
begin
begin
Pos := St.Into_String;
Pos := St.Into_String;
St.Prepare ("select country_name from countries");
St.Execute;
St.Prepare ("select country_name from countries");
St.Execute;
while St.Fetch loop
while St.Fetch loop
Ada.Text_IO.Put_Line (St.Get_Into_String (Pos));
Ada.Text_IO.Put_Line (St.Get_Into_String (Pos));
end loop;
end loop;
end My_Program;
end My_Program;
```
<div class="note">
<span class="note">Note:</span>
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.
</div>
## 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;
```ada
with SOCI;
with Ada.Text_IO;
procedure My_Program is
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;
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;
Batch_Size : constant := 10;
begin
begin
Pos := St.Into_Vector_String;
St.Into_Vectors_Resize (Batch_Size);
Pos := St.Into_Vector_String;
St.Into_Vectors_Resize (Batch_Size);
St.Prepare ("select country_name from countries");
St.Execute;
St.Prepare ("select country_name from countries");
St.Execute;
while St.Fetch loop
while St.Fetch loop
for I in St.Into_Vectors_First_Index .. St.Into_Vectors_Last_Index 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));
Ada.Text_IO.Put_Line (St.Get_Into_Vector_String (Pos, I));
end loop;
end loop;
St.Into_Vectors_Resize (Batch_Size);
St.Into_Vectors_Resize (Batch_Size);
end loop;
end loop;
end My_Program;
end My_Program;
```
##### Note:
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.
@@ -262,7 +237,6 @@ There is a tradeoff between efficiency and memory usage and this tradeoff is con
This type of query can have simple (not vectors) parameters that are fixed at execution time.
##### Final note:
## 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.

View File

@@ -1,10 +1,8 @@
# SOCI-Ada Language Binding - documentation
# Ada Bindings
* [Introduction](#introduction)
* [Compilation](#compilation)
* [Concepts](concepts.html)
* [Common Idioms](idioms.html)
* [API Reference](reference.html)
* [Concepts](concepts.md)
* [Idioms](idioms.md)
* [API Reference](reference.md)
## Introduction
@@ -22,9 +20,9 @@ The SOCI-Ada library offers the following features to the Ada community:
Currently the following database servers are directly supported via their native interfaces:
* Oracle
* PostgreSQL
* MySQL
* Oracle
* PostgreSQL
* MySQL
Other backends exist in the SOCI Git repository and can be provided with future version of the library.
@@ -36,4 +34,4 @@ In order to use SOCI-Ada, compile the C++ parts first (core and required backend
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.
In order to link the user programs the `-lsoci_core -lstdc++` linker options need to be provided on the Unix/Linux platforms.

View File

@@ -1,147 +1,150 @@
# SOCI-Ada - manual
## API Reference
# Ada 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:
```ada
--
-- General exception related to database and library usage.
--
--
-- General exception related to database and library usage.
--
Database_Error : exception;
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.
--
```ada
--
-- Session.
--
type Session is tagged limited private;
type Session is tagged limited private;
not overriding
function Make_Session (Connection_String : in String) return Session;
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 Open (This : in out Session; Connection_String : in String);
not overriding
procedure Close (This : in out Session);
not overriding
procedure Close (This : in out Session);
not overriding
function Is_Open (This : in Session) return Boolean;
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)
* [Oracle](http://soci.sourceforge.net/doc/backends/oracle.html)
* [PostgreSQL](http://soci.sourceforge.net/doc/backends/postgresql.html)
* [MySQL](http://soci.sourceforge.net/doc/backends/mysql.html)
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.
```ada
-- Transaction management.
-- Transaction management.
not overriding
procedure Start (This : in Session);
not overriding
procedure Start (This : in Session);
not overriding
procedure Commit (This : in Session);
not overriding
procedure Commit (This : in Session);
not overriding
procedure Rollback (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);
```ada
-- 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.
--
```ada
--
-- Connection pool management.
--
type Connection_Pool (Size : Positive) is tagged limited private;
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 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 Close (This : in out Connection_Pool; Position : in Positive);
not overriding
procedure Lease (This : in out Connection_Pool; S : in out Session'Class);
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:
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.
--
```ada
--
-- Statement.
--
type Statement (&lt;&gt;) is tagged limited private;
type Statement (&lt;&gt;) is tagged limited private;
type Data_State is (Data_Null, Data_Not_Null);
type Data_State is (Data_Null, Data_Not_Null);
type Into_Position is private;
type Into_Position is private;
type Vector_Index is new Natural;
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.
```ada
-- Statement preparation and execution.
-- Statement preparation and execution.
not overriding
procedure Prepare (This : in Statement; Query : in String);
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
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 Execute
(This : in Statement;
With_Data_Exchange : in Boolean := False) return Boolean;
not overriding
function Fetch (This : in Statement) return Boolean;
not overriding
function Fetch (This : in Statement) return Boolean;
not overriding
function Got_Data (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.
@@ -151,19 +154,20 @@ The `Fetch` function is used to transfer next portion of data (a single row or a
The `Got_Data` function returns `True` if the last execution or fetch resulted in some data being transmitted from the database server.
```ada
--
-- Data items handling.
--
--
-- 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.
-- 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;
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:
@@ -173,92 +177,88 @@ The data types used for interaction with the database are:
* `DB_Long_Float`, defined above
* `Ada.Calendar.Time`
-- Creation of single into elements.
```ada
-- Creation of single into elements.
not overriding
function Into_String (This : in Statement) return Into_Position;
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_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_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;
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:
Note: Simple into elements cannot be created together with vector into elements for the same statement.
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.
---
```ada
-- Inspection of single into elements.
---
#####Note:
Simple into elements cannot be created together with vector into elements for the same statement.
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;
-- Inspection of single into elements.
not overriding
function Get_Into_Integer
(This : in Statement;
Position : in Into_Position)
return DB_Integer;
not overriding
function Get_Into_State
(This : in Statement;
Position : in Into_Position)
return Data_State;
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_String
(This : in Statement;
Position : in Into_Position)
return String;
not overriding
function Get_Into_Long_Float
(This : in Statement;
Position : in Into_Position)
return DB_Long_Float;
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;
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.
```ada
-- Inspection of vector into elements.
not overriding
function Get_Into_Vectors_Size (This : in Statement) return Natural;
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_First_Index (This : in Statement) return Vector_Index;
not overriding
function Into_Vectors_Last_Index (This : in Statement) return Vector_Index;
not overriding
function Into_Vectors_Last_Index (This : in Statement) return Vector_Index;
not overriding
procedure Into_Vectors_Resize (This : in Statement; New_Size : in Natural);
not overriding
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.
@@ -266,163 +266,161 @@ The `Into_Vectors_First_Index` returns the lowest index value for vector into el
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;
```ada
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_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_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_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_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;
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.
```ada
-- Creation of single use elements.
-- Creation of single use elements.
not overriding
procedure Use_String (This : in Statement; Name : in String);
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_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_Long_Integer (This : in Statement; Name : in String);
not overriding
procedure Use_Long_Float (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);
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.
Note:
Vector use elements cannot be created together with any into elements for the same statement.
* 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.
---
```ada
-- Creation of vector use elements.
not overriding
procedure Use_Vector_String (This : in Statement; Name : in String);
-- Creation of vector use elements.
not overriding
procedure Use_Vector_Integer (This : in Statement; Name : in String);
not overriding
procedure Use_Vector_String (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_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);
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:
---
#####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.
Simple use elements cannot be created together with vector use elements for the same statement.
```ada
-- Modifiers for single use elements.
Vector use elements cannot be created together with any into elements for the same statement.
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);
-- Modifiers for single use elements.
not overriding
procedure Set_Use_Integer
(This : in Statement;
Name : in String;
Value : in DB_Integer);
not overriding
procedure Set_Use_State
(This : in Statement;
Name : in String;
State : in Data_State);
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_String
(This : in Statement;
Name : in String;
Value : in String);
not overriding
procedure Set_Use_Long_Float
(This : in Statement;
Name : in String;
Value : in DB_Long_Float);
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);
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`.
```ada
-- Modifiers for vector use elements.
-- Modifiers for vector use elements.
not overriding
function Get_Use_Vectors_Size (This : in Statement) return Natural;
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_First_Index (This : in Statement) return Vector_Index;
not overriding
function Use_Vectors_Last_Index (This : in Statement) return Vector_Index;
not overriding
function Use_Vectors_Last_Index (This : in Statement) return Vector_Index;
not overriding
procedure Use_Vectors_Resize (This : in Statement; New_Size : in Natural);
not overriding
procedure 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.
@@ -430,94 +428,95 @@ The `Use_Vectors_First_Index` returns the lowest index value for vector use elem
The `Use_Vectors_Resize` procedure allows to change the size of all use vectors for the given statement.
```ada
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_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_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_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_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);
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`.
```ada
-- 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.
-- 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_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_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_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_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_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;
```
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.
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.

View File

@@ -0,0 +1,3 @@
# Language bindings
* [Ada](ada/index.md)

29
src/soci/docs/license.md Normal file
View File

@@ -0,0 +1,29 @@
# License
The SOCI library is distributed under the terms of the [Boost Software License](http://www.boost.org/LICENSE_1_0.txt).
## Boost Software License
Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

71
src/soci/docs/lobs.md Normal file
View File

@@ -0,0 +1,71 @@
# Large Objects (LOBs)
## Binary (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_from_start(char * buf, std::size_t toRead, std::size_t offset = 0);`
* `std::size_t write_from_start(const char * buf, std::size_t toWrite, std::size_t offset = 0);`
* `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.
## Long strings and XML
The SOCI library recognizes the fact that long string values are not handled portably and in some databases long string values need to be stored as a different data type.
Similar concerns relate to the use of XML values, which are essentially strings at the application level, but can be stored in special database-level field types.
In order to facilitate handling of long strings and XML values the following wrapper types are defined:
struct xml_type
{
std::string value;
};
struct long_string
{
std::string value;
};
Values of these wrapper types can be used with `into` and `use` elements with the database target type that is specifically intended to handle XML and long strings data types.
For Oracle, these database-side types are, respectively:
* `XMLType`,
* `CLOB`
For PostgreSQL, these types are:
* `XML`
* `text`
For Firebird, there is no special XML support, but `BLOB SUB_TYPE TEXT` can be
used for storing it, as well as long strings.
For ODBC backend, these types depend on the type of the database connected to.
In particularly important special case of Microsoft SQL Server, these types
are:
* `xml`
* `text`
When using ODBC backend to connect to a PostgreSQL database, please be aware
that by default PostgreSQL ODBC driver truncates all "unknown" types, such as
XML, to maximal varchar type size which is just 256 bytes and so is often
insufficient for XML values in practice. It is advised to set the
`UnknownsAsLongVarchar` connection option to 1 to avoid truncating XML strings
or use PostgreSQL ODBC driver 9.6.300 or later, which allows the backend to set
this option to 1 automatically on connection.

26
src/soci/docs/logging.md Normal file
View File

@@ -0,0 +1,26 @@
# Logging
SOCI provides a very basic logging facility.
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.

View File

@@ -1,38 +1,47 @@
## Multithreading
# Multithreading
The general rule for multithreading is that SOCI classes are *not* thread-safe, meaning that their instances should not be used concurrently by multiple threads.
The simplest solution for multithreaded code is to set up a separate `session` object for each thread that needs to inteact with the database. Depending on the design of the client application this might be also the most straightforward approach.
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:
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:
```cpp
// phase 1: preparation
// phase 1: preparation
const size_t poolSize = 10;
connection_pool pool(poolSize);
const size_t poolSize = 10;
connection_pool pool(poolSize);
for (size_t i = 0; i != poolSize; ++i)
{
session &amp; sql = pool.at(i);
for (size_t i = 0; i != poolSize; ++i)
{
session &amp; sql = pool.at(i);
sql.open("postgresql://dbname=mydb");
}
sql.open("postgresql://dbname=mydb");
}
// phase 2: usage from working threads
// phase 2: usage from working threads
{
session sql(pool);
{
session sql(pool);
sql << "select something from somewhere...";
sql << "select something from somewhere...";
} // session is returned to the pool automatically
```
} // 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.
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.
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.
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.

View File

@@ -0,0 +1,20 @@
# Stored Procedures
The `procedure` class provides a convenient mechanism for calling stored procedures:
```cpp
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.

View File

@@ -1,25 +1,30 @@
## Queries
# Queries
### Simple SQL statements
## 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";
```cpp
sql.once << "drop table persons";
```
For shorter syntax, the following form is also allowed:
sql << "drop table persons";
```cpp
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<<`):
```cpp
string tableName = "persons";
sql << "drop table " << tableName;
string tableName = "persons";
sql << "drop table " << tableName;
int id = 123;
sql << "delete from companies where id = " << id;
```
int id = 123;
sql << "delete from companies where id = " << id;
### Query transformation
## Query transformation
In SOCI 3.2.0, query transformation mechanism was introduced.
@@ -31,46 +36,51 @@ For one-time statements, query transformation is performed before each execution
A few short examples how to use query transformation:
*defined as free function:*
* defined as free function:
std::string less_than_ten(std::string query)
```cpp
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:
```cpp
struct order : std::unary_function<std::string, std::string&gt;
{
order(std::string const&amp; by) : by_(by) {}
result_type operator()(argument_type query) const
{
return query + " WHERE price < 10";
return query + " ORDER BY " + by_;
}
session sql(postgresql, "dbname=mydb");
sql.set_query_transformation(less_than_ten);
sql << "DELETE FROM item";
std::string by_;
};
*defined as function object:*
char const* query = "SELECT * FROM product";
sql.set_query_transformation(order("price");
sql << query;
sql.set_query_transformation(order("id");
sql << query;
```
struct order : std::unary_function<std::string, std::string&gt;
{
order(std::string const&amp; by) : by_(by) {}
result_type operator()(argument_type query) const
{
return query + " ORDER BY " + by_;
}
std::string by_;
};
char const* query = "SELECT * FROM product";
sql.set_query_transformation(order("price");
sql << query;
sql.set_query_transformation(order("id");
sql << query;
*defined as lambda function (since C++11):*
std::string dep = "sales";
sql.set_query_transformation(
[&dep](std::string const&amp; query) {
return query + " WHERE department = '" + dep + "'";
});
sql << "SELECT * FROM employee";
* defined as lambda function (since C++11):
```cpp
std::string dep = "sales";
sql.set_query_transformation(
[&dep](std::string const&amp; 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.
@@ -81,4 +91,4 @@ For example, the query transformation may be used to:
* 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)
* apply database-specific features like add optimization hints to SQL statements (i.e. `SELECT /*+RULE*/ A FROM C` in Oracle 9)

View File

@@ -0,0 +1,56 @@
# Quickstart
The following (complete!) example is purposedly provided without any explanation.
```cpp
#include "soci.h"
#include "soci-oracle.h"
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <exception>
using namespace soci;
using namespace std;
bool get_name(string &name) {
cout << "Enter name: ";
return cin >> name;
}
int main()
{
try
{
session sql(oracle, "service=mydb user=john password=secret");
int count;
sql << "select count(*) from phonebook", into(count);
cout << "We have " << count << " entries in the phonebook.\n";
string name;
while (get_name(name))
{
string phone;
indicator ind;
sql << "select phone from phonebook where name = :name",
into(phone, ind), use(name);
if (ind == i_ok)
{
cout << "The phone number is " << phone << '\n';
}
else
{
cout << "There is no phone for " << name << '\n';
}
}
}
catch (exception const &e)
{
cerr << "Error: " << e.what() << '\n';
}
}
```

View File

@@ -1,54 +1,56 @@
## Statements, procedures and transactions
# Statements
* [Statement preparation and repeated execution](#preparation)
* [Rowset and iterator-based access](#rowset)
* [Bulk operations](#bulk)
* [Stored procedures](#procedures)
* [Transactions](#transactions)
* [Basic logging support](#logging)
### <a name="preparation"></a> Statement preparation and repeated execution
## Prepared statement
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);
}
```cpp
// 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 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.
### Statement preparation
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);
}
```cpp
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`".
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
#####Portability note:
> "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.
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.
### <a name="rowset"></a> Rowset and iterator-based access
## Rowset and iterator
The `rowset` class provides an alternative means of executing queries and accessing results using STL-like iterator interface.
@@ -56,68 +58,75 @@ The `rowset_iterator` type is compatible with requirements defined for input ite
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`:
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`:
```cpp
rowset<int> rs = (sql.prepare << "select values from numbers");
rowset<int> rs = (sql.prepare << "select values from numbers");
for (rowset<int>::const_iterator it = rs.begin(); it != rs.end(); ++it)
{
cout << *it << '\n';
}
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](exchange.html#dynamic):
```cpp
// person table has 4 columns
// person table has 4 columns
rowset<row> rs = (sql.prepare << "select id, firstname, lastname, gender from person");
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;
// 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;
}
```
// 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;
}
The `rowset_iterator` can be used with standard algorithms as well:
`rowset_iterator` can be used with standard algorithms as well:
```cpp
rowset<string> rs = (sql.prepare << "select firstname from person");
std::copy(rs.begin(), rs.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
```
rowset<string> rs = (sql.prepare << "select firstname from person");
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.
std::copy(rs.begin(), rs.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
## Bulk operations
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.
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.
### Bulk operations
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`:
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.
```cpp
// Example 3.
void fill_ids(std::vector<int>& ids)
{
for (std::size_t i = 0; i < ids.size(); ++i)
ids[i] = i; // mimics source of a new ID
}
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`:
const int BATCH_SIZE = 25;
std::vector<int> ids(BATCH_SIZE);
// Example 3.
void fill_ids(std::vector<int>& 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<int> 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);
}
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.
@@ -125,52 +134,60 @@ Given batch size is 25, this example should insert 4 x 25 = 100 records.
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';
}
```cpp
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.
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`.
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);
```cpp
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.
Above, the value `100` indicates that no more values should be retrieved, even if it would be otherwise possible.
If there are less rows than asked for, the vector will be appropriately down-sized.
The `statement::execute()` and `statement::fetch()` functions can also be used to repeatedly select all rows returned by a query into a vector based type:
const int BATCH_SIZE = 30;
std::vector<int> valsOut(BATCH_SIZE);
statement st = (sql.prepare <<
"select value from numbers",
into(valsOut));
st.execute();
while (st.fetch())
```cpp
const int BATCH_SIZE = 30;
std::vector<int> valsOut(BATCH_SIZE);
statement st = (sql.prepare <<
"select value from numbers",
into(valsOut));
st.execute();
while (st.fetch())
{
std::vector<int>::iterator pos;
for(pos = valsOut.begin(); pos != valsOut.end(); ++pos)
{
std::vector<int>::iterator pos;
for(pos = valsOut.begin(); pos != valsOut.end(); ++pos)
{
cout << *pos << '\n';
}
valsOut.resize(BATCH_SIZE);
cout << *pos << '\n';
}
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.
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:
@@ -179,133 +196,54 @@ Note the following details about the above examples:
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
### Portability note
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`.
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.
sql << "CREATE TABLE test(a INTEGER)";
## 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`.
```cpp
sql << "CREATE TABLE test(a INTEGER)";
{
// prepare statement
soci::statement stmt = (db.prepare << "INSERT INTO numbers(value) VALUES(:val)");
{
// prepare statement
soci::statement stmt = (db.prepare << "INSERT INTO numbers(value) VALUES(:val)");
// first insert
int a0 = 0;
{
// first insert
int a0 = 0;
// update reference
stmt.exchange(soci::use(a0));
// 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();
}
stmt.define_and_bind();
stmt.execute(true);
stmt.bind_clean_up();
}
{
std::vector<int> 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;
// 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();
}
}
#####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.
### <a name="procedures"></a> 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.
### <a name="transactions"></a> 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.
### <a name="logging"></a> 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.
{
std::vector<int> 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;
}
```

View File

@@ -1,27 +1,27 @@
## Structure
# 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 picture below 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.
![Structure Chart](images/structure.png)
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 <i>simple interface</i>, which was designed specifically for the "C" calling convention to ensure easy binding.
* Other languages can use the [simple interface](interfaces.md), 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:
```cpp
#include "soci.h"
// other includes if necessary
#include "soci.h"
// other includes if necessary
using namespace soci;
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.
---
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.

View File

@@ -0,0 +1,45 @@
# 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:
```cpp
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:
```cpp
{
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.

292
src/soci/docs/types.md Normal file
View File

@@ -0,0 +1,292 @@
# Data Types
## Static 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)
* `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 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.
Bulk operations are supported also for `std::vector`s of the user-provided types that have appropriate conversion routines defines.
## Dynamic 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 binding dynamic resultset 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:
```cpp
row r;
sql << "select * from some_table", into(r);
std::ostringstream doc;
doc << "<row>" << std::endl;
for(std::size_t i = 0; i != r.size(); ++i)
{
const column_properties & props = r.get_properties(i);
doc << '<' << props.get_name() << '>';
switch(props.get_data_type())
{
case dt_string:
doc << r.get<std::string>(i);
break;
case dt_double:
doc << r.get<double>(i);
break;
case dt_integer:
doc << r.get<int>(i);
break;
case dt_long_long:
doc << r.get<long long>(i);
break;
case dt_unsigned_long_long:
doc << r.get<unsigned long long>(i);
break;
case dt_date:
std::tm when = r.get<std::tm>(i);
doc << asctime(&when);
break;
}
doc << "</" << props.get_name() << '>' << std::endl;
}
doc << "</row>";
```
The type `T` parameter that should be passed to `row::get<T>()` depends on the SOCI data type that is returned from `column_properties::get_data_type()`.
`row::get<T>()` throws an exception of type `std::bad_cast` if an incorrect type `T` is requested.
| SOCI Data Type | `row::get<T>` specialization |
|----------------|------------------------------|
| `dt_double` | `double` |
| `dt_integer` | `int` |
| `dt_long_long` | `long long` |
| `dt_unsigned_long_long` | `unsigned long long`|
| `dt_string` | `std::string` |
| `dt_date` | `std::tm` |
The mapping of underlying database column types to SOCI datatypes is database specific.
See the [backend documentation](backends/index.html) for details.
The `row` also provides access to indicators for each column:
```cpp
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:
```cpp
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.
## 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` structure 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:
```cpp
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:
```cpp
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](boost.html) for complete description. Use these as examples of conversions for more complext data types.
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:
```cpp
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:
```cpp
session sql(oracle, "service=db1 user=scott password=tiger");
Person p;
p.id = 1;
p.lastName = "Smith";
p.firstName = "Pat";
sql << "insert into person(id, first_name, last_name) "
"values(:ID, :FIRST_NAME, :LAST_NAME)", use(p);
Person p1;
sql << "select * from person", into(p1);
assert(p1.id == 1);
assert(p1.firstName + p.lastName == "PatSmith");
assert(p1.gender == "unknown");
p.firstName = "Patricia";
sql << "update person set first_name = :FIRST_NAME "
"where id = :ID", use(p);
```
Note: The `values` class is currently not suited for use outside of `type_conversion`specializations.
It is specially designed to facilitate object-relational mapping when used as shown above.

151
src/soci/docs/utilities.md Normal file
View File

@@ -0,0 +1,151 @@
# Utilities
SOCI provides a portable abstraction for selection of database queries.
## DDL
SOCI supports some basic methods to construct portable DDL queries. That is, instead of writing explicit SQL statement for creating or modifying tables, it is possible to use dedicated SOCI functions, which prepare appropriate DDL statements behind the scenes, thus enabling the user application to create basic database structures in a way that is portable across different database servers. Note that the actual support for these functions depends on the actual backend implementation.
It is possible to create a new table in a single statement:
```cpp
sql.create_table("t1").column("i", soci::dt_integer).column("j", soci::dt_integer);
```
Above, table "t1" will be created with two columns ("i", "j") of type integer.
It is also possible to build similar statements piece by piece, which is useful if the table structure is computed dynamically:
```cpp
{
soci::ddl_type ddl = sql.create_table("t2");
ddl.column("i", soci::dt_integer);
ddl.column("j", soci::dt_integer);
ddl.column("k", soci::dt_integer)("not null");
ddl.primary_key("t2_pk", "j");
}
```
The actual statement is executed at the end of above block, when the ddl object goes out of scope. The "not null" constraint was added to the definition of column "k" explicitly and in fact any piece of SQL can be inserted this way - with the obvious caveat of having limited portability (the "not null" piece seems to be universaly portable).
Columns can be added to and dropped from already existing tables as well:
```cpp
sql.add_column("t1", "k", soci::dt_integer);
// or with constraint:
//sql.add_column("t1", "k", soci::dt_integer)("not null");
sql.drop_column("t1", "i");
```
If needed, precision and scale can be defined with additional integer arguments to functions that create columns:
```cpp
sql.add_column("t1", "s", soci::dt_string, precision);
sql.add_column("t1", "d", soci::dt_double, precision, scale);
```
Tables with foreign keys to each other can be also created:
```cpp
{
soci::ddl_type ddl = sql.create_table("t3");
ddl.column("x", soci::dt_integer);
ddl.column("y", soci::dt_integer);
ddl.foreign_key("t3_fk", "x", "t2", "j");
}
```
Tables can be dropped, too:
```cpp
sql.drop_table("t1");
sql.drop_table("t3");
sql.drop_table("t2");
```
Note that due to the differences in the set of types that are actually supported on the target database server, the type mappings, as well as precision and scales, might be different, even in the way that makes them impossible to portably recover with metadata queries.
In the category of portability utilities, the following functions are also available:
```cpp
sql.empty_blob()
```
the above call returns the string containing expression that represents an empty BLOB value in the given target backend. This expression can be used as part of a bigger SQL statement, for example:
```cpp
sql << "insert into my_table (x) values (" + sql.empty_blob() + ")";
```
and:
```cpp
sql.nvl()
```
the above call returns the string containing the name of the SQL function that implements the NVL or COALESCE operation in the given target backend, for example:
```cpp
sql << "select name, " + sql.nvl() + "(phone, \'UNKNOWN\') from phone_book";
```
Note: `empty_blob` and `nvl` are implemented in Oracle, PostgreSQL and SQLite3 backends; for other backends their behaviour is as for PostgreSQL.
## DML
Only two related functions are currently available in this category:
`get_dummy_from_clause()` can be used to construct select statements that don't
operate on any table in a portable way, as while some databases allow simply
omitting the from clause in this case, others -- e.g. Oracle -- still require
providing some syntactically valid from clause even if it is not used. To use
this function, simply append the result of this function to the statement:
```cpp
double databasePi;
session << ("select 4*atan(1)" + session.get_dummy_from_clause()),
into(databasePi);
```
If just the name of the dummy table is needed, and not the full clause, you can
use `get_dummy_from_table()` to obtain it.
Notice that both functions require the session to be connected as their result
depends on the database it is connected to.
## Database Metadata
It is possible to portably query the database server to obtain basic metadata information.
In order to get the list of table names in the current schema:
```cpp
std::vector<std::string> names(100);
sql.get_table_names(), into(names);
```
alternatively:
```cpp
std::string name;
soci::statement st = (sql.prepare_table_names(), into(name));
st.execute();
while (st.fetch())
{
// ...
}
```
Similarly, to get the description of all columns in the given table:
```cpp
soci::column_info ci;
soci::statement st = (sql.prepare_column_descriptions(table_name), into(ci));
st.execute();
while (st.fetch())
{
// ci fields describe each column in turn
}
```

125
src/soci/docs/vagrant.md Normal file
View File

@@ -0,0 +1,125 @@
# Vagrant SOCI
[Vagrant](https://www.vagrantup.com/) used to build and provision
virtual environments for **hassle-free** SOCI development.
## Features
* Ubuntu 14.04 (Trusty) virtual machine
* Multi-machine set-up with three VMs: `soci`, `oracle`, `db2`.
* Support networking between the configured machines.
* `soci.vm`:
* hostname: `vmsoci.local`
* build essentials
* core dependencies
* backend dependencies
* FOSS databases installed with sample `soci` user and instance pre-configured
* during provision, automatically clones and builds SOCI from `master` branch.
* `db2.vm`:
* hostname: `vmdb2.local`
* IBM DB2 Express-C 9.7 installed from [archive.canonical.com](http://archive.canonical.com) packages.
* `oracle.vm`:
* *TODO*: provision with Oracle XE
* SOCI local git repository (aka `$SOCI_HOME`) is automatically shared on host
and all guest machines.
## Prerequisites
* Speedy broadband, time and coffee.
* Recommended 4GB or much more RAM (tested with 16GB only).
### SOCI DB2 backend
The `soci.vm` will be configured properly to build the DB2 backend only if
it is provisioned with complete DB2 CLI client (libraries and headers).
You need to download "IBM Data Server Driver Package (DS Driver)" manually
and make it visible to Vagrant:
1. Go to [IBM Data Server Client Packages](http://www-01.ibm.com/support/docview.wss?uid=swg21385217).
2. Download "IBM Data Server Driver Package (DS Driver)".
3. Copy the package to `${SOCI_HOME}/tmp` directory, on host machine.
## Usage
Below, simple and easy development workflow with Vagrant is outlined:
* [Boot](https://docs.vagrantup.com/v2/getting-started/up.html)
```console
vagrant up
```
or boot VMs selectively:
```console
vagrant up {soci|db2}
```
First time you run it, be patient as Vagrant downloads VM box and
provisions it installing all the necessary packages.
* You can SSH into the machine
```console
vagrant ssh {soci|db2}
```
* Run git commands can either from host or VM `soci` (once connected via SSH)
```console
cd /vagrant # aka $SOCI_HOME
git pull origin master
```
* You can edit source code on both, on host or VM `soci`.
* For example, edit in your favourite editor on host machine, then build, run, test and debug on guest machine from command line.
* Alternatively, edit and build on host machine using your favourite IDE, then test and debug connecting to DBs on guest machines via network.
* Build on VM `soci`
```console
vagrant ssh soci
cd /vagrant # aka $SOCI_HOME
cd soci-build # aka $SOCI_BUILD
make
```
You can also execute the `build.h` script provided to run CMake and make
```console
vagrant ssh soci
cd $SOCI_BUILD
/vagrant/scripts/vagrant/build.sh
```
* Debug, only on VM `soci`, for example, with gdb or remotely Visual Studio 2017.
* [Teardown](https://docs.vagrantup.com/v2/getting-started/teardown.html)
```console
vagrant {suspend|halt|destroy} {soci|db2}
```
Check Vagrant [command-line interface](https://docs.vagrantup.com/v2/cli/index.html) for complete list of commands.
### Environment variables
All variables available to the `vagrant` user on the VMs are defined in and sourced from `/vagrant/scripts/vagrant/common.env`:
* `SOCI_HOME` where SOCI master is cloned (`/vagrant` on VM `soci`)
* `SOCI_BUILD` where CMake generates build configuration (`/home/vagrant/soci-build` on VM `soci`)
* `SOCI_HOST` network accessible VM `soci` hostname (`ping vmsoci.local`)
* `SOCI_USER` default database user and database name
* `SOCI_PASS` default database password for both, `SOCI_USER` and root/sysdba
of particular database.
* `SOCI_DB2_HOST` network accessible VM `db2` hostname (`ping vmdb2.local`)
* `SOCI_DB2_USER` admin username to DB2 instance.
* `SOCI_DB2_USER` admin password to DB2 instance.
Note, those variables are also used by provision scripts to set up databases.
## Troubleshooting
* Analyze `vagrant up` output.
* On Windows, prefer `vagrant ssh` from inside MinGW Shell where `ssh.exe` is available or learn how to use Vagrant with PuTTY.
* If you modify any of `scripts/vagrant/*.sh` scripts, **ensure** they have unified end-of-line characters to `LF` only. Otherwise, provisioning steps may fail.

View File

@@ -9,6 +9,7 @@
#define SOCI_EXCHANGE_CAST_H_INCLUDED
#include "soci/soci-backend.h"
#include "soci/type-wrappers.h"
#include <ctime>
@@ -69,6 +70,18 @@ struct exchange_type_traits<x_stdtm>
typedef std::tm value_type;
};
template <>
struct exchange_type_traits<x_longstring>
{
typedef long_string value_type;
};
template <>
struct exchange_type_traits<x_xmltype>
{
typedef xml_type value_type;
};
// exchange_type_traits not defined for x_statement, x_rowid and x_blob here.
template <exchange_type e>

View File

@@ -39,6 +39,11 @@ mktime_from_ymdhms(tm& t,
mktime(&t);
}
// Helper function for parsing datetime values.
//
// Throws if the string in buf couldn't be parsed as a date or a time string.
SOCI_DECL void parse_std_tm(char const *buf, std::tm &t);
} // namespace details
} // namespace soci

View File

@@ -1,6 +1,7 @@
#ifndef SOCI_BIND_VALUES_H_INCLUDED
#define SOCI_BIND_VALUES_H_INCLUDED
#include "soci/soci-platform.h"
#include "exchange-traits.h"
#include "into-type.h"
#include "into.h"
@@ -9,10 +10,10 @@
#include "use.h"
#ifdef HAVE_BOOST
#ifdef SOCI_HAVE_BOOST
# include <boost/fusion/algorithm/iteration/for_each.hpp>
# include <boost/mpl/bool.hpp>
#endif // HAVE_BOOST
#endif // SOCI_HAVE_BOOST
#include <vector>
namespace soci
@@ -35,15 +36,15 @@ public:
template <typename T, typename Indicator>
void exchange(use_container<T, Indicator> const &uc)
{
#ifdef HAVE_BOOST
#ifdef SOCI_HAVE_BOOST
exchange_(uc, (typename boost::fusion::traits::is_sequence<T>::type *)NULL);
#else
exchange_(uc, NULL);
#endif // HAVE_BOOST
#endif // SOCI_HAVE_BOOST
}
private:
#ifdef HAVE_BOOST
#ifdef SOCI_HAVE_BOOST
template <typename T, typename Indicator>
struct use_sequence
{
@@ -91,7 +92,7 @@ private:
boost::fusion::for_each(uc.t, use_sequence<T, details::no_indicator>(*this));
}
#endif // HAVE_BOOST
#endif // SOCI_HAVE_BOOST
template <typename T, typename Indicator>
void exchange_(use_container<T, Indicator> const &uc, ...)
@@ -125,15 +126,15 @@ public:
template <typename T, typename Indicator>
void exchange(into_container<T, Indicator> const &ic)
{
#ifdef HAVE_BOOST
#ifdef SOCI_HAVE_BOOST
exchange_(ic, (typename boost::fusion::traits::is_sequence<T>::type *)NULL);
#else
exchange_(ic, NULL);
#endif // HAVE_BOOST
#endif // SOCI_HAVE_BOOST
}
private:
#ifdef HAVE_BOOST
#ifdef SOCI_HAVE_BOOST
template <typename T, typename Indicator>
struct into_sequence
{
@@ -180,7 +181,7 @@ private:
{
boost::fusion::for_each(ic.t, into_sequence<T, details::no_indicator>(*this));
}
#endif // HAVE_BOOST
#endif // SOCI_HAVE_BOOST
template <typename T, typename Indicator>
void exchange_(into_container<T, Indicator> const &ic, ...)

View File

@@ -30,10 +30,24 @@ public:
~blob();
std::size_t get_len();
// offset is backend-specific
std::size_t read(std::size_t offset, char * buf, std::size_t toRead);
// offset starts from 0
std::size_t read_from_start(char * buf, std::size_t toRead,
std::size_t offset = 0);
// offset is backend-specific
std::size_t write(std::size_t offset, char const * buf,
std::size_t toWrite);
// offset starts from 0
std::size_t write_from_start(const char * buf, std::size_t toWrite,
std::size_t offset = 0);
std::size_t append(char const * buf, std::size_t toWrite);
void trim(std::size_t newLen);
details::blob_backend * get_backend() { return backEnd_; }

View File

@@ -11,16 +11,11 @@
#include "soci/type-conversion-traits.h"
// boost
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
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 <typename T>
struct type_conversion<boost::optional<T> >
@@ -36,7 +31,7 @@ struct type_conversion<boost::optional<T> >
}
else
{
T tmp;
T tmp = T();
type_conversion<T>::from_base(in, ind, tmp);
out = tmp;
}
@@ -58,8 +53,4 @@ struct type_conversion<boost::optional<T> >
} // namespace soci
#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ > 6)
#pragma GCC diagnostic pop
#endif
#endif // SOCI_BOOST_OPTIONAL_H_INCLUDED

View File

@@ -0,0 +1,47 @@
//
// Copyright (C) 2015 Maciej Sobczak
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef SOCI_CALLBACKS_H_INCLUDED
#define SOCI_CALLBACKS_H_INCLUDED
namespace soci
{
class session;
// Simple callback interface for reporting failover events.
// The meaning of each operation is intended to be portable,
// but the behaviour details and parameters can be backend-specific.
class SOCI_DECL failover_callback
{
public:
// Called when the failover operation has started,
// after discovering connectivity problems.
virtual void started() {}
// Called after successful failover and creating a new connection;
// the sql parameter denotes the new connection and allows the user
// to replay any initial sequence of commands (like session configuration).
virtual void finished(session & /* sql */) {}
// Called when the attempt to reconnect failed,
// if the user code sets the retry parameter to true,
// then new connection will be attempted;
// the newTarget connection string is a hint that can be ignored
// by external means.
virtual void failed(bool & /* out */ /* retry */,
std::string & /* out */ /* newTarget */) {}
// Called when there was a failure that prevents further failover attempts.
virtual void aborted() {}
};
} // namespace soci
#endif // SOCI_CALLBACKS_H_INCLUDED

View File

@@ -0,0 +1,123 @@
//
// Copyright (C) 2016 Maciej Sobczak
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef SOCI_COLUMN_INFO_H_INCLUDED
#define SOCI_COLUMN_INFO_H_INCLUDED
#include "soci/soci-backend.h"
#include "soci/type-conversion.h"
#include "soci/values.h"
namespace soci
{
struct SOCI_DECL column_info
{
std::string name;
data_type type;
std::size_t length; // meaningful for text columns only
std::size_t precision;
std::size_t scale;
bool nullable;
};
template <>
struct type_conversion<column_info>
{
typedef values base_type;
static std::size_t get_numeric_value(const values & v,
const std::string & field_name)
{
data_type dt = v.get_properties(field_name).get_data_type();
switch (dt)
{
case dt_double:
return static_cast<std::size_t>(
v.get<double>(field_name, 0.0));
case dt_integer:
return static_cast<std::size_t>(
v.get<int>(field_name, 0));
case dt_long_long:
return static_cast<std::size_t>(
v.get<long long>(field_name, 0ll));
case dt_unsigned_long_long:
return static_cast<std::size_t>(
v.get<unsigned long long>(field_name, 0ull));
break;
default:
return 0u;
}
}
static void from_base(values const & v, indicator /* ind */, column_info & ci)
{
ci.name = v.get<std::string>("COLUMN_NAME");
ci.length = get_numeric_value(v, "CHARACTER_MAXIMUM_LENGTH");
ci.precision = get_numeric_value(v, "NUMERIC_PRECISION");
ci.scale = get_numeric_value(v, "NUMERIC_SCALE");
const std::string & type_name = v.get<std::string>("DATA_TYPE");
if (type_name == "text" || type_name == "TEXT" ||
type_name == "clob" || type_name == "CLOB" ||
type_name.find("char") != std::string::npos ||
type_name.find("CHAR") != std::string::npos)
{
ci.type = dt_string;
}
else if (type_name == "integer" || type_name == "INTEGER")
{
ci.type = dt_integer;
}
else if (type_name.find("number") != std::string::npos ||
type_name.find("NUMBER") != std::string::npos ||
type_name.find("numeric") != std::string::npos ||
type_name.find("NUMERIC") != std::string::npos)
{
if (ci.scale != 0)
{
ci.type = dt_double;
}
else
{
ci.type = dt_integer;
}
}
else if (type_name.find("time") != std::string::npos ||
type_name.find("TIME") != std::string::npos ||
type_name.find("date") != std::string::npos ||
type_name.find("DATE") != std::string::npos)
{
ci.type = dt_date;
}
else if (type_name.find("blob") != std::string::npos ||
type_name.find("BLOB") != std::string::npos ||
type_name.find("oid") != std::string::npos ||
type_name.find("OID") != std::string::npos)
{
ci.type = dt_blob;
}
else if (type_name.find("xml") != std::string::npos ||
type_name.find("XML") != std::string::npos)
{
ci.type = dt_xml;
}
else
{
// this seems to be a safe default
ci.type = dt_string;
}
const std::string & nullable_s = v.get<std::string>("IS_NULLABLE");
ci.nullable = (nullable_s == "YES");
}
};
} // namespace soci
#endif // SOCI_COLUMN_INFO_H_INCLUDED

View File

@@ -32,6 +32,7 @@ public:
// Retrieve the backend and the connection strings specified in the ctor.
backend_factory const * get_factory() const { return factory_; }
void set_connect_string(const std::string & connectString) { connectString_ = connectString; }
std::string const & get_connect_string() const { return connectString_; }
// Set the value of the given option, overwriting any previous value.

View File

@@ -32,6 +32,8 @@ public:
private:
struct connection_pool_impl;
connection_pool_impl * pimpl_;
SOCI_NOT_COPYABLE(connection_pool)
};
}

View File

@@ -61,10 +61,10 @@ namespace soci
static const std::size_t maxBuffer = 1024 * 1024 * 1024; //CLI limit is about 3 GB, but 1GB should be enough
class db2_soci_error : public soci_error {
class SOCI_DB2_DECL db2_soci_error : public soci_error {
public:
db2_soci_error(std::string const & msg, SQLRETURN rc) : soci_error(msg),errorCode(rc) {};
~db2_soci_error() throw() { };
~db2_soci_error() throw() SOCI_OVERRIDE { };
//We have to extract error information before exception throwing, cause CLI handles could be broken at the construction time
static const std::string sqlState(std::string const & msg,const SQLSMALLINT htype,const SQLHANDLE hndl);
@@ -72,6 +72,12 @@ public:
SQLRETURN errorCode;
};
// Option allowing to specify the "driver completion" parameter of
// SQLDriverConnect(). Its possible values are the same as the allowed values
// for this parameter in the official DB2 CLI, i.e. one of SQL_DRIVER_XXX
// (in string form as all options are strings currently).
extern SOCI_DB2_DECL char const * db2_option_driver_complete;
struct db2_statement_backend;
struct SOCI_DB2_DECL db2_standard_into_type_backend : details::standard_into_type_backend
@@ -80,12 +86,12 @@ struct SOCI_DB2_DECL db2_standard_into_type_backend : details::standard_into_typ
: statement_(st),buf(NULL)
{}
void define_by_pos(int& position, void* data, details::exchange_type type);
void define_by_pos(int& position, void* data, details::exchange_type type) SOCI_OVERRIDE;
void pre_fetch();
void post_fetch(bool gotData, bool calledFromFetch, indicator* ind);
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, bool calledFromFetch, indicator* ind) SOCI_OVERRIDE;
void clean_up();
void clean_up() SOCI_OVERRIDE;
db2_statement_backend& statement_;
@@ -103,15 +109,15 @@ struct SOCI_DB2_DECL db2_vector_into_type_backend : details::vector_into_type_ba
: statement_(st),buf(NULL)
{}
void define_by_pos(int& position, void* data, details::exchange_type type);
void define_by_pos(int& position, void* data, details::exchange_type type) SOCI_OVERRIDE;
void pre_fetch();
void post_fetch(bool gotData, indicator* ind);
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, indicator* ind) SOCI_OVERRIDE;
void resize(std::size_t sz);
std::size_t size();
void resize(std::size_t sz) SOCI_OVERRIDE;
std::size_t size() SOCI_OVERRIDE;
void clean_up();
void clean_up() SOCI_OVERRIDE;
db2_statement_backend& statement_;
@@ -133,13 +139,13 @@ struct SOCI_DB2_DECL db2_standard_use_type_backend : details::standard_use_type_
: statement_(st),buf(NULL),ind(0)
{}
void bind_by_pos(int& position, void* data, details::exchange_type type, bool readOnly);
void bind_by_name(std::string const& name, void* data, details::exchange_type type, bool readOnly);
void bind_by_pos(int& position, void* data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
void bind_by_name(std::string const& name, void* data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
void pre_use(indicator const* ind);
void post_use(bool gotData, indicator* ind);
void pre_use(indicator const* ind) SOCI_OVERRIDE;
void post_use(bool gotData, indicator* ind) SOCI_OVERRIDE;
void clean_up();
void clean_up() SOCI_OVERRIDE;
db2_statement_backend& statement_;
@@ -158,14 +164,14 @@ struct SOCI_DB2_DECL db2_vector_use_type_backend : details::vector_use_type_back
db2_vector_use_type_backend(db2_statement_backend &st)
: statement_(st),buf(NULL) {}
void bind_by_pos(int& position, void* data, details::exchange_type type);
void bind_by_name(std::string const& name, void* data, details::exchange_type type);
void bind_by_pos(int& position, void* data, details::exchange_type type) SOCI_OVERRIDE;
void bind_by_name(std::string const& name, void* data, details::exchange_type type) SOCI_OVERRIDE;
void pre_use(indicator const* ind);
void pre_use(indicator const* ind) SOCI_OVERRIDE;
std::size_t size();
std::size_t size() SOCI_OVERRIDE;
void clean_up();
void clean_up() SOCI_OVERRIDE;
db2_statement_backend& statement_;
@@ -186,27 +192,27 @@ struct SOCI_DB2_DECL db2_statement_backend : details::statement_backend
{
db2_statement_backend(db2_session_backend &session);
void alloc();
void clean_up();
void prepare(std::string const& query, details::statement_type eType);
void alloc() SOCI_OVERRIDE;
void clean_up() SOCI_OVERRIDE;
void prepare(std::string const& query, details::statement_type eType) SOCI_OVERRIDE;
exec_fetch_result execute(int number);
exec_fetch_result fetch(int number);
exec_fetch_result execute(int number) SOCI_OVERRIDE;
exec_fetch_result fetch(int number) SOCI_OVERRIDE;
long long get_affected_rows();
int get_number_of_rows();
std::string get_parameter_name(int index) const;
long long get_affected_rows() SOCI_OVERRIDE;
int get_number_of_rows() SOCI_OVERRIDE;
std::string get_parameter_name(int index) const SOCI_OVERRIDE;
std::string rewrite_for_procedure_call(std::string const& query);
std::string rewrite_for_procedure_call(std::string const& query) SOCI_OVERRIDE;
int prepare_for_describe();
void describe_column(int colNum, data_type& dtype, std::string& columnName);
int prepare_for_describe() SOCI_OVERRIDE;
void describe_column(int colNum, data_type& dtype, std::string& columnName) SOCI_OVERRIDE;
size_t column_size(int col);
db2_standard_into_type_backend* make_into_type_backend();
db2_standard_use_type_backend* make_use_type_backend();
db2_vector_into_type_backend* make_vector_into_type_backend();
db2_vector_use_type_backend* make_vector_use_type_backend();
db2_standard_into_type_backend* make_into_type_backend() SOCI_OVERRIDE;
db2_standard_use_type_backend* make_use_type_backend() SOCI_OVERRIDE;
db2_vector_into_type_backend* make_vector_into_type_backend() SOCI_OVERRIDE;
db2_vector_use_type_backend* make_vector_use_type_backend() SOCI_OVERRIDE;
db2_session_backend& session_;
@@ -222,20 +228,20 @@ struct db2_rowid_backend : details::rowid_backend
{
db2_rowid_backend(db2_session_backend &session);
~db2_rowid_backend();
~db2_rowid_backend() SOCI_OVERRIDE;
};
struct db2_blob_backend : details::blob_backend
{
db2_blob_backend(db2_session_backend& session);
~db2_blob_backend();
~db2_blob_backend() SOCI_OVERRIDE;
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);
std::size_t get_len() SOCI_OVERRIDE;
std::size_t read(std::size_t offset, char* buf, std::size_t toRead) SOCI_OVERRIDE;
std::size_t write(std::size_t offset, char const* buf, std::size_t toWrite) SOCI_OVERRIDE;
std::size_t append(char const* buf, std::size_t toWrite) SOCI_OVERRIDE;
void trim(std::size_t newLen) SOCI_OVERRIDE;
db2_session_backend& session_;
};
@@ -244,26 +250,26 @@ struct db2_session_backend : details::session_backend
{
db2_session_backend(connection_parameters const& parameters);
~db2_session_backend();
~db2_session_backend() SOCI_OVERRIDE;
void begin();
void commit();
void rollback();
void begin() SOCI_OVERRIDE;
void commit() SOCI_OVERRIDE;
void rollback() SOCI_OVERRIDE;
std::string get_backend_name() const { return "DB2"; }
std::string get_dummy_from_table() const SOCI_OVERRIDE { return "sysibm.sysdummy1"; }
std::string get_backend_name() const SOCI_OVERRIDE { return "DB2"; }
void clean_up();
db2_statement_backend* make_statement_backend();
db2_rowid_backend* make_rowid_backend();
db2_blob_backend* make_blob_backend();
db2_statement_backend* make_statement_backend() SOCI_OVERRIDE;
db2_rowid_backend* make_rowid_backend() SOCI_OVERRIDE;
db2_blob_backend* make_blob_backend() SOCI_OVERRIDE;
void parseConnectString(std::string const &);
void parseKeyVal(std::string const &);
std::string dsn;
std::string username;
std::string password;
std::string connection_string_;
bool autocommit;
bool in_transaction;
@@ -275,7 +281,7 @@ struct SOCI_DB2_DECL db2_backend_factory : backend_factory
{
db2_backend_factory() {}
db2_session_backend* make_session(
connection_parameters const & parameters) const;
connection_parameters const & parameters) const SOCI_OVERRIDE;
};
extern SOCI_DB2_DECL db2_backend_factory const db2;

View File

@@ -39,12 +39,12 @@ struct SOCI_EMPTY_DECL empty_standard_into_type_backend : details::standard_into
: statement_(st)
{}
void define_by_pos(int& position, void* data, details::exchange_type type);
void define_by_pos(int& position, void* data, details::exchange_type type) SOCI_OVERRIDE;
void pre_fetch();
void post_fetch(bool gotData, bool calledFromFetch, indicator* ind);
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, bool calledFromFetch, indicator* ind) SOCI_OVERRIDE;
void clean_up();
void clean_up() SOCI_OVERRIDE;
empty_statement_backend& statement_;
};
@@ -55,15 +55,15 @@ struct SOCI_EMPTY_DECL empty_vector_into_type_backend : details::vector_into_typ
: statement_(st)
{}
void define_by_pos(int& position, void* data, details::exchange_type type);
void define_by_pos(int& position, void* data, details::exchange_type type) SOCI_OVERRIDE;
void pre_fetch();
void post_fetch(bool gotData, indicator* ind);
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, indicator* ind) SOCI_OVERRIDE;
void resize(std::size_t sz);
std::size_t size();
void resize(std::size_t sz) SOCI_OVERRIDE;
std::size_t size() SOCI_OVERRIDE;
void clean_up();
void clean_up() SOCI_OVERRIDE;
empty_statement_backend& statement_;
};
@@ -74,13 +74,13 @@ struct SOCI_EMPTY_DECL empty_standard_use_type_backend : details::standard_use_t
: statement_(st)
{}
void bind_by_pos(int& position, void* data, details::exchange_type type, bool readOnly);
void bind_by_name(std::string const& name, void* data, details::exchange_type type, bool readOnly);
void bind_by_pos(int& position, void* data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
void bind_by_name(std::string const& name, void* data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
void pre_use(indicator const* ind);
void post_use(bool gotData, indicator* ind);
void pre_use(indicator const* ind) SOCI_OVERRIDE;
void post_use(bool gotData, indicator* ind) SOCI_OVERRIDE;
void clean_up();
void clean_up() SOCI_OVERRIDE;
empty_statement_backend& statement_;
};
@@ -90,14 +90,14 @@ struct SOCI_EMPTY_DECL empty_vector_use_type_backend : details::vector_use_type_
empty_vector_use_type_backend(empty_statement_backend &st)
: statement_(st) {}
void bind_by_pos(int& position, void* data, details::exchange_type type);
void bind_by_name(std::string const& name, void* data, details::exchange_type type);
void bind_by_pos(int& position, void* data, details::exchange_type type) SOCI_OVERRIDE;
void bind_by_name(std::string const& name, void* data, details::exchange_type type) SOCI_OVERRIDE;
void pre_use(indicator const* ind);
void pre_use(indicator const* ind) SOCI_OVERRIDE;
std::size_t size();
std::size_t size() SOCI_OVERRIDE;
void clean_up();
void clean_up() SOCI_OVERRIDE;
empty_statement_backend& statement_;
};
@@ -107,26 +107,26 @@ struct SOCI_EMPTY_DECL empty_statement_backend : details::statement_backend
{
empty_statement_backend(empty_session_backend &session);
void alloc();
void clean_up();
void prepare(std::string const& query, details::statement_type eType);
void alloc() SOCI_OVERRIDE;
void clean_up() SOCI_OVERRIDE;
void prepare(std::string const& query, details::statement_type eType) SOCI_OVERRIDE;
exec_fetch_result execute(int number);
exec_fetch_result fetch(int number);
exec_fetch_result execute(int number) SOCI_OVERRIDE;
exec_fetch_result fetch(int number) SOCI_OVERRIDE;
long long get_affected_rows();
int get_number_of_rows();
std::string get_parameter_name(int index) const;
long long get_affected_rows() SOCI_OVERRIDE;
int get_number_of_rows() SOCI_OVERRIDE;
std::string get_parameter_name(int index) const SOCI_OVERRIDE;
std::string rewrite_for_procedure_call(std::string const& query);
std::string rewrite_for_procedure_call(std::string const& query) SOCI_OVERRIDE;
int prepare_for_describe();
void describe_column(int colNum, data_type& dtype, std::string& columnName);
int prepare_for_describe() SOCI_OVERRIDE;
void describe_column(int colNum, data_type& dtype, std::string& columnName) SOCI_OVERRIDE;
empty_standard_into_type_backend* make_into_type_backend();
empty_standard_use_type_backend* make_use_type_backend();
empty_vector_into_type_backend* make_vector_into_type_backend();
empty_vector_use_type_backend* make_vector_use_type_backend();
empty_standard_into_type_backend* make_into_type_backend() SOCI_OVERRIDE;
empty_standard_use_type_backend* make_use_type_backend() SOCI_OVERRIDE;
empty_vector_into_type_backend* make_vector_into_type_backend() SOCI_OVERRIDE;
empty_vector_use_type_backend* make_vector_use_type_backend() SOCI_OVERRIDE;
empty_session_backend& session_;
};
@@ -135,20 +135,20 @@ struct empty_rowid_backend : details::rowid_backend
{
empty_rowid_backend(empty_session_backend &session);
~empty_rowid_backend();
~empty_rowid_backend() SOCI_OVERRIDE;
};
struct empty_blob_backend : details::blob_backend
{
empty_blob_backend(empty_session_backend& session);
~empty_blob_backend();
~empty_blob_backend() SOCI_OVERRIDE;
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);
std::size_t get_len() SOCI_OVERRIDE;
std::size_t read(std::size_t offset, char* buf, std::size_t toRead) SOCI_OVERRIDE;
std::size_t write(std::size_t offset, char const* buf, std::size_t toWrite) SOCI_OVERRIDE;
std::size_t append(char const* buf, std::size_t toWrite) SOCI_OVERRIDE;
void trim(std::size_t newLen) SOCI_OVERRIDE;
empty_session_backend& session_;
};
@@ -157,25 +157,27 @@ struct empty_session_backend : details::session_backend
{
empty_session_backend(connection_parameters const& parameters);
~empty_session_backend();
~empty_session_backend() SOCI_OVERRIDE;
void begin();
void commit();
void rollback();
void begin() SOCI_OVERRIDE;
void commit() SOCI_OVERRIDE;
void rollback() SOCI_OVERRIDE;
std::string get_backend_name() const { return "empty"; }
std::string get_dummy_from_table() const SOCI_OVERRIDE { return std::string(); }
std::string get_backend_name() const SOCI_OVERRIDE { return "empty"; }
void clean_up();
empty_statement_backend* make_statement_backend();
empty_rowid_backend* make_rowid_backend();
empty_blob_backend* make_blob_backend();
empty_statement_backend* make_statement_backend() SOCI_OVERRIDE;
empty_rowid_backend* make_rowid_backend() SOCI_OVERRIDE;
empty_blob_backend* make_blob_backend() SOCI_OVERRIDE;
};
struct SOCI_EMPTY_DECL empty_backend_factory : backend_factory
{
empty_backend_factory() {}
empty_session_backend* make_session(connection_parameters const& parameters) const;
empty_session_backend* make_session(connection_parameters const& parameters) const SOCI_OVERRIDE;
};
extern SOCI_EMPTY_DECL empty_backend_factory const empty;

View File

@@ -25,14 +25,14 @@ public:
soci_error(soci_error const& e);
soci_error& operator=(soci_error const& e);
virtual ~soci_error() throw();
~soci_error() throw() SOCI_OVERRIDE;
// Returns just the error message itself, without the context.
std::string get_error_message() const;
// Returns the full error message combining the message given to the ctor
// with all the available context records.
virtual char const* what() const throw();
char const* what() const throw() SOCI_OVERRIDE;
// This is used only by SOCI itself to provide more information about the
// exception as it bubbles up. It can be called multiple times, with the
@@ -40,6 +40,22 @@ public:
// highest level context.
void add_context(std::string const& context);
// Basic error classes.
enum error_category
{
connection_error,
invalid_statement,
no_privilege,
no_data,
constraint_violation,
unknown_transaction_state,
system_error,
unknown
};
// Basic error classification support
virtual error_category get_error_category() const { return unknown; }
private:
// Optional extra information (currently just the context data).
class soci_error_extra_info* info_;

View File

@@ -10,6 +10,7 @@
#include "soci/type-conversion-traits.h"
#include "soci/soci-backend.h"
#include "soci/type-wrappers.h"
// std
#include <ctime>
#include <string>
@@ -131,6 +132,22 @@ struct exchange_traits<std::vector<T> >
enum { x_type = exchange_traits<T>::x_type };
};
// handling of wrapper types
template <>
struct exchange_traits<xml_type>
{
typedef basic_type_tag type_family;
enum { x_type = x_xmltype };
};
template <>
struct exchange_traits<long_string>
{
typedef basic_type_tag type_family;
enum { x_type = x_longstring };
};
} // namespace details
} // namespace soci

View File

@@ -49,7 +49,7 @@ public:
firebird_soci_error(std::string const & msg,
ISC_STATUS const * status = 0);
~firebird_soci_error() throw() {};
~firebird_soci_error() throw() SOCI_OVERRIDE {};
std::vector<ISC_STATUS> status_;
};
@@ -59,21 +59,22 @@ enum BuffersType
eStandard, eVector
};
struct firebird_blob_backend;
struct firebird_statement_backend;
struct firebird_standard_into_type_backend : details::standard_into_type_backend
{
firebird_standard_into_type_backend(firebird_statement_backend &st)
: statement_(st), buf_(NULL)
: statement_(st), data_(NULL), type_(), position_(0), buf_(NULL), indISCHolder_(0)
{}
virtual void define_by_pos(int &position,
void *data, details::exchange_type type);
void define_by_pos(int &position,
void *data, details::exchange_type type) SOCI_OVERRIDE;
virtual void pre_fetch();
virtual void post_fetch(bool gotData, bool calledFromFetch,
indicator *ind);
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, bool calledFromFetch,
indicator *ind) SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
firebird_statement_backend &statement_;
virtual void exchangeData();
@@ -84,24 +85,29 @@ struct firebird_standard_into_type_backend : details::standard_into_type_backend
char *buf_;
short indISCHolder_;
private:
// Copy contents of a BLOB (represented by its id) in buf_ into the given
// string.
void copy_from_blob(std::string& out);
};
struct firebird_vector_into_type_backend : details::vector_into_type_backend
{
firebird_vector_into_type_backend(firebird_statement_backend &st)
: statement_(st), buf_(NULL)
: statement_(st), data_(NULL), type_(), position_(0), buf_(NULL), indISCHolder_(0)
{}
virtual void define_by_pos(int &position,
void *data, details::exchange_type type);
void define_by_pos(int &position,
void *data, details::exchange_type type) SOCI_OVERRIDE;
virtual void pre_fetch();
virtual void post_fetch(bool gotData, indicator *ind);
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, indicator *ind) SOCI_OVERRIDE;
virtual void resize(std::size_t sz);
virtual std::size_t size();
void resize(std::size_t sz) SOCI_OVERRIDE;
std::size_t size() SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
firebird_statement_backend &statement_;
virtual void exchangeData(std::size_t row);
@@ -117,18 +123,19 @@ struct firebird_vector_into_type_backend : details::vector_into_type_backend
struct firebird_standard_use_type_backend : details::standard_use_type_backend
{
firebird_standard_use_type_backend(firebird_statement_backend &st)
: statement_(st), buf_(NULL), indISCHolder_(0)
: statement_(st), data_(NULL), type_(), position_(0), buf_(NULL), indISCHolder_(0),
blob_(NULL)
{}
virtual void bind_by_pos(int &position,
void *data, details::exchange_type type, bool readOnly);
virtual void bind_by_name(std::string const &name,
void *data, details::exchange_type type, bool readOnly);
void bind_by_pos(int &position,
void *data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
void bind_by_name(std::string const &name,
void *data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
virtual void pre_use(indicator const *ind);
virtual void post_use(bool gotData, indicator *ind);
void pre_use(indicator const *ind) SOCI_OVERRIDE;
void post_use(bool gotData, indicator *ind) SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
firebird_statement_backend &statement_;
virtual void exchangeData();
@@ -139,24 +146,32 @@ struct firebird_standard_use_type_backend : details::standard_use_type_backend
char *buf_;
short indISCHolder_;
private:
// Allocate a temporary blob, fill it with the data from the provided
// string and copy its ID into buf_.
void copy_to_blob(const std::string& in);
// This is used for types mapping to CLOB.
firebird_blob_backend* blob_;
};
struct firebird_vector_use_type_backend : details::vector_use_type_backend
{
firebird_vector_use_type_backend(firebird_statement_backend &st)
: statement_(st), inds_(NULL), buf_(NULL), indISCHolder_(0)
: statement_(st), data_(NULL), type_(), position_(0), buf_(NULL), indISCHolder_(0)
{}
virtual void bind_by_pos(int &position,
void *data, details::exchange_type type);
virtual void bind_by_name(std::string const &name,
void *data, details::exchange_type type);
void bind_by_pos(int &position,
void *data, details::exchange_type type) SOCI_OVERRIDE;
void bind_by_name(std::string const &name,
void *data, details::exchange_type type) SOCI_OVERRIDE;
virtual void pre_use(indicator const *ind);
void pre_use(indicator const *ind) SOCI_OVERRIDE;
virtual std::size_t size();
std::size_t size() SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
firebird_statement_backend &statement_;
virtual void exchangeData(std::size_t row);
@@ -175,28 +190,28 @@ struct firebird_statement_backend : details::statement_backend
{
firebird_statement_backend(firebird_session_backend &session);
virtual void alloc();
virtual void clean_up();
virtual void prepare(std::string const &query,
details::statement_type eType);
void alloc() SOCI_OVERRIDE;
void clean_up() SOCI_OVERRIDE;
void prepare(std::string const &query,
details::statement_type eType) SOCI_OVERRIDE;
virtual exec_fetch_result execute(int number);
virtual exec_fetch_result fetch(int number);
exec_fetch_result execute(int number) SOCI_OVERRIDE;
exec_fetch_result fetch(int number) SOCI_OVERRIDE;
virtual long long get_affected_rows();
virtual int get_number_of_rows();
virtual std::string get_parameter_name(int index) const;
long long get_affected_rows() SOCI_OVERRIDE;
int get_number_of_rows() SOCI_OVERRIDE;
std::string get_parameter_name(int index) const SOCI_OVERRIDE;
virtual std::string rewrite_for_procedure_call(std::string const &query);
std::string rewrite_for_procedure_call(std::string const &query) SOCI_OVERRIDE;
virtual int prepare_for_describe();
virtual void describe_column(int colNum, data_type &dtype,
std::string &columnName);
int prepare_for_describe() SOCI_OVERRIDE;
void describe_column(int colNum, data_type &dtype,
std::string &columnName) SOCI_OVERRIDE;
virtual firebird_standard_into_type_backend * make_into_type_backend();
virtual firebird_standard_use_type_backend * make_use_type_backend();
virtual firebird_vector_into_type_backend * make_vector_into_type_backend();
virtual firebird_vector_use_type_backend * make_vector_use_type_backend();
firebird_standard_into_type_backend * make_into_type_backend() SOCI_OVERRIDE;
firebird_standard_use_type_backend * make_use_type_backend() SOCI_OVERRIDE;
firebird_vector_into_type_backend * make_vector_into_type_backend() SOCI_OVERRIDE;
firebird_vector_use_type_backend * make_vector_use_type_backend() SOCI_OVERRIDE;
firebird_session_backend &session_;
@@ -242,15 +257,15 @@ struct firebird_blob_backend : details::blob_backend
{
firebird_blob_backend(firebird_session_backend &session);
~firebird_blob_backend();
~firebird_blob_backend() SOCI_OVERRIDE;
virtual std::size_t get_len();
virtual std::size_t read(std::size_t offset, char *buf,
std::size_t toRead);
virtual std::size_t write(std::size_t offset, char const *buf,
std::size_t toWrite);
virtual std::size_t append(char const *buf, std::size_t toWrite);
virtual void trim(std::size_t newLen);
std::size_t get_len() SOCI_OVERRIDE;
std::size_t read(std::size_t offset, char *buf,
std::size_t toRead) SOCI_OVERRIDE;
std::size_t write(std::size_t offset, char const *buf,
std::size_t toWrite) SOCI_OVERRIDE;
std::size_t append(char const *buf, std::size_t toWrite) SOCI_OVERRIDE;
void trim(std::size_t newLen) SOCI_OVERRIDE;
firebird_session_backend &session_;
@@ -293,22 +308,24 @@ struct firebird_session_backend : details::session_backend
{
firebird_session_backend(connection_parameters const & parameters);
~firebird_session_backend();
~firebird_session_backend() SOCI_OVERRIDE;
virtual void begin();
virtual void commit();
virtual void rollback();
void begin() SOCI_OVERRIDE;
void commit() SOCI_OVERRIDE;
void rollback() SOCI_OVERRIDE;
virtual bool get_next_sequence_value(session & s,
std::string const & sequence, long & value);
bool get_next_sequence_value(session & s,
std::string const & sequence, long & value) SOCI_OVERRIDE;
virtual std::string get_backend_name() const { return "firebird"; }
std::string get_dummy_from_table() const SOCI_OVERRIDE { return "rdb$database"; }
std::string get_backend_name() const SOCI_OVERRIDE { return "firebird"; }
void cleanUp();
virtual firebird_statement_backend * make_statement_backend();
virtual details::rowid_backend* make_rowid_backend();
virtual firebird_blob_backend * make_blob_backend();
firebird_statement_backend * make_statement_backend() SOCI_OVERRIDE;
details::rowid_backend* make_rowid_backend() SOCI_OVERRIDE;
firebird_blob_backend * make_blob_backend() SOCI_OVERRIDE;
bool get_option_decimals_as_strings() { return decimals_as_strings_; }
@@ -328,8 +345,8 @@ private:
struct firebird_backend_factory : backend_factory
{
firebird_backend_factory() {}
virtual firebird_session_backend * make_session(
connection_parameters const & parameters) const;
firebird_session_backend * make_session(
connection_parameters const & parameters) const SOCI_OVERRIDE;
};
extern SOCI_FIREBIRD_DECL firebird_backend_factory const firebird;

View File

@@ -1,5 +1,5 @@
//
// Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton
// Copyright (C) 2004-2016 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)
@@ -36,6 +36,7 @@ public:
virtual ~into_type_base() {}
virtual void define(statement_impl & st, int & position) = 0;
virtual void pre_exec(int num) = 0;
virtual void pre_fetch() = 0;
virtual void post_fetch(bool gotData, bool calledFromFetch) = 0;
virtual void clean_up() = 0;
@@ -56,17 +57,18 @@ public:
standard_into_type(void * data, exchange_type type, indicator & ind)
: data_(data), type_(type), ind_(&ind), backEnd_(NULL) {}
virtual ~standard_into_type();
~standard_into_type() SOCI_OVERRIDE;
protected:
virtual void post_fetch(bool gotData, bool calledFromFetch);
void post_fetch(bool gotData, bool calledFromFetch) SOCI_OVERRIDE;
private:
virtual void define(statement_impl & st, int & position);
virtual void pre_fetch();
virtual void clean_up();
void define(statement_impl & st, int & position) SOCI_OVERRIDE;
void pre_exec(int num) SOCI_OVERRIDE;
void pre_fetch() SOCI_OVERRIDE;
void clean_up() SOCI_OVERRIDE;
virtual std::size_t size() const { return 1; }
std::size_t size() const SOCI_OVERRIDE { return 1; }
// conversion hook (from base type to arbitrary user type)
virtual void convert_from_base() {}
@@ -83,27 +85,42 @@ class SOCI_DECL vector_into_type : public into_type_base
{
public:
vector_into_type(void * data, exchange_type type)
: data_(data), type_(type), indVec_(NULL), backEnd_(NULL) {}
: data_(data), type_(type), indVec_(NULL),
begin_(0), end_(NULL), backEnd_(NULL) {}
vector_into_type(void * data, exchange_type type,
std::size_t begin, std::size_t * end)
: data_(data), type_(type), indVec_(NULL),
begin_(begin), end_(end), backEnd_(NULL) {}
vector_into_type(void * data, exchange_type type,
std::vector<indicator> & ind)
: data_(data), type_(type), indVec_(&ind), backEnd_(NULL) {}
: data_(data), type_(type), indVec_(&ind),
begin_(0), end_(NULL), backEnd_(NULL) {}
~vector_into_type();
vector_into_type(void * data, exchange_type type,
std::vector<indicator> & ind,
std::size_t begin, std::size_t * end)
: data_(data), type_(type), indVec_(&ind),
begin_(begin), end_(end), backEnd_(NULL) {}
~vector_into_type() SOCI_OVERRIDE;
protected:
virtual void post_fetch(bool gotData, bool calledFromFetch);
void post_fetch(bool gotData, bool calledFromFetch) SOCI_OVERRIDE;
private:
virtual void define(statement_impl & st, int & position);
virtual void pre_fetch();
virtual void clean_up();
virtual void resize(std::size_t sz);
virtual std::size_t size() const;
void define(statement_impl & st, int & position) SOCI_OVERRIDE;
void pre_exec(int num) SOCI_OVERRIDE;
void pre_fetch() SOCI_OVERRIDE;
void clean_up() SOCI_OVERRIDE;
void resize(std::size_t sz) SOCI_OVERRIDE;
std::size_t size() const SOCI_OVERRIDE;
void * data_;
exchange_type type_;
std::vector<indicator> * indVec_;
std::size_t begin_;
std::size_t * end_;
vector_into_type_backend * backEnd_;
@@ -132,9 +149,21 @@ public:
into_type(std::vector<T> & v)
: vector_into_type(&v,
static_cast<exchange_type>(exchange_traits<T>::x_type)) {}
into_type(std::vector<T> & v, std::size_t begin, std::size_t * end)
: vector_into_type(&v,
static_cast<exchange_type>(exchange_traits<T>::x_type),
begin, end) {}
into_type(std::vector<T> & v, std::vector<indicator> & ind)
: vector_into_type(&v,
static_cast<exchange_type>(exchange_traits<T>::x_type), ind) {}
into_type(std::vector<T> & v, std::vector<indicator> & ind,
std::size_t begin, std::size_t * end)
: vector_into_type(&v,
static_cast<exchange_type>(exchange_traits<T>::x_type), ind,
begin, end) {}
};
// helper dispatchers for basic types
@@ -157,6 +186,20 @@ into_type_ptr do_into(T & t, std::vector<indicator> & ind, basic_type_tag)
return into_type_ptr(new into_type<T>(t, ind));
}
template <typename T>
into_type_ptr do_into(std::vector<T> & t,
std::size_t begin, std::size_t * end, basic_type_tag)
{
return into_type_ptr(new into_type<std::vector<T> >(t, begin, end));
}
template <typename T>
into_type_ptr do_into(std::vector<T> & t, std::vector<indicator> & ind,
std::size_t begin, std::size_t * end, basic_type_tag)
{
return into_type_ptr(new into_type<std::vector<T> >(t, ind, begin, end));
}
} // namespace details
} // namespace soci

View File

@@ -1,5 +1,5 @@
//
// Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton
// Copyright (C) 2004-2016 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)
@@ -67,6 +67,24 @@ details::into_type_ptr into(T & t, std::size_t bufSize)
return details::into_type_ptr(new details::into_type<T>(t, bufSize));
}
// vectors with index ranges
template <typename T>
details::into_type_ptr into(std::vector<T> & t,
std::size_t begin, std::size_t & end)
{
return details::do_into(t, begin, &end,
typename details::exchange_traits<std::vector<T> >::type_family());
}
template <typename T>
details::into_type_ptr into(std::vector<T> & t, std::vector<indicator> & ind,
std::size_t begin, std::size_t & end)
{
return details::do_into(t, ind, begin, &end,
typename details::exchange_traits<std::vector<T> >::type_family());
}
} // namespace soci
#endif // SOCI_INTO_H_INCLUDED

View File

@@ -35,7 +35,7 @@
namespace soci
{
class mysql_soci_error : public soci_error
class SOCI_MYSQL_DECL mysql_soci_error : public soci_error
{
public:
mysql_soci_error(std::string const & msg, int errNum)
@@ -50,14 +50,14 @@ struct mysql_standard_into_type_backend : details::standard_into_type_backend
mysql_standard_into_type_backend(mysql_statement_backend &st)
: statement_(st) {}
virtual void define_by_pos(int &position,
void *data, details::exchange_type type);
void define_by_pos(int &position,
void *data, details::exchange_type type) SOCI_OVERRIDE;
virtual void pre_fetch();
virtual void post_fetch(bool gotData, bool calledFromFetch,
indicator *ind);
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, bool calledFromFetch,
indicator *ind) SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
mysql_statement_backend &statement_;
@@ -71,16 +71,16 @@ struct mysql_vector_into_type_backend : details::vector_into_type_backend
mysql_vector_into_type_backend(mysql_statement_backend &st)
: statement_(st) {}
virtual void define_by_pos(int &position,
void *data, details::exchange_type type);
void define_by_pos(int &position,
void *data, details::exchange_type type) SOCI_OVERRIDE;
virtual void pre_fetch();
virtual void post_fetch(bool gotData, indicator *ind);
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, indicator *ind) SOCI_OVERRIDE;
virtual void resize(std::size_t sz);
virtual std::size_t size();
void resize(std::size_t sz) SOCI_OVERRIDE;
std::size_t size() SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
mysql_statement_backend &statement_;
@@ -94,15 +94,15 @@ struct mysql_standard_use_type_backend : details::standard_use_type_backend
mysql_standard_use_type_backend(mysql_statement_backend &st)
: statement_(st), position_(0), buf_(NULL) {}
virtual void bind_by_pos(int &position,
void *data, details::exchange_type type, bool readOnly);
virtual void bind_by_name(std::string const &name,
void *data, details::exchange_type type, bool readOnly);
void bind_by_pos(int &position,
void *data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
void bind_by_name(std::string const &name,
void *data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
virtual void pre_use(indicator const *ind);
virtual void post_use(bool gotData, indicator *ind);
void pre_use(indicator const *ind) SOCI_OVERRIDE;
void post_use(bool gotData, indicator *ind) SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
mysql_statement_backend &statement_;
@@ -118,16 +118,16 @@ struct mysql_vector_use_type_backend : details::vector_use_type_backend
mysql_vector_use_type_backend(mysql_statement_backend &st)
: statement_(st), position_(0) {}
virtual void bind_by_pos(int &position,
void *data, details::exchange_type type);
virtual void bind_by_name(std::string const &name,
void *data, details::exchange_type type);
void bind_by_pos(int &position,
void *data, details::exchange_type type) SOCI_OVERRIDE;
void bind_by_name(std::string const &name,
void *data, details::exchange_type type) SOCI_OVERRIDE;
virtual void pre_use(indicator const *ind);
void pre_use(indicator const *ind) SOCI_OVERRIDE;
virtual std::size_t size();
std::size_t size() SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
mysql_statement_backend &statement_;
@@ -143,28 +143,28 @@ struct mysql_statement_backend : details::statement_backend
{
mysql_statement_backend(mysql_session_backend &session);
virtual void alloc();
virtual void clean_up();
virtual void prepare(std::string const &query,
details::statement_type eType);
void alloc() SOCI_OVERRIDE;
void clean_up() SOCI_OVERRIDE;
void prepare(std::string const &query,
details::statement_type eType) SOCI_OVERRIDE;
virtual exec_fetch_result execute(int number);
virtual exec_fetch_result fetch(int number);
exec_fetch_result execute(int number) SOCI_OVERRIDE;
exec_fetch_result fetch(int number) SOCI_OVERRIDE;
virtual long long get_affected_rows();
virtual int get_number_of_rows();
virtual std::string get_parameter_name(int index) const;
long long get_affected_rows() SOCI_OVERRIDE;
int get_number_of_rows() SOCI_OVERRIDE;
std::string get_parameter_name(int index) const SOCI_OVERRIDE;
virtual std::string rewrite_for_procedure_call(std::string const &query);
std::string rewrite_for_procedure_call(std::string const &query) SOCI_OVERRIDE;
virtual int prepare_for_describe();
virtual void describe_column(int colNum, data_type &dtype,
std::string &columnName);
int prepare_for_describe() SOCI_OVERRIDE;
void describe_column(int colNum, data_type &dtype,
std::string &columnName) SOCI_OVERRIDE;
virtual mysql_standard_into_type_backend * make_into_type_backend();
virtual mysql_standard_use_type_backend * make_use_type_backend();
virtual mysql_vector_into_type_backend * make_vector_into_type_backend();
virtual mysql_vector_use_type_backend * make_vector_use_type_backend();
mysql_standard_into_type_backend * make_into_type_backend() SOCI_OVERRIDE;
mysql_standard_use_type_backend * make_use_type_backend() SOCI_OVERRIDE;
mysql_vector_into_type_backend * make_vector_into_type_backend() SOCI_OVERRIDE;
mysql_vector_use_type_backend * make_vector_use_type_backend() SOCI_OVERRIDE;
mysql_session_backend &session_;
@@ -209,22 +209,22 @@ struct mysql_rowid_backend : details::rowid_backend
{
mysql_rowid_backend(mysql_session_backend &session);
~mysql_rowid_backend();
~mysql_rowid_backend() SOCI_OVERRIDE;
};
struct mysql_blob_backend : details::blob_backend
{
mysql_blob_backend(mysql_session_backend &session);
~mysql_blob_backend();
~mysql_blob_backend() SOCI_OVERRIDE;
virtual std::size_t get_len();
virtual std::size_t read(std::size_t offset, char *buf,
std::size_t toRead);
virtual std::size_t write(std::size_t offset, char const *buf,
std::size_t toWrite);
virtual std::size_t append(char const *buf, std::size_t toWrite);
virtual void trim(std::size_t newLen);
std::size_t get_len() SOCI_OVERRIDE;
std::size_t read(std::size_t offset, char *buf,
std::size_t toRead) SOCI_OVERRIDE;
std::size_t write(std::size_t offset, char const *buf,
std::size_t toWrite) SOCI_OVERRIDE;
std::size_t append(char const *buf, std::size_t toWrite) SOCI_OVERRIDE;
void trim(std::size_t newLen) SOCI_OVERRIDE;
mysql_session_backend &session_;
};
@@ -233,21 +233,25 @@ struct mysql_session_backend : details::session_backend
{
mysql_session_backend(connection_parameters const & parameters);
~mysql_session_backend();
~mysql_session_backend() SOCI_OVERRIDE;
virtual void begin();
virtual void commit();
virtual void rollback();
void begin() SOCI_OVERRIDE;
void commit() SOCI_OVERRIDE;
void rollback() SOCI_OVERRIDE;
virtual bool get_last_insert_id(session&, std::string const&, long&);
bool get_last_insert_id(session&, std::string const&, long&) SOCI_OVERRIDE;
virtual std::string get_backend_name() const { return "mysql"; }
// Note that MySQL supports both "SELECT 2+2" and "SELECT 2+2 FROM DUAL"
// syntaxes, but there doesn't seem to be any reason to use the longer one.
std::string get_dummy_from_table() const SOCI_OVERRIDE { return std::string(); }
std::string get_backend_name() const SOCI_OVERRIDE { return "mysql"; }
void clean_up();
virtual mysql_statement_backend * make_statement_backend();
virtual mysql_rowid_backend * make_rowid_backend();
virtual mysql_blob_backend * make_blob_backend();
mysql_statement_backend * make_statement_backend() SOCI_OVERRIDE;
mysql_rowid_backend * make_rowid_backend() SOCI_OVERRIDE;
mysql_blob_backend * make_blob_backend() SOCI_OVERRIDE;
MYSQL *conn_;
};
@@ -256,8 +260,8 @@ struct mysql_session_backend : details::session_backend
struct mysql_backend_factory : backend_factory
{
mysql_backend_factory() {}
virtual mysql_session_backend * make_session(
connection_parameters const & parameters) const;
mysql_session_backend * make_session(
connection_parameters const & parameters) const SOCI_OVERRIDE;
};
extern SOCI_MYSQL_DECL mysql_backend_factory const mysql;

View File

@@ -33,6 +33,10 @@
#include <sqlext.h> // ODBC
#include <string.h> // strcpy()
#ifndef SQL_SS_LENGTH_UNLIMITED
#define SQL_SS_LENGTH_UNLIMITED 0
#endif
namespace soci
{
@@ -41,6 +45,10 @@ namespace details
// TODO: Do we want to make it a part of public interface? --mloskot
std::size_t const odbc_max_buffer_length = 100 * 1024 * 1024;
// select max size from following MSDN article
// https://msdn.microsoft.com/en-us/library/ms130896.aspx
SQLLEN const ODBC_MAX_COL_SIZE = 8000;
// This cast is only used to avoid compiler warnings when passing strings
// to ODBC functions, the returned string may *not* be really modified.
inline SQLCHAR* sqlchar_cast(std::string const& s)
@@ -88,14 +96,14 @@ struct odbc_standard_into_type_backend : details::standard_into_type_backend,
: odbc_standard_type_backend_base(st), buf_(0)
{}
virtual void define_by_pos(int &position,
void *data, details::exchange_type type);
void define_by_pos(int &position,
void *data, details::exchange_type type) SOCI_OVERRIDE;
virtual void pre_fetch();
virtual void post_fetch(bool gotData, bool calledFromFetch,
indicator *ind);
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, bool calledFromFetch,
indicator *ind) SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
char *buf_; // generic buffer
void *data_;
@@ -114,16 +122,16 @@ struct odbc_vector_into_type_backend : details::vector_into_type_backend,
: odbc_standard_type_backend_base(st), indHolders_(NULL),
data_(NULL), buf_(NULL) {}
virtual void define_by_pos(int &position,
void *data, details::exchange_type type);
void define_by_pos(int &position,
void *data, details::exchange_type type) SOCI_OVERRIDE;
virtual void pre_fetch();
virtual void post_fetch(bool gotData, indicator *ind);
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, indicator *ind) SOCI_OVERRIDE;
virtual void resize(std::size_t sz);
virtual std::size_t size();
void resize(std::size_t sz) SOCI_OVERRIDE;
std::size_t size() SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
// helper function for preparing indicators
// (as part of the define_by_pos)
@@ -146,15 +154,15 @@ struct odbc_standard_use_type_backend : details::standard_use_type_backend,
: odbc_standard_type_backend_base(st),
position_(-1), data_(0), buf_(0), indHolder_(0) {}
virtual void bind_by_pos(int &position,
void *data, details::exchange_type type, bool readOnly);
virtual void bind_by_name(std::string const &name,
void *data, details::exchange_type type, bool readOnly);
void bind_by_pos(int &position,
void *data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
void bind_by_name(std::string const &name,
void *data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
virtual void pre_use(indicator const *ind);
virtual void post_use(bool gotData, indicator *ind);
void pre_use(indicator const *ind) SOCI_OVERRIDE;
void post_use(bool gotData, indicator *ind) SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
// Return the pointer to the buffer containing data to be used by ODBC.
// This can be either data_ itself or buf_, that is allocated by this
@@ -169,6 +177,15 @@ struct odbc_standard_use_type_backend : details::standard_use_type_backend,
details::exchange_type type_;
char *buf_;
SQLLEN indHolder_;
private:
// Copy string data to buf_ and set size, sqlType and cType to the values
// appropriate for strings.
void copy_from_string(std::string const& s,
SQLLEN& size,
SQLSMALLINT& sqlType,
SQLSMALLINT& cType);
};
struct odbc_vector_use_type_backend : details::vector_use_type_backend,
@@ -187,16 +204,16 @@ struct odbc_vector_use_type_backend : details::vector_use_type_backend,
void bind_helper(int &position,
void *data, details::exchange_type type);
virtual void bind_by_pos(int &position,
void *data, details::exchange_type type);
virtual void bind_by_name(std::string const &name,
void *data, details::exchange_type type);
void bind_by_pos(int &position,
void *data, details::exchange_type type) SOCI_OVERRIDE;
void bind_by_name(std::string const &name,
void *data, details::exchange_type type) SOCI_OVERRIDE;
virtual void pre_use(indicator const *ind);
void pre_use(indicator const *ind) SOCI_OVERRIDE;
virtual std::size_t size();
std::size_t size() SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
SQLLEN *indHolders_;
@@ -214,31 +231,31 @@ struct odbc_statement_backend : details::statement_backend
{
odbc_statement_backend(odbc_session_backend &session);
virtual void alloc();
virtual void clean_up();
virtual void prepare(std::string const &query,
details::statement_type eType);
void alloc() SOCI_OVERRIDE;
void clean_up() SOCI_OVERRIDE;
void prepare(std::string const &query,
details::statement_type eType) SOCI_OVERRIDE;
virtual exec_fetch_result execute(int number);
virtual exec_fetch_result fetch(int number);
exec_fetch_result execute(int number) SOCI_OVERRIDE;
exec_fetch_result fetch(int number) SOCI_OVERRIDE;
virtual long long get_affected_rows();
virtual int get_number_of_rows();
virtual std::string get_parameter_name(int index) const;
long long get_affected_rows() SOCI_OVERRIDE;
int get_number_of_rows() SOCI_OVERRIDE;
std::string get_parameter_name(int index) const SOCI_OVERRIDE;
virtual std::string rewrite_for_procedure_call(std::string const &query);
std::string rewrite_for_procedure_call(std::string const &query) SOCI_OVERRIDE;
virtual int prepare_for_describe();
virtual void describe_column(int colNum, data_type &dtype,
std::string &columnName);
int prepare_for_describe() SOCI_OVERRIDE;
void describe_column(int colNum, data_type &dtype,
std::string &columnName) SOCI_OVERRIDE;
// helper for defining into vector<string>
std::size_t column_size(int position);
virtual odbc_standard_into_type_backend * make_into_type_backend();
virtual odbc_standard_use_type_backend * make_use_type_backend();
virtual odbc_vector_into_type_backend * make_vector_into_type_backend();
virtual odbc_vector_use_type_backend * make_vector_use_type_backend();
odbc_standard_into_type_backend * make_into_type_backend() SOCI_OVERRIDE;
odbc_standard_use_type_backend * make_use_type_backend() SOCI_OVERRIDE;
odbc_vector_into_type_backend * make_vector_into_type_backend() SOCI_OVERRIDE;
odbc_vector_use_type_backend * make_vector_use_type_backend() SOCI_OVERRIDE;
odbc_session_backend &session_;
SQLHSTMT hstmt_;
@@ -258,22 +275,22 @@ struct odbc_rowid_backend : details::rowid_backend
{
odbc_rowid_backend(odbc_session_backend &session);
~odbc_rowid_backend();
~odbc_rowid_backend() SOCI_OVERRIDE;
};
struct odbc_blob_backend : details::blob_backend
{
odbc_blob_backend(odbc_session_backend &session);
~odbc_blob_backend();
~odbc_blob_backend() SOCI_OVERRIDE;
virtual std::size_t get_len();
virtual std::size_t read(std::size_t offset, char *buf,
std::size_t toRead);
virtual std::size_t write(std::size_t offset, char const *buf,
std::size_t toWrite);
virtual std::size_t append(char const *buf, std::size_t toWrite);
virtual void trim(std::size_t newLen);
std::size_t get_len() SOCI_OVERRIDE;
std::size_t read(std::size_t offset, char *buf,
std::size_t toRead) SOCI_OVERRIDE;
std::size_t write(std::size_t offset, char const *buf,
std::size_t toWrite) SOCI_OVERRIDE;
std::size_t append(char const *buf, std::size_t toWrite) SOCI_OVERRIDE;
void trim(std::size_t newLen) SOCI_OVERRIDE;
odbc_session_backend &session_;
};
@@ -282,27 +299,29 @@ struct odbc_session_backend : details::session_backend
{
odbc_session_backend(connection_parameters const & parameters);
~odbc_session_backend();
~odbc_session_backend() SOCI_OVERRIDE;
virtual void begin();
virtual void commit();
virtual void rollback();
void begin() SOCI_OVERRIDE;
void commit() SOCI_OVERRIDE;
void rollback() SOCI_OVERRIDE;
virtual bool get_next_sequence_value(session & s,
std::string const & sequence, long & value);
virtual bool get_last_insert_id(session & s,
std::string const & table, long & value);
bool get_next_sequence_value(session & s,
std::string const & sequence, long & value) SOCI_OVERRIDE;
bool get_last_insert_id(session & s,
std::string const & table, long & value) SOCI_OVERRIDE;
virtual std::string get_backend_name() const { return "odbc"; }
std::string get_dummy_from_table() const SOCI_OVERRIDE;
std::string get_backend_name() const SOCI_OVERRIDE { return "odbc"; }
void configure_connection();
void reset_transaction();
void clean_up();
virtual odbc_statement_backend * make_statement_backend();
virtual odbc_rowid_backend * make_rowid_backend();
virtual odbc_blob_backend * make_blob_backend();
odbc_statement_backend * make_statement_backend() SOCI_OVERRIDE;
odbc_rowid_backend * make_rowid_backend() SOCI_OVERRIDE;
odbc_blob_backend * make_blob_backend() SOCI_OVERRIDE;
enum database_product
{
@@ -317,7 +336,7 @@ struct odbc_session_backend : details::session_backend
};
// Determine the type of the database we're connected to.
database_product get_database_product();
database_product get_database_product() const;
// Return full ODBC connection string.
std::string get_connection_string() const { return connection_string_; }
@@ -326,7 +345,9 @@ struct odbc_session_backend : details::session_backend
SQLHDBC hdbc_;
std::string connection_string_;
database_product product_;
private:
mutable database_product product_;
};
class SOCI_ODBC_DECL odbc_soci_error : public soci_error
@@ -435,8 +456,8 @@ inline bool odbc_standard_type_backend_base::use_string_for_bigint() const
struct odbc_backend_factory : backend_factory
{
odbc_backend_factory() {}
virtual odbc_session_backend * make_session(
connection_parameters const & parameters) const;
odbc_session_backend * make_session(
connection_parameters const & parameters) const SOCI_OVERRIDE;
};
extern SOCI_ODBC_DECL odbc_backend_factory const odbc;

View File

@@ -1,5 +1,5 @@
//
// Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton
// Copyright (C) 2004-2016 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)
@@ -8,15 +8,10 @@
#ifndef SOCI_ONCE_TEMP_TYPE_H_INCLUDED
#define SOCI_ONCE_TEMP_TYPE_H_INCLUDED
#include "soci/soci-platform.h"
#include "soci/ref-counted-statement.h"
#include "soci/prepare-temp-type.h"
#if __cplusplus >= 201103L
#define SOCI_ONCE_TEMP_TYPE_NOEXCEPT noexcept(false)
#else
#define SOCI_ONCE_TEMP_TYPE_NOEXCEPT
#endif
namespace soci
{
@@ -36,7 +31,7 @@ public:
once_temp_type(once_temp_type const & o);
once_temp_type & operator=(once_temp_type const & o);
~once_temp_type() SOCI_ONCE_TEMP_TYPE_NOEXCEPT;
~once_temp_type() SOCI_NOEXCEPT_FALSE;
template <typename T>
once_temp_type & operator<<(T const & t)
@@ -46,6 +41,8 @@ public:
}
once_temp_type & operator,(into_type_ptr const &);
once_temp_type & operator,(use_type_ptr const &);
template <typename T, typename Indicator>
once_temp_type &operator,(into_container<T, Indicator> const &ic)
{
@@ -114,6 +111,50 @@ private:
} // namespace details
// Note: ddl_type is intended to be used just as once_temp_type,
// but since it can be also used directly (explicitly) by the user code,
// it is declared outside of the namespace details.
class SOCI_DECL ddl_type
{
public:
ddl_type(session & s);
ddl_type(const ddl_type & d);
ddl_type & operator=(const ddl_type & d);
~ddl_type() SOCI_NOEXCEPT_FALSE;
void create_table(const std::string & tableName);
void add_column(const std::string & tableName,
const std::string & columnName, data_type dt,
int precision, int scale);
void alter_column(const std::string & tableName,
const std::string & columnName, data_type dt,
int precision, int scale);
void drop_column(const std::string & tableName,
const std::string & columnName);
ddl_type & column(const std::string & columnName, data_type dt,
int precision = 0, int scale = 0);
ddl_type & unique(const std::string & name,
const std::string & columnNames);
ddl_type & primary_key(const std::string & name,
const std::string & columnNames);
ddl_type & foreign_key(const std::string & name,
const std::string & columnNames,
const std::string & refTableName,
const std::string & refColumnNames);
ddl_type & operator()(const std::string & arbitrarySql);
// helper function for handling delimiters
// between various parts of DDL statements
void set_tail(const std::string & tail);
private:
session * s_;
details::ref_counted_statement * rcst_;
};
} // namespace soci
#endif

View File

@@ -1,5 +1,5 @@
//
// Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton
// Copyright (C) 2004-2016 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)
@@ -25,6 +25,7 @@
#include <soci/soci-backend.h>
#include <oci.h> // OCI
#include <sstream>
#include <vector>
#ifdef _MSC_VER
@@ -40,7 +41,10 @@ class SOCI_ORACLE_DECL oracle_soci_error : public soci_error
public:
oracle_soci_error(std::string const & msg, int errNum = 0);
error_category get_error_category() const SOCI_OVERRIDE { return cat_; }
int err_num_;
error_category cat_;
};
@@ -51,20 +55,24 @@ struct oracle_standard_into_type_backend : details::standard_into_type_backend
: statement_(st), defnp_(NULL), indOCIHolder_(0),
data_(NULL), buf_(NULL) {}
virtual void define_by_pos(int &position,
void *data, details::exchange_type type);
void define_by_pos(int &position,
void *data, details::exchange_type type) SOCI_OVERRIDE;
virtual void pre_fetch();
virtual void post_fetch(bool gotData, bool calledFromFetch,
indicator *ind);
void read_from_lob(OCILobLocator * lobp, std::string & value);
virtual void clean_up();
void pre_exec(int num) SOCI_OVERRIDE;
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, bool calledFromFetch,
indicator *ind) SOCI_OVERRIDE;
void clean_up() SOCI_OVERRIDE;
oracle_statement_backend &statement_;
OCIDefine *defnp_;
sb2 indOCIHolder_;
void *data_;
void *ociData_;
char *buf_; // generic buffer
details::exchange_type type_;
@@ -75,18 +83,27 @@ struct oracle_vector_into_type_backend : details::vector_into_type_backend
{
oracle_vector_into_type_backend(oracle_statement_backend &st)
: statement_(st), defnp_(NULL), indOCIHolders_(NULL),
data_(NULL), buf_(NULL) {}
data_(NULL), buf_(NULL), user_ranges_(true) {}
virtual void define_by_pos(int &position,
void *data, details::exchange_type type);
void define_by_pos(int &position,
void *data, details::exchange_type type) SOCI_OVERRIDE
{
user_ranges_ = false;
define_by_pos_bulk(position, data, type, 0, &end_var_);
}
virtual void pre_fetch();
virtual void post_fetch(bool gotData, indicator *ind);
void define_by_pos_bulk(
int & position, void * data, details::exchange_type type,
std::size_t begin, std::size_t * end) SOCI_OVERRIDE;
virtual void resize(std::size_t sz);
virtual std::size_t size();
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, indicator *ind) SOCI_OVERRIDE;
virtual void clean_up();
void resize(std::size_t sz) SOCI_OVERRIDE;
std::size_t size() SOCI_OVERRIDE;
std::size_t full_size();
void clean_up() SOCI_OVERRIDE;
// helper function for preparing indicators and sizes_ vectors
// (as part of the define_by_pos)
@@ -100,6 +117,10 @@ struct oracle_vector_into_type_backend : details::vector_into_type_backend
void *data_;
char *buf_; // generic buffer
details::exchange_type type_;
std::size_t begin_;
std::size_t * end_;
std::size_t end_var_;
bool user_ranges_;
std::size_t colSize_; // size of the string column (used for strings)
std::vector<ub2> sizes_; // sizes of data fetched (used for strings)
@@ -112,24 +133,32 @@ struct oracle_standard_use_type_backend : details::standard_use_type_backend
: statement_(st), bindp_(NULL), indOCIHolder_(0),
data_(NULL), buf_(NULL) {}
virtual void bind_by_pos(int &position,
void *data, details::exchange_type type, bool readOnly);
virtual void bind_by_name(std::string const &name,
void *data, details::exchange_type type, bool readOnly);
void bind_by_pos(int &position,
void *data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
void bind_by_name(std::string const &name,
void *data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
// common part for bind_by_pos and bind_by_name
void prepare_for_bind(void *&data, sb4 &size, ub2 &oracleType, bool readOnly);
virtual void pre_use(indicator const *ind);
virtual void post_use(bool gotData, indicator *ind);
// common helper for pre_use for LOB-directed wrapped types
void write_to_lob(OCILobLocator * lobp, const std::string & value);
virtual void clean_up();
// common lazy initialization of the temporary LOB object
void lazy_temp_lob_init();
void pre_exec(int num) SOCI_OVERRIDE;
void pre_use(indicator const *ind) SOCI_OVERRIDE;
void post_use(bool gotData, indicator *ind) SOCI_OVERRIDE;
void clean_up() SOCI_OVERRIDE;
oracle_statement_backend &statement_;
OCIBind *bindp_;
sb2 indOCIHolder_;
void *data_;
void *ociData_;
bool readOnly_;
char *buf_; // generic buffer
details::exchange_type type_;
@@ -141,10 +170,25 @@ struct oracle_vector_use_type_backend : details::vector_use_type_backend
: statement_(st), bindp_(NULL), indOCIHolders_(NULL),
data_(NULL), buf_(NULL) {}
virtual void bind_by_pos(int &position,
void *data, details::exchange_type type);
virtual void bind_by_name(std::string const &name,
void *data, details::exchange_type type);
void bind_by_pos(int & position,
void * data, details::exchange_type type) SOCI_OVERRIDE
{
bind_by_pos_bulk(position, data, type, 0, &end_var_);
}
void bind_by_pos_bulk(int & position,
void * data, details::exchange_type type,
std::size_t begin, std::size_t * end) SOCI_OVERRIDE;
void bind_by_name(const std::string & name,
void * data, details::exchange_type type) SOCI_OVERRIDE
{
bind_by_name_bulk(name, data, type, 0, &end_var_);
}
void bind_by_name_bulk(std::string const &name,
void *data, details::exchange_type type,
std::size_t begin, std::size_t * end) SOCI_OVERRIDE;
// common part for bind_by_pos and bind_by_name
void prepare_for_bind(void *&data, sb4 &size, ub2 &oracleType);
@@ -153,11 +197,12 @@ struct oracle_vector_use_type_backend : details::vector_use_type_backend
// (as part of the bind_by_pos and bind_by_name)
void prepare_indicators(std::size_t size);
virtual void pre_use(indicator const *ind);
void pre_use(indicator const *ind) SOCI_OVERRIDE;
virtual std::size_t size();
std::size_t size() SOCI_OVERRIDE; // active size (might be lower than full vector size)
std::size_t full_size(); // actual size of the user-provided vector
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
oracle_statement_backend &statement_;
@@ -167,6 +212,9 @@ struct oracle_vector_use_type_backend : details::vector_use_type_backend
void *data_;
char *buf_; // generic buffer
details::exchange_type type_;
std::size_t begin_;
std::size_t * end_;
std::size_t end_var_;
// used for strings only
std::vector<ub2> sizes_;
@@ -178,31 +226,31 @@ struct oracle_statement_backend : details::statement_backend
{
oracle_statement_backend(oracle_session_backend &session);
virtual void alloc();
virtual void clean_up();
virtual void prepare(std::string const &query,
details::statement_type eType);
void alloc() SOCI_OVERRIDE;
void clean_up() SOCI_OVERRIDE;
void prepare(std::string const &query,
details::statement_type eType) SOCI_OVERRIDE;
virtual exec_fetch_result execute(int number);
virtual exec_fetch_result fetch(int number);
exec_fetch_result execute(int number) SOCI_OVERRIDE;
exec_fetch_result fetch(int number) SOCI_OVERRIDE;
virtual long long get_affected_rows();
virtual int get_number_of_rows();
virtual std::string get_parameter_name(int index) const;
long long get_affected_rows() SOCI_OVERRIDE;
int get_number_of_rows() SOCI_OVERRIDE;
std::string get_parameter_name(int index) const SOCI_OVERRIDE;
virtual std::string rewrite_for_procedure_call(std::string const &query);
std::string rewrite_for_procedure_call(std::string const &query) SOCI_OVERRIDE;
virtual int prepare_for_describe();
virtual void describe_column(int colNum, data_type &dtype,
std::string &columnName);
int prepare_for_describe() SOCI_OVERRIDE;
void describe_column(int colNum, data_type &dtype,
std::string &columnName) SOCI_OVERRIDE;
// helper for defining into vector<string>
std::size_t column_size(int position);
virtual oracle_standard_into_type_backend * make_into_type_backend();
virtual oracle_standard_use_type_backend * make_use_type_backend();
virtual oracle_vector_into_type_backend * make_vector_into_type_backend();
virtual oracle_vector_use_type_backend * make_vector_use_type_backend();
oracle_standard_into_type_backend * make_into_type_backend() SOCI_OVERRIDE;
oracle_standard_use_type_backend * make_use_type_backend() SOCI_OVERRIDE;
oracle_vector_into_type_backend * make_vector_into_type_backend() SOCI_OVERRIDE;
oracle_vector_use_type_backend * make_vector_use_type_backend() SOCI_OVERRIDE;
oracle_session_backend &session_;
@@ -217,7 +265,7 @@ struct oracle_rowid_backend : details::rowid_backend
{
oracle_rowid_backend(oracle_session_backend &session);
~oracle_rowid_backend();
~oracle_rowid_backend() SOCI_OVERRIDE;
OCIRowid *rowidp_;
};
@@ -226,15 +274,31 @@ struct oracle_blob_backend : details::blob_backend
{
oracle_blob_backend(oracle_session_backend &session);
~oracle_blob_backend();
~oracle_blob_backend() SOCI_OVERRIDE;
virtual std::size_t get_len();
virtual std::size_t read(std::size_t offset, char *buf,
std::size_t toRead);
virtual std::size_t write(std::size_t offset, char const *buf,
std::size_t toWrite);
virtual std::size_t append(char const *buf, std::size_t toWrite);
virtual void trim(std::size_t newLen);
std::size_t get_len() SOCI_OVERRIDE;
std::size_t read(std::size_t offset, char *buf,
std::size_t toRead) SOCI_OVERRIDE;
std::size_t read_from_start(char * buf, std::size_t toRead,
std::size_t offset) SOCI_OVERRIDE
{
return read(offset + 1, buf, toRead);
}
std::size_t write(std::size_t offset, char const *buf,
std::size_t toWrite) SOCI_OVERRIDE;
std::size_t write_from_start(const char * buf, std::size_t toWrite,
std::size_t offset) SOCI_OVERRIDE
{
return write(offset + 1, buf, toWrite);
}
std::size_t append(char const *buf, std::size_t toWrite) SOCI_OVERRIDE;
void trim(std::size_t newLen) SOCI_OVERRIDE;
oracle_session_backend &session_;
@@ -247,21 +311,137 @@ struct oracle_session_backend : details::session_backend
std::string const & userName,
std::string const & password,
int mode,
bool decimals_as_strings = false);
bool decimals_as_strings = false,
int charset = 0,
int ncharset = 0);
~oracle_session_backend();
~oracle_session_backend() SOCI_OVERRIDE;
virtual void begin();
virtual void commit();
virtual void rollback();
void begin() SOCI_OVERRIDE;
void commit() SOCI_OVERRIDE;
void rollback() SOCI_OVERRIDE;
virtual std::string get_backend_name() const { return "oracle"; }
std::string get_table_names_query() const SOCI_OVERRIDE
{
return "select table_name"
" from user_tables";
}
std::string get_column_descriptions_query() const SOCI_OVERRIDE
{
return "select column_name,"
" data_type,"
" char_length as character_maximum_length,"
" data_precision as numeric_precision,"
" data_scale as numeric_scale,"
" decode(nullable, 'Y', 'YES', 'N', 'NO') as is_nullable"
" from user_tab_columns"
" where table_name = :t";
}
std::string create_column_type(data_type dt,
int precision, int scale) SOCI_OVERRIDE
{
// Oracle-specific SQL syntax:
std::string res;
switch (dt)
{
case dt_string:
{
std::ostringstream oss;
if (precision == 0)
{
oss << "clob";
}
else
{
oss << "varchar(" << precision << ")";
}
res += oss.str();
}
break;
case dt_date:
res += "timestamp";
break;
case dt_double:
{
std::ostringstream oss;
if (precision == 0)
{
oss << "number";
}
else
{
oss << "number(" << precision << ", " << scale << ")";
}
res += oss.str();
}
break;
case dt_integer:
res += "integer";
break;
case dt_long_long:
res += "number";
break;
case dt_unsigned_long_long:
res += "number";
break;
case dt_blob:
res += "blob";
break;
case dt_xml:
res += "xmltype";
break;
default:
throw soci_error("this data_type is not supported in create_column");
}
return res;
}
std::string add_column(const std::string & tableName,
const std::string & columnName, data_type dt,
int precision, int scale) SOCI_OVERRIDE
{
return "alter table " + tableName + " add " +
columnName + " " + create_column_type(dt, precision, scale);
}
std::string alter_column(const std::string & tableName,
const std::string & columnName, data_type dt,
int precision, int scale) SOCI_OVERRIDE
{
return "alter table " + tableName + " modify " +
columnName + " " + create_column_type(dt, precision, scale);
}
std::string empty_blob() SOCI_OVERRIDE
{
return "empty_blob()";
}
std::string nvl() SOCI_OVERRIDE
{
return "nvl";
}
std::string get_dummy_from_table() const SOCI_OVERRIDE { return "dual"; }
std::string get_backend_name() const SOCI_OVERRIDE { return "oracle"; }
void clean_up();
virtual oracle_statement_backend * make_statement_backend();
virtual oracle_rowid_backend * make_rowid_backend();
virtual oracle_blob_backend * make_blob_backend();
oracle_statement_backend * make_statement_backend() SOCI_OVERRIDE;
oracle_rowid_backend * make_rowid_backend() SOCI_OVERRIDE;
oracle_blob_backend * make_blob_backend() SOCI_OVERRIDE;
bool get_option_decimals_as_strings() { return decimals_as_strings_; }
@@ -281,8 +461,8 @@ struct oracle_session_backend : details::session_backend
struct oracle_backend_factory : backend_factory
{
oracle_backend_factory() {}
virtual oracle_session_backend * make_session(
connection_parameters const & parameters) const;
oracle_session_backend * make_session(
connection_parameters const & parameters) const SOCI_OVERRIDE;
};
extern SOCI_ORACLE_DECL oracle_backend_factory const oracle;

View File

@@ -31,17 +31,22 @@
namespace soci
{
class postgresql_soci_error : public soci_error
class SOCI_POSTGRESQL_DECL postgresql_soci_error : public soci_error
{
public:
postgresql_soci_error(std::string const & msg, char const * sqlst);
std::string sqlstate() const;
error_category get_error_category() const SOCI_OVERRIDE { return cat_; }
private:
char sqlstate_[ 5 ]; // not std::string to keep copy-constructor no-throw
error_category cat_;
};
struct postgresql_session_backend;
namespace details
{
@@ -51,18 +56,21 @@ class postgresql_result
{
public:
// Creates a wrapper for the given, possibly NULL, result. The wrapper
// object takes ownership of the object and will call PQclear() on it.
explicit postgresql_result(PGresult* result = NULL)
// object takes ownership of the result object and will call PQclear() on it.
explicit postgresql_result(
postgresql_session_backend & sessionBackend,
PGresult * result)
: sessionBackend_(sessionBackend)
{
init(result);
init(result);
}
// Frees any currently stored result pointer and takes ownership of the
// given one.
void reset(PGresult* result = NULL)
{
free();
init(result);
free();
init(result);
}
// Check whether the status is PGRES_COMMAND_OK and throw an exception if
@@ -98,7 +106,7 @@ public:
private:
void init(PGresult* result)
{
result_ = result;
result_ = result;
}
void free()
@@ -108,6 +116,7 @@ private:
PQclear(result_);
}
postgresql_session_backend & sessionBackend_;
PGresult* result_;
SOCI_NOT_COPYABLE(postgresql_result)
@@ -121,14 +130,14 @@ struct postgresql_standard_into_type_backend : details::standard_into_type_backe
postgresql_standard_into_type_backend(postgresql_statement_backend & st)
: statement_(st) {}
virtual void define_by_pos(int & position,
void * data, details::exchange_type type);
void define_by_pos(int & position,
void * data, details::exchange_type type) SOCI_OVERRIDE;
virtual void pre_fetch();
virtual void post_fetch(bool gotData, bool calledFromFetch,
indicator * ind);
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, bool calledFromFetch,
indicator * ind) SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
postgresql_statement_backend & statement_;
@@ -140,23 +149,36 @@ struct postgresql_standard_into_type_backend : details::standard_into_type_backe
struct postgresql_vector_into_type_backend : details::vector_into_type_backend
{
postgresql_vector_into_type_backend(postgresql_statement_backend & st)
: statement_(st) {}
: statement_(st), user_ranges_(true) {}
virtual void define_by_pos(int & position,
void * data, details::exchange_type type);
void define_by_pos(int & position,
void * data, details::exchange_type type) SOCI_OVERRIDE
{
user_ranges_ = false;
define_by_pos_bulk(position, data, type, 0, &end_var_);
}
virtual void pre_fetch();
virtual void post_fetch(bool gotData, indicator * ind);
void define_by_pos_bulk(int & position,
void * data, details::exchange_type type,
std::size_t begin, std::size_t * end) SOCI_OVERRIDE;
virtual void resize(std::size_t sz);
virtual std::size_t size();
void pre_fetch() SOCI_OVERRIDE;
void post_fetch(bool gotData, indicator * ind) SOCI_OVERRIDE;
virtual void clean_up();
void resize(std::size_t sz) SOCI_OVERRIDE;
std::size_t size() SOCI_OVERRIDE; // active size (might be lower than full vector size)
std::size_t full_size(); // actual size of the user-provided vector
void clean_up() SOCI_OVERRIDE;
postgresql_statement_backend & statement_;
void * data_;
details::exchange_type type_;
std::size_t begin_;
std::size_t * end_;
std::size_t end_var_;
bool user_ranges_;
int position_;
};
@@ -165,15 +187,15 @@ struct postgresql_standard_use_type_backend : details::standard_use_type_backend
postgresql_standard_use_type_backend(postgresql_statement_backend & st)
: statement_(st), position_(0), buf_(NULL) {}
virtual void bind_by_pos(int & position,
void * data, details::exchange_type type, bool readOnly);
virtual void bind_by_name(std::string const & name,
void * data, details::exchange_type type, bool readOnly);
void bind_by_pos(int & position,
void * data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
void bind_by_name(std::string const & name,
void * data, details::exchange_type type, bool readOnly) SOCI_OVERRIDE;
virtual void pre_use(indicator const * ind);
virtual void post_use(bool gotData, indicator * ind);
void pre_use(indicator const * ind) SOCI_OVERRIDE;
void post_use(bool gotData, indicator * ind) SOCI_OVERRIDE;
virtual void clean_up();
void clean_up() SOCI_OVERRIDE;
postgresql_statement_backend & statement_;
@@ -182,6 +204,10 @@ struct postgresql_standard_use_type_backend : details::standard_use_type_backend
int position_;
std::string name_;
char * buf_;
private:
// Allocate buf_ of appropriate size and copy string data into it.
void copy_from_string(std::string const& s);
};
struct postgresql_vector_use_type_backend : details::vector_use_type_backend
@@ -189,57 +215,78 @@ struct postgresql_vector_use_type_backend : details::vector_use_type_backend
postgresql_vector_use_type_backend(postgresql_statement_backend & st)
: statement_(st), position_(0) {}
virtual void bind_by_pos(int & position,
void * data, details::exchange_type type);
virtual void bind_by_name(std::string const & name,
void * data, details::exchange_type type);
void bind_by_pos(int & position,
void * data, details::exchange_type type) SOCI_OVERRIDE
{
bind_by_pos_bulk(position, data, type, 0, &end_var_);
}
virtual void pre_use(indicator const * ind);
void bind_by_pos_bulk(int & position,
void * data, details::exchange_type type,
std::size_t begin, std::size_t * end) SOCI_OVERRIDE;
virtual std::size_t size();
void bind_by_name(std::string const & name,
void * data, details::exchange_type type) SOCI_OVERRIDE
{
bind_by_name_bulk(name, data, type, 0, &end_var_);
}
virtual void clean_up();
void bind_by_name_bulk(const std::string & name,
void * data, details::exchange_type type,
std::size_t begin, std::size_t * end) SOCI_OVERRIDE;
void pre_use(indicator const * ind) SOCI_OVERRIDE;
std::size_t size() SOCI_OVERRIDE; // active size (might be lower than full vector size)
std::size_t full_size(); // actual size of the user-provided vector
void clean_up() SOCI_OVERRIDE;
postgresql_statement_backend & statement_;
void * data_;
details::exchange_type type_;
std::size_t begin_;
std::size_t * end_;
std::size_t end_var_;
int position_;
std::string name_;
std::vector<char *> buffers_;
};
struct postgresql_session_backend;
struct postgresql_statement_backend : details::statement_backend
{
postgresql_statement_backend(postgresql_session_backend & session);
~postgresql_statement_backend();
postgresql_statement_backend(postgresql_session_backend & session,
bool single_row_mode);
~postgresql_statement_backend() SOCI_OVERRIDE;
virtual void alloc();
virtual void clean_up();
virtual void prepare(std::string const & query,
details::statement_type stType);
void alloc() SOCI_OVERRIDE;
void clean_up() SOCI_OVERRIDE;
void prepare(std::string const & query,
details::statement_type stType) SOCI_OVERRIDE;
virtual exec_fetch_result execute(int number);
virtual exec_fetch_result fetch(int number);
exec_fetch_result execute(int number) SOCI_OVERRIDE;
exec_fetch_result fetch(int number) SOCI_OVERRIDE;
virtual long long get_affected_rows();
virtual int get_number_of_rows();
virtual std::string get_parameter_name(int index) const;
long long get_affected_rows() SOCI_OVERRIDE;
int get_number_of_rows() SOCI_OVERRIDE;
std::string get_parameter_name(int index) const SOCI_OVERRIDE;
virtual std::string rewrite_for_procedure_call(std::string const & query);
std::string rewrite_for_procedure_call(std::string const & query) SOCI_OVERRIDE;
virtual int prepare_for_describe();
virtual void describe_column(int colNum, data_type & dtype,
std::string & columnName);
int prepare_for_describe() SOCI_OVERRIDE;
void describe_column(int colNum, data_type & dtype,
std::string & columnName) SOCI_OVERRIDE;
virtual postgresql_standard_into_type_backend * make_into_type_backend();
virtual postgresql_standard_use_type_backend * make_use_type_backend();
virtual postgresql_vector_into_type_backend * make_vector_into_type_backend();
virtual postgresql_vector_use_type_backend * make_vector_use_type_backend();
postgresql_standard_into_type_backend * make_into_type_backend() SOCI_OVERRIDE;
postgresql_standard_use_type_backend * make_use_type_backend() SOCI_OVERRIDE;
postgresql_vector_into_type_backend * make_vector_into_type_backend() SOCI_OVERRIDE;
postgresql_vector_use_type_backend * make_vector_use_type_backend() SOCI_OVERRIDE;
postgresql_session_backend & session_;
bool single_row_mode_;
details::postgresql_result result_;
std::string query_;
details::statement_type stType_;
@@ -274,7 +321,7 @@ struct postgresql_rowid_backend : details::rowid_backend
{
postgresql_rowid_backend(postgresql_session_backend & session);
~postgresql_rowid_backend();
~postgresql_rowid_backend() SOCI_OVERRIDE;
unsigned long value_;
};
@@ -283,15 +330,31 @@ struct postgresql_blob_backend : details::blob_backend
{
postgresql_blob_backend(postgresql_session_backend & session);
~postgresql_blob_backend();
~postgresql_blob_backend() SOCI_OVERRIDE;
virtual std::size_t get_len();
virtual std::size_t read(std::size_t offset, char * buf,
std::size_t toRead);
virtual std::size_t write(std::size_t offset, char const * buf,
std::size_t toWrite);
virtual std::size_t append(char const * buf, std::size_t toWrite);
virtual void trim(std::size_t newLen);
std::size_t get_len() SOCI_OVERRIDE;
std::size_t read(std::size_t offset, char * buf,
std::size_t toRead) SOCI_OVERRIDE;
std::size_t read_from_start(char * buf, std::size_t toRead,
std::size_t offset) SOCI_OVERRIDE
{
return read(offset, buf, toRead);
}
std::size_t write(std::size_t offset, char const * buf,
std::size_t toWrite) SOCI_OVERRIDE;
std::size_t write_from_start(const char * buf, std::size_t toWrite,
std::size_t offset) SOCI_OVERRIDE
{
return write(offset, buf, toWrite);
}
std::size_t append(char const * buf, std::size_t toWrite) SOCI_OVERRIDE;
void trim(std::size_t newLen) SOCI_OVERRIDE;
postgresql_session_backend & session_;
@@ -301,30 +364,36 @@ struct postgresql_blob_backend : details::blob_backend
struct postgresql_session_backend : details::session_backend
{
postgresql_session_backend(connection_parameters const & parameters);
postgresql_session_backend(connection_parameters const & parameters,
bool single_row_mode);
~postgresql_session_backend();
~postgresql_session_backend() SOCI_OVERRIDE;
virtual void begin();
virtual void commit();
virtual void rollback();
void connect(connection_parameters const & parameters);
void begin() SOCI_OVERRIDE;
void commit() SOCI_OVERRIDE;
void rollback() SOCI_OVERRIDE;
void deallocate_prepared_statement(const std::string & statementName);
virtual bool get_next_sequence_value(session & s,
std::string const & sequence, long & value);
bool get_next_sequence_value(session & s,
std::string const & sequence, long & value) SOCI_OVERRIDE;
virtual std::string get_backend_name() const { return "postgresql"; }
std::string get_dummy_from_table() const SOCI_OVERRIDE { return std::string(); }
std::string get_backend_name() const SOCI_OVERRIDE { return "postgresql"; }
void clean_up();
virtual postgresql_statement_backend * make_statement_backend();
virtual postgresql_rowid_backend * make_rowid_backend();
virtual postgresql_blob_backend * make_blob_backend();
postgresql_statement_backend * make_statement_backend() SOCI_OVERRIDE;
postgresql_rowid_backend * make_rowid_backend() SOCI_OVERRIDE;
postgresql_blob_backend * make_blob_backend() SOCI_OVERRIDE;
std::string get_next_statement_name();
int statementCount_;
bool single_row_mode_;
PGconn * conn_;
};
@@ -332,8 +401,8 @@ struct postgresql_session_backend : details::session_backend
struct postgresql_backend_factory : backend_factory
{
postgresql_backend_factory() {}
virtual postgresql_session_backend * make_session(
connection_parameters const & parameters) const;
postgresql_session_backend * make_session(
connection_parameters const & parameters) const SOCI_OVERRIDE;
};
extern SOCI_POSTGRESQL_DECL postgresql_backend_factory const postgresql;

View File

@@ -42,13 +42,13 @@ class SOCI_DECL procedure
public:
// this is a conversion constructor
procedure(details::prepare_temp_type const & prep)
: impl_(new details::procedure_impl(prep)) {}
: impl_(new details::procedure_impl(prep)), gotData_(false) {}
~procedure() { impl_->dec_ref(); }
// copy is supported here
procedure(procedure const & other)
: impl_(other.impl_)
: impl_(other.impl_), gotData_(other.gotData_)
{
impl_->inc_ref();
}
@@ -57,6 +57,7 @@ public:
other.impl_->inc_ref();
impl_->dec_ref();
impl_ = other.impl_;
gotData_ = other.gotData_;
}
// forwarders to procedure_impl

View File

@@ -43,7 +43,7 @@ public:
: callback_(callback)
{}
result_type operator()(argument_type query) const
result_type operator()(argument_type query) const SOCI_OVERRIDE
{
return callback_(query);
}

View File

@@ -47,7 +47,7 @@ public:
void exchange(into_container<T, Indicator> const &ic)
{ intos_.exchange(ic); }
void final_action();
void final_action() SOCI_OVERRIDE;
private:
friend class statement_impl;

View File

@@ -1,5 +1,5 @@
//
// Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton
// Copyright (C) 2004-2016 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)
@@ -37,6 +37,11 @@ public:
{
try
{
if (tail_.empty() == false)
{
accumulate(tail_);
}
final_action();
}
catch (...)
@@ -52,6 +57,10 @@ public:
template <typename T>
void accumulate(T const & t) { get_query_stream() << t; }
void set_tail(const std::string & tail) { tail_ = tail; }
void set_need_comma(bool need_comma) { need_comma_ = need_comma; }
bool get_need_comma() const { return need_comma_; }
protected:
// this function allows to break the circular dependenc
// between session and this class
@@ -61,6 +70,10 @@ protected:
session & session_;
// used mainly for portable ddl
std::string tail_;
bool need_comma_;
private:
SOCI_NOT_COPYABLE(ref_counted_statement_base)
};
@@ -73,7 +86,7 @@ public:
ref_counted_statement(session & s)
: ref_counted_statement_base(s), st_(s) {}
virtual void final_action();
void final_action() SOCI_OVERRIDE;
template <typename T>
void exchange(T &t) { st_.exchange(t); }

View File

@@ -33,7 +33,7 @@ public:
private:
// special handling for Row
virtual void define(statement_impl & st, int & /* position */)
void define(statement_impl & st, int & /* position */) SOCI_OVERRIDE
{
st.set_row(&r_);
@@ -41,8 +41,9 @@ private:
// as part of the statement execute
}
virtual void pre_fetch() {}
virtual void post_fetch(bool gotData, bool /* calledFromFetch */)
void pre_exec(int /* num */) SOCI_OVERRIDE {}
void pre_fetch() SOCI_OVERRIDE {}
void post_fetch(bool gotData, bool /* calledFromFetch */) SOCI_OVERRIDE
{
r_.reset_get_counter();
@@ -55,9 +56,9 @@ private:
}
}
virtual void clean_up() {}
void clean_up() SOCI_OVERRIDE {}
virtual std::size_t size() const { return 1; }
std::size_t size() const SOCI_OVERRIDE { return 1; }
virtual void convert_from_base() {}

View File

@@ -8,6 +8,7 @@
#ifndef SOCI_ROWSET_H_INCLUDED
#define SOCI_ROWSET_H_INCLUDED
#include "soci/soci-platform.h"
#include "soci/statement.h"
// std
#include <iterator>
@@ -147,13 +148,8 @@ private:
unsigned int refs_;
#ifdef SOCI_CXX_C11
const std::unique_ptr<statement> st_;
const std::unique_ptr<T> define_;
#else
const std::auto_ptr<statement> st_;
const std::auto_ptr<T> define_;
#endif
const cxx_details::auto_ptr<statement> st_;
const cxx_details::auto_ptr<T> define_;
SOCI_NOT_COPYABLE(rowset_impl)
}; // class rowset_impl

View File

@@ -1,5 +1,5 @@
//
// Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton
// Copyright (C) 2004-2016 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)
@@ -8,6 +8,7 @@
#ifndef SOCI_SESSION_H_INCLUDED
#define SOCI_SESSION_H_INCLUDED
#include "soci/soci-platform.h"
#include "soci/once-temp-type.h"
#include "soci/query_transformation.h"
#include "soci/connection-parameters.h"
@@ -35,16 +36,13 @@ class blob_backend;
} // namespace details
class connection_pool;
class failover_callback;
class SOCI_DECL session
{
private:
#ifdef SOCI_CXX_C11
void set_query_transformation_(std::unique_ptr<details::query_transformation_function> & qtf);
#else
void set_query_transformation_(std::auto_ptr<details::query_transformation_function> qtf);
#endif
void set_query_transformation_(cxx_details::auto_ptr<details::query_transformation_function>& qtf);
@@ -84,13 +82,9 @@ public:
void set_query_transformation(T callback)
{
#ifdef SOCI_CXX_C11
std::unique_ptr<details::query_transformation_function> qtf(new details::query_transformation<T>(callback));
#else
std::auto_ptr<details::query_transformation_function> qtf(new details::query_transformation<T>(callback));
#endif
cxx_details::auto_ptr<details::query_transformation_function> qtf(new details::query_transformation<T>(callback));
set_query_transformation_(qtf);
}
}
// support for basic logging
void set_log_stream(std::ostream * s);
@@ -120,7 +114,58 @@ public:
// return the last value auto-generated in this session).
bool get_last_insert_id(std::string const & table, long & value);
// Returns once_temp_type for the internally composed query
// for the list of tables in the current schema.
// Since this query usually returns multiple results (for multiple tables),
// it makes sense to bind std::vector<std::string> for the single output field.
details::once_temp_type get_table_names();
// Returns prepare_temp_type for the internally composed query
// for the list of tables in the current schema.
// Since this is intended for use with statement objects, where results are obtained one row after another,
// it makes sense to bind std::string for the output field.
details::prepare_temp_type prepare_table_names();
// Returns prepare_temp_type for the internally composed query
// for the list of column descriptions.
// Since this is intended for use with statement objects, where results are obtained one row after another,
// it makes sense to bind either std::string for each output field or soci::column_info for the whole row.
// Note: table_name is a non-const reference to prevent temporary objects,
// this argument is bound as a regular "use" element.
details::prepare_temp_type prepare_column_descriptions(std::string & table_name);
// Functions for basic portable DDL statements.
ddl_type create_table(const std::string & tableName);
void drop_table(const std::string & tableName);
void truncate_table(const std::string & tableName);
ddl_type add_column(const std::string & tableName,
const std::string & columnName, data_type dt,
int precision = 0, int scale = 0);
ddl_type alter_column(const std::string & tableName,
const std::string & columnName, data_type dt,
int precision = 0, int scale = 0);
ddl_type drop_column(const std::string & tableName,
const std::string & columnName);
std::string empty_blob();
std::string nvl();
// And some functions to help with writing portable DML statements.
// Get the name of the dummy table that needs to be used in the FROM clause
// of a SELECT statement not operating on any tables, e.g. "dual" for
// Oracle. The returned string is empty if no such table is needed.
std::string get_dummy_from_table() const;
// Returns a possibly empty string that needs to be used as a FROM clause
// of a SELECT statement not operating on any tables, e.g. " FROM DUAL"
// (notice the leading space).
std::string get_dummy_from_clause() const;
// Sets the failover callback object.
void set_failover_callback(failover_callback & callback);
// for diagnostics and advanced users
// (downcast it to expected back-end session class)
details::session_backend * get_backend() { return backEnd_; }

View File

@@ -1,5 +1,5 @@
//
// Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton
// Copyright (C) 2004-2016 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)
@@ -14,6 +14,7 @@
#include <cstddef>
#include <map>
#include <string>
#include <sstream>
namespace soci
{
@@ -21,13 +22,15 @@ namespace soci
// data types, as seen by the user
enum data_type
{
dt_string, dt_date, dt_double, dt_integer, dt_long_long, dt_unsigned_long_long, dt_blob
dt_string, dt_date, dt_double, dt_integer, dt_long_long, dt_unsigned_long_long,
dt_blob, dt_xml
};
// the enum type for indicator variables
enum indicator { i_ok, i_null, i_truncated };
class session;
class failover_callback;
namespace details
{
@@ -45,7 +48,10 @@ enum exchange_type
x_stdtm,
x_statement,
x_rowid,
x_blob
x_blob,
x_xmltype,
x_longstring
};
// type of statement (used for optimizing statement preparation)
@@ -65,6 +71,7 @@ public:
virtual void define_by_pos(int& position, void* data, exchange_type type) = 0;
virtual void pre_exec(int /* num */) {}
virtual void pre_fetch() = 0;
virtual void post_fetch(bool gotData, bool calledFromFetch, indicator* ind) = 0;
@@ -81,8 +88,16 @@ public:
vector_into_type_backend() {}
virtual ~vector_into_type_backend() {}
virtual void define_by_pos_bulk(
int & /* position */, void * /* data */, exchange_type /* type */,
std::size_t /* begin */, std::size_t * /* end */)
{
throw soci_error("into bulk iterators are not supported with this backend");
}
virtual void define_by_pos(int& position, void* data, exchange_type type) = 0;
virtual void pre_exec(int /* num */) {}
virtual void pre_fetch() = 0;
virtual void post_fetch(bool gotData, indicator* ind) = 0;
@@ -108,6 +123,7 @@ public:
virtual void bind_by_name(std::string const& name,
void* data, exchange_type type, bool readOnly) = 0;
virtual void pre_exec(int /* num */) {}
virtual void pre_use(indicator const* ind) = 0;
virtual void post_use(bool gotData, indicator * ind) = 0;
@@ -124,9 +140,23 @@ public:
virtual ~vector_use_type_backend() {}
virtual void bind_by_pos(int& position, void* data, exchange_type type) = 0;
virtual void bind_by_pos_bulk(int& /* position */, void* /* data */, exchange_type /* type */,
std::size_t /* begin */, std::size_t * /* end */)
{
throw soci_error("use bulk iterators are not supported with this backend");
}
virtual void bind_by_name(std::string const& name,
void* data, exchange_type type) = 0;
virtual void bind_by_name_bulk(std::string const& /* name */,
void* /* data */, exchange_type /* type */,
std::size_t /* begin */, std::size_t * /* end */)
{
throw soci_error("use bulk iterators are not supported with this backend");
}
virtual void pre_exec(int /* num */) {}
virtual void pre_use(indicator const* ind) = 0;
virtual std::size_t size() = 0;
@@ -196,11 +226,27 @@ 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 read_from_start(char * /* buf */, std::size_t /* toRead */,
std::size_t /* offset */)
{
throw soci_error("read_from_start is not implemented for this backend");
}
virtual std::size_t write(std::size_t offset, char const* buf,
std::size_t toWrite) = 0;
virtual std::size_t write_from_start(const char * /* buf */, std::size_t /* toWrite */,
std::size_t /* offset */)
{
throw soci_error("write_from_start is not implemented for this backend");
}
virtual std::size_t append(char const* buf, std::size_t toWrite) = 0;
virtual void trim(std::size_t newLen) = 0;
private:
@@ -212,7 +258,7 @@ private:
class session_backend
{
public:
session_backend() {}
session_backend() : failoverCallback_(NULL), session_(NULL) {}
virtual ~session_backend() {}
virtual void begin() = 0;
@@ -234,12 +280,184 @@ public:
return false;
}
// There is a set of standard SQL metadata structures that can be
// queried in a portable way - backends that are standard compliant
// do not need to override the following methods, which are intended
// to return a proper query for basic metadata statements.
// Returns a parameterless query for the list of table names in the current schema.
virtual std::string get_table_names_query() const
{
return "select table_name as \"TABLE_NAME\""
" from information_schema.tables"
" where table_schema = 'public'";
}
// Returns a query with a single parameter (table name) for the list
// of columns and their properties.
virtual std::string get_column_descriptions_query() const
{
return "select column_name as \"COLUMN_NAME\","
" data_type as \"DATA_TYPE\","
" character_maximum_length as \"CHARACTER_MAXIMUM_LENGTH\","
" numeric_precision as \"NUMERIC_PRECISION\","
" numeric_scale as \"NUMERIC_SCALE\","
" is_nullable as \"IS_NULLABLE\""
" from information_schema.columns"
" where table_schema = 'public' and table_name = :t";
}
virtual std::string create_table(const std::string & tableName)
{
return "create table " + tableName + " (";
}
virtual std::string drop_table(const std::string & tableName)
{
return "drop table " + tableName;
}
virtual std::string truncate_table(const std::string & tableName)
{
return "truncate table " + tableName;
}
virtual std::string create_column_type(data_type dt,
int precision, int scale)
{
// PostgreSQL was selected as a baseline for the syntax:
std::string res;
switch (dt)
{
case dt_string:
{
std::ostringstream oss;
if (precision == 0)
{
oss << "text";
}
else
{
oss << "varchar(" << precision << ")";
}
res += oss.str();
}
break;
case dt_date:
res += "timestamp";
break;
case dt_double:
{
std::ostringstream oss;
if (precision == 0)
{
oss << "numeric";
}
else
{
oss << "numeric(" << precision << ", " << scale << ")";
}
res += oss.str();
}
break;
case dt_integer:
res += "integer";
break;
case dt_long_long:
res += "bigint";
break;
case dt_unsigned_long_long:
res += "bigint";
break;
case dt_blob:
res += "oid";
break;
case dt_xml:
res += "xml";
break;
default:
throw soci_error("this data_type is not supported in create_column");
}
return res;
}
virtual std::string add_column(const std::string & tableName,
const std::string & columnName, data_type dt,
int precision, int scale)
{
return "alter table " + tableName + " add column " + columnName +
" " + create_column_type(dt, precision, scale);
}
virtual std::string alter_column(const std::string & tableName,
const std::string & columnName, data_type dt,
int precision, int scale)
{
return "alter table " + tableName + " alter column " +
columnName + " type " +
create_column_type(dt, precision, scale);
}
virtual std::string drop_column(const std::string & tableName,
const std::string & columnName)
{
return "alter table " + tableName +
" drop column " + columnName;
}
virtual std::string constraint_unique(const std::string & name,
const std::string & columnNames)
{
return "constraint " + name +
" unique (" + columnNames + ")";
}
virtual std::string constraint_primary_key(const std::string & name,
const std::string & columnNames)
{
return "constraint " + name +
" primary key (" + columnNames + ")";
}
virtual std::string constraint_foreign_key(const std::string & name,
const std::string & columnNames,
const std::string & refTableName,
const std::string & refColumnNames)
{
return "constraint " + name +
" foreign key (" + columnNames + ")" +
" references " + refTableName + " (" + refColumnNames + ")";
}
virtual std::string empty_blob()
{
return "lo_creat(-1)";
}
virtual std::string nvl()
{
return "coalesce";
}
virtual std::string get_dummy_from_table() const = 0;
void set_failover_callback(failover_callback & callback, session & sql)
{
failoverCallback_ = &callback;
session_ = &sql;
}
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;
failover_callback * failoverCallback_;
session * session_;
private:
SOCI_NOT_COPYABLE(session_backend)
};

View File

@@ -8,6 +8,9 @@
#ifndef SOCICONFIG_H_INCLUDED
#define SOCICONFIG_H_INCLUDED
#include "soci/soci-platform.h"
//
// SOCI has been build with support for:
//
@CONFIGURED_VARIABLES@
#endif // SOCICONFIG_H_INCLUDED

Some files were not shown because too many files have changed in this diff Show More