Commit 638b89d1 authored by Maciej Sobczak's avatar Maciej Sobczak

Merge remote-tracking branch 'upstream/master'

parents 138b29e4 a9ab0db1
......@@ -23,20 +23,11 @@ env:
- SOCI_TRAVIS_BACKEND=mysql
- SOCI_TRAVIS_BACKEND=odbc
- SOCI_TRAVIS_BACKEND=postgresql
- SOCI_TRAVIS_BACKEND=oracle CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32 WITH_BOOST=OFF
- SOCI_TRAVIS_BACKEND=postgression
- SOCI_TRAVIS_BACKEND=sqlite3
- SOCI_TRAVIS_BACKEND=valgrind
matrix:
fast_finish: true
allow_failures:
- env: SOCI_TRAVIS_BACKEND=db2
- env: SOCI_TRAVIS_BACKEND=postgression
- env: SOCI_TRAVIS_BACKEND=valgrind
- env: SOCI_TRAVIS_BACKEND=odbc
- env: SOCI_TRAVIS_BACKEND=mysql
- env: SOCI_TRAVIS_BACKEND=oracle CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32 WITH_BOOST=OFF
# This build is disabled because Oracle setup is currently broken, see #554.
# - SOCI_TRAVIS_BACKEND=oracle CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32 WITH_BOOST=OFF
addons:
apt:
......
......@@ -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.
......
......@@ -35,5 +35,5 @@ run_test()
run_test_memcheck()
{
valgrind --leak-check=full --error-exitcode=1 --trace-children=yes ctest -V --output-on-failure "$@" .
valgrind --leak-check=full --suppressions=${TRAVIS_BUILD_DIR}/valgrind.suppress --error-exitcode=1 --trace-children=yes ctest -V --output-on-failure "$@" .
}
#!/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_BUILD_TYPE=Debug \
-DSOCI_ASAN=ON \
-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
......@@ -27,7 +27,9 @@ endif(WIN32)
# 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 (NOT SOCI_CXX_C11 )
#
......@@ -58,7 +60,20 @@ 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")
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")
......@@ -73,19 +88,6 @@ else()
endif()
endif()
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_CXX_COMPILER}" MATCHES "clang")
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}")
else()
message(WARNING "Unknown toolset - using default flags to build SOCI")
endif()
......
......@@ -87,6 +87,9 @@ The `session` class encapsulates the connection to the database.
void uppercase_column_names(bool forceToUpper);
std::string get_dummy_from_table() const;
std::string get_dummy_from_clause() const;
details::session_backend * get_backend();
std::string get_backend_name() const;
......@@ -124,6 +127,7 @@ This class contains the following members:
* `set_log_stream` and `get_log_stream` functions for setting and getting the current stream object used for basic query logging. By default, it is `NULL`, which means no logging The string value that is actually logged into the stream is one-line verbatim copy of the query string provided by the user, without including any data from the `use` elements. The query is logged exactly once, before the preparation step.
* `get_last_query` retrieves the text of the last used query.
* `uppercase_column_names` allows to force all column names to uppercase in dynamic row description; this function is particularly useful for portability, since various database servers report column names differently (some preserve case, some change it).
* `get_dummy_from_table` and `get_dummy_from_clause()`: helpers for writing portable DML statements, see [DML helpers](statement.html#dml) for more details.
* `get_backend` returns the internal pointer to the concrete backend implementation of the session. This is provided for advanced users that need access to the functionality that is not otherwise available.
*`get_backend_name` is a convenience forwarder to the same function of the backend object.
......
......@@ -7,6 +7,7 @@
* [Transactions](#transactions)
* [Portable DDL](#ddl)
* [Metadata queries](#metadata)
* [Portable DML](#dml)
* [Basic logging support](#logging)
### <a name="preparation"></a> Statement preparation and repeated execution
......@@ -392,6 +393,28 @@ Similarly, to get the description of all columns in the given table:
// ci fields describe each column in turn
}
### <a name="dml"></a> Portable DDL
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:
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.
### <a name="logging"></a> Basic logging support
The following members of the `session` class support the basic logging functionality:
......@@ -411,4 +434,4 @@ The first two functions allow to set the user-provided output stream object for
Each statement logs its query string before the preparation step (whether explicit or implicit) and therefore logging is effective whether the query succeeds or not. Note that each prepared query is logged only once, independent on how many times it is executed.
The `get_last_query` function allows to retrieve the last used query.
\ No newline at end of file
The `get_last_query` function allows to retrieve the last used query.
......@@ -256,6 +256,8 @@ struct db2_session_backend : details::session_backend
void commit();
void rollback();
virtual std::string get_dummy_from_table() const { return "sysibm.sysdummy1"; }
std::string get_backend_name() const { return "DB2"; }
void clean_up();
......
......@@ -163,6 +163,8 @@ struct empty_session_backend : details::session_backend
void commit();
void rollback();
virtual std::string get_dummy_from_table() const { return std::string(); }
std::string get_backend_name() const { return "empty"; }
void clean_up();
......
......@@ -302,6 +302,8 @@ struct firebird_session_backend : details::session_backend
virtual bool get_next_sequence_value(session & s,
std::string const & sequence, long & value);
virtual std::string get_dummy_from_table() const { return "rdb$database"; }
virtual std::string get_backend_name() const { return "firebird"; }
void cleanUp();
......
......@@ -241,6 +241,10 @@ struct mysql_session_backend : details::session_backend
virtual bool get_last_insert_id(session&, std::string const&, long&);
// 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.
virtual std::string get_dummy_from_table() const { return std::string(); }
virtual std::string get_backend_name() const { return "mysql"; }
void clean_up();
......
......@@ -301,6 +301,8 @@ struct odbc_session_backend : details::session_backend
virtual bool get_last_insert_id(session & s,
std::string const & table, long & value);
virtual std::string get_dummy_from_table() const;
virtual std::string get_backend_name() const { return "odbc"; }
void configure_connection();
......@@ -325,7 +327,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_; }
......@@ -334,7 +336,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
......
......@@ -433,6 +433,8 @@ struct oracle_session_backend : details::session_backend
return "nvl";
}
virtual std::string get_dummy_from_table() const { return "dual"; }
virtual std::string get_backend_name() const { return "oracle"; }
void clean_up();
......
......@@ -376,6 +376,8 @@ struct postgresql_session_backend : details::session_backend
virtual bool get_next_sequence_value(session & s,
std::string const & sequence, long & value);
virtual std::string get_dummy_from_table() const { return std::string(); }
virtual std::string get_backend_name() const { return "postgresql"; }
void clean_up();
......
......@@ -150,11 +150,21 @@ public:
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)
{
backEnd_->set_failover_callback(callback, *this);
}
void set_failover_callback(failover_callback & callback);
// for diagnostics and advanced users
// (downcast it to expected back-end session class)
......
......@@ -440,7 +440,9 @@ public:
{
return "coalesce";
}
virtual std::string get_dummy_from_table() const = 0;
void set_failover_callback(failover_callback & callback, session & sql)
{
failoverCallback_ = &callback;
......
......@@ -296,6 +296,8 @@ struct sqlite3_session_backend : details::session_backend
return "x\'\'";
}
virtual std::string get_dummy_from_table() const { return std::string(); }
virtual std::string get_backend_name() const { return "sqlite3"; }
void clean_up();
......
......@@ -99,6 +99,8 @@ void *db2_standard_use_type_backend::prepare_for_bind(
break;
case x_blob:
case x_xmltype:
case x_longstring:
break;
case x_statement:
case x_rowid:
......
......@@ -149,6 +149,8 @@ void db2_vector_into_type_backend::define_by_pos(
case x_statement: break; // not supported
case x_rowid: break; // not supported
case x_blob: break; // not supported
case x_xmltype: break; // not supported
case x_longstring:break; // not supported
}
SQLRETURN cliRC = SQLBindCol(statement_.hStmt, static_cast<SQLUSMALLINT>(position++),
......@@ -321,6 +323,8 @@ void db2_vector_into_type_backend::resize(std::size_t sz)
case x_statement: break; // not supported
case x_rowid: break; // not supported
case x_blob: break; // not supported
case x_xmltype: break; // not supported
case x_longstring:break; // not supported
}
}
......@@ -387,6 +391,8 @@ std::size_t db2_vector_into_type_backend::size()
case x_statement: break; // not supported
case x_rowid: break; // not supported
case x_blob: break; // not supported
case x_xmltype: break; // not supported
case x_longstring:break; // not supported
}
return sz;
......
......@@ -179,6 +179,8 @@ void db2_vector_use_type_backend::prepare_for_bind(void *&data, SQLUINTEGER &siz
case x_statement: break; // not supported
case x_rowid: break; // not supported
case x_blob: break; // not supported
case x_xmltype: break; // not supported
case x_longstring:break; // not supported
}
colSize = size;
......@@ -381,6 +383,8 @@ std::size_t db2_vector_use_type_backend::size()
case x_statement: break; // not supported
case x_rowid: break; // not supported
case x_blob: break; // not supported
case x_xmltype: break; // not supported
case x_longstring:break; // not supported
}
return sz;
......
......@@ -253,6 +253,37 @@ bool odbc_session_backend::get_last_insert_id(
return true;
}
std::string odbc_session_backend::get_dummy_from_table() const
{
std::string table;
switch ( get_database_product() )
{
case prod_firebird:
table = "rdb$database";
break;
case prod_oracle:
table = "dual";
break;
case prod_mssql:
case prod_mysql:
case prod_sqlite:
case prod_postgresql:
// No special dummy table needed.
break;
// These cases are here just to make the switch exhaustive, we
// can't really do anything about them anyhow.
case prod_unknown:
case prod_uninitialized:
break;
}
return table;
}
void odbc_session_backend::reset_transaction()
{
SQLRETURN rc = SQLSetConnectAttr( hdbc_, SQL_ATTR_AUTOCOMMIT,
......@@ -301,7 +332,7 @@ odbc_blob_backend * odbc_session_backend::make_blob_backend()
}
odbc_session_backend::database_product
odbc_session_backend::get_database_product()
odbc_session_backend::get_database_product() const
{
// Cache the product type, it's not going to change during our life time.
if (product_ != prod_uninitialized)
......
......@@ -290,57 +290,94 @@ void odbc_vector_use_type_backend::bind_by_name(
void odbc_vector_use_type_backend::pre_use(indicator const *ind)
{
// first deal with data
if (type_ == x_stdtm)
SQLLEN non_null_indicator = 0;
switch (type_)
{
std::vector<std::tm> *vp
= static_cast<std::vector<std::tm> *>(data_);
case x_short:
case x_integer:
case x_double:
// Length of the parameter value is ignored for these types.
break;
std::vector<std::tm> &v(*vp);
case x_char:
case x_stdstring:
non_null_indicator = SQL_NTS;
break;
char *pos = buf_;
std::size_t const vsize = v.size();
for (std::size_t i = 0; i != vsize; ++i)
{
std::tm t = v[i];
TIMESTAMP_STRUCT * ts = reinterpret_cast<TIMESTAMP_STRUCT*>(pos);
ts->year = static_cast<SQLSMALLINT>(t.tm_year + 1900);
ts->month = static_cast<SQLUSMALLINT>(t.tm_mon + 1);
ts->day = static_cast<SQLUSMALLINT>(t.tm_mday);
ts->hour = static_cast<SQLUSMALLINT>(t.tm_hour);
ts->minute = static_cast<SQLUSMALLINT>(t.tm_min);
ts->second = static_cast<SQLUSMALLINT>(t.tm_sec);
ts->fraction = 0;
pos += sizeof(TIMESTAMP_STRUCT);
}
}
else if (type_ == x_long_long && use_string_for_bigint())
{
std::vector<long long> *vp
= static_cast<std::vector<long long> *>(data_);
std::vector<long long> &v(*vp);
case x_stdtm:
{
std::vector<std::tm> *vp
= static_cast<std::vector<std::tm> *>(data_);
char *pos = buf_;
std::size_t const vsize = v.size();
for (std::size_t i = 0; i != vsize; ++i)
{
snprintf(pos, max_bigint_length, "%" LL_FMT_FLAGS "d", v[i]);
pos += max_bigint_length;
}
}
else if (type_ == x_unsigned_long_long && use_string_for_bigint())
{
std::vector<unsigned long long> *vp
= static_cast<std::vector<unsigned long long> *>(data_);
std::vector<unsigned long long> &v(*vp);
std::vector<std::tm> &v(*vp);
char *pos = buf_;
std::size_t const vsize = v.size();
for (std::size_t i = 0; i != vsize; ++i)
{
snprintf(pos, max_bigint_length, "%" LL_FMT_FLAGS "u", v[i]);
pos += max_bigint_length;
}
char *pos = buf_;
std::size_t const vsize = v.size();
for (std::size_t i = 0; i != vsize; ++i)
{
std::tm t = v[i];
TIMESTAMP_STRUCT * ts = reinterpret_cast<TIMESTAMP_STRUCT*>(pos);
ts->year = static_cast<SQLSMALLINT>(t.tm_year + 1900);
ts->month = static_cast<SQLUSMALLINT>(t.tm_mon + 1);
ts->day = static_cast<SQLUSMALLINT>(t.tm_mday);
ts->hour = static_cast<SQLUSMALLINT>(t.tm_hour);
ts->minute = static_cast<SQLUSMALLINT>(t.tm_min);
ts->second = static_cast<SQLUSMALLINT>(t.tm_sec);
ts->fraction = 0;
pos += sizeof(TIMESTAMP_STRUCT);
}
}
break;
case x_long_long:
if (use_string_for_bigint())
{
std::vector<long long> *vp
= static_cast<std::vector<long long> *>(data_);
std::vector<long long> &v(*vp);
char *pos = buf_;
std::size_t const vsize = v.size();
for (std::size_t i = 0; i != vsize; ++i)
{
snprintf(pos, max_bigint_length, "%" LL_FMT_FLAGS "d", v[i]);
pos += max_bigint_length;
}
non_null_indicator = SQL_NTS;
}
break;
case x_unsigned_long_long:
if (use_string_for_bigint())
{
std::vector<unsigned long long> *vp
= static_cast<std::vector<unsigned long long> *>(data_);
std::vector<unsigned long long> &v(*vp);
char *pos = buf_;
std::size_t const vsize = v.size();
for (std::size_t i = 0; i != vsize; ++i)
{
snprintf(pos, max_bigint_length, "%" LL_FMT_FLAGS "u", v[i]);
pos += max_bigint_length;
}
non_null_indicator = SQL_NTS;
}
break;
case x_statement:
case x_rowid:
case x_blob:
case x_xmltype:
case x_longstring:
// Those are unreachable, we would have thrown from
// prepare_for_bind() if we we were using one of them, only handle
// them here to avoid compiler warnings about unhandled enum
// elements.
break;
}
// then handle indicators
......@@ -358,7 +395,7 @@ void odbc_vector_use_type_backend::pre_use(indicator const *ind)
// for strings we have already set the values
if (type_ != x_stdstring)
{
indHolderVec_[i] = SQL_NTS; // value is OK
indHolderVec_[i] = non_null_indicator;
}
}
}
......@@ -372,7 +409,7 @@ void odbc_vector_use_type_backend::pre_use(indicator const *ind)
// for strings we have already set the values
if (type_ != x_stdstring)
{
indHolderVec_[i] = SQL_NTS; // value is OK
indHolderVec_[i] = non_null_indicator;
}
}
}
......
......@@ -5,6 +5,7 @@
// http://www.boost.org/LICENSE_1_0.txt)
//
#define SOCI_SQLITE3_SOURCE
#include "soci/sqlite3/soci-sqlite3.h"
#include <algorithm>
......
......@@ -5,6 +5,7 @@
// http://www.boost.org/LICENSE_1_0.txt)
//
#define SOCI_SQLITE3_SOURCE
#include "soci/sqlite3/soci-sqlite3.h"
#ifdef _MSC_VER
......
......@@ -5,7 +5,7 @@
// http://www.boost.org/LICENSE_1_0.txt)
//
#define SOCI_SQLITE3_SOURCE
#include "soci/sqlite3/soci-sqlite3.h"
#include "soci/connection-parameters.h"
......
......@@ -5,6 +5,7 @@
// http://www.boost.org/LICENSE_1_0.txt)
//
#define SOCI_SQLITE3_SOURCE
#include "soci/soci-platform.h"
#include "soci/sqlite3/soci-sqlite3.h"
#include "soci/rowid.h"
......
......@@ -5,6 +5,7 @@
// http://www.boost.org/LICENSE_1_0.txt)
//
#define SOCI_SQLITE3_SOURCE
#include "soci/soci-platform.h"
#include "soci/sqlite3/soci-sqlite3.h"
#include "soci/rowid.h"
......
......@@ -4,6 +4,8 @@
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#define SOCI_SQLITE3_SOURCE
#include "soci/sqlite3/soci-sqlite3.h"
// std
#include <algorithm>
......
......@@ -9,6 +9,7 @@
#pragma warning(disable : 4512)
#endif
#define SOCI_SQLITE3_SOURCE
#include "soci-dtocstr.h"
#include "soci-exchange-cast.h"
#include "soci/blob.h"
......
......@@ -5,6 +5,7 @@
// http://www.boost.org/LICENSE_1_0.txt)
//
#define SOCI_SQLITE3_SOURCE
#include "soci-exchange-cast.h"
#include "soci/soci-platform.h"
#include "soci/sqlite3/soci-sqlite3.h"
......
......@@ -361,16 +361,22 @@ bool session::get_last_insert_id(std::string const & sequence, long & value)
details::once_temp_type session::get_table_names()
{
ensureConnected(backEnd_);
return once << backEnd_->get_table_names_query();
}
details::prepare_temp_type session::prepare_table_names()
{
ensureConnected(backEnd_);
return prepare << backEnd_->get_table_names_query();
}
details::prepare_temp_type session::prepare_column_descriptions(std::string & table_name)
{
ensureConnected(backEnd_);
return prepare << backEnd_->get_column_descriptions_query(), use(table_name, "t");
}
......@@ -386,11 +392,15 @@ ddl_type session::create_table(const std::string & tableName)
void session::drop_table(const std::string & tableName)
{
ensureConnected(backEnd_);
once << backEnd_->drop_table(tableName);
}
void session::truncate_table(const std::string & tableName)
{
ensureConnected(backEnd_);
once << backEnd_->truncate_table(tableName);
}
......@@ -428,14 +438,41 @@ ddl_type session::drop_column(const std::string & tableName,
std::string session::empty_blob()
{
ensureConnected(backEnd_);
return backEnd_->empty_blob();
}
std::string session::nvl()
{
ensureConnected(backEnd_);
return backEnd_->nvl();
}
std::string session::get_dummy_from_table() const