From adcde5fa92861b38df2b225f3b82966ee15735f4 Mon Sep 17 00:00:00 2001 From: Howard Butler Date: Sun, 3 Feb 2013 11:01:43 -0600 Subject: [PATCH 1/9] Patch for SOCI/soci#46 to support readying bytea data in PostgreSQL --- src/backends/postgresql/statement.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backends/postgresql/statement.cpp b/src/backends/postgresql/statement.cpp index 26daca8b2..402a8e91c 100644 --- a/src/backends/postgresql/statement.cpp +++ b/src/backends/postgresql/statement.cpp @@ -504,6 +504,7 @@ void postgresql_statement_backend::describe_column(int colNum, data_type & type, case 18: // char case 1042: // bpchar case 142: // xml + case 17: // bytea type = dt_string; break; @@ -533,7 +534,7 @@ void postgresql_statement_backend::describe_column(int colNum, data_type & type, case 20: // int8 type = dt_long_long; break; - + default: { std::stringstream message; From 4962b5941c7d9cf62f59a9b0868de5bf07376313 Mon Sep 17 00:00:00 2001 From: Mateusz Loskot Date: Sun, 10 Feb 2013 01:48:58 +0000 Subject: [PATCH 2/9] PostgreSQL test for bytea - #46. Use case of bytea to dt_string mapping is unclear, so it needs to be confirmed if the ida is to allow the semantic as presented in the test_bytea() that data != (bin1 == bin1). --- .../postgresql/test/test-postgresql.cpp | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/backends/postgresql/test/test-postgresql.cpp b/src/backends/postgresql/test/test-postgresql.cpp index ccc863268..70827d880 100644 --- a/src/backends/postgresql/test/test-postgresql.cpp +++ b/src/backends/postgresql/test/test-postgresql.cpp @@ -544,6 +544,49 @@ void test12() std::cout << "test 12 passed" << std::endl; } +struct bytea_table_creator : public table_creator_base +{ + bytea_table_creator(session& sql) + : table_creator_base(sql) + { + sql << "drop table if exists soci_test;"; + sql << "create table soci_test ( val bytea null )"; + } +}; + +void test_bytea() +{ + { + session sql(backEnd, connectString); + bytea_table_creator tableCreator(sql); + + int v = 0x0A0B0C0D; + unsigned char* b = reinterpret_cast(&v); + std::string data; + std::copy(b, b + sizeof(v), std::back_inserter(data)); + { + + sql << "insert into soci_test(val) values(:val)", use(data); + + // 1) into string, no Oid mapping + std::string bin1; + sql << "select val from soci_test", into(bin1); + assert(bin1 == "\\x0d0c0b0a"); + + // 2) Oid-to-dt_string mapped + row r; + sql << "select * from soci_test", into(r); + + assert(r.size() == 1); + column_properties const& props = r.get_properties(0); + assert(props.get_data_type() == soci::dt_string); + std::string bin2 = r.get(0); + assert(bin2 == "\\x0d0c0b0a"); + } + } + std::cout << "test_bytea passed" << std::endl; +} + // DDL Creation objects for common tests struct table_creator_one : public table_creator_base { @@ -637,6 +680,8 @@ int main(int argc, char** argv) try { + test_bytea(); + test_context tc(backEnd, connectString); common_tests tests(tc); tests.run(); @@ -658,6 +703,7 @@ int main(int argc, char** argv) test10(); test11(); test12(); + test_bytea(); std::cout << "\nOK, all tests passed.\n\n"; return EXIT_SUCCESS; From c18cf358ca07a20b18d2284844fd74c6396cd3b3 Mon Sep 17 00:00:00 2001 From: Viacheslav Naydenov Date: Sun, 10 Feb 2013 08:46:12 +0400 Subject: [PATCH 3/9] Fix Ubuntu detection at build configure stage --- src/CMakeLists.txt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fda71e4cd..8f3ce3de5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -69,13 +69,18 @@ include(SociDependencies) if(EXISTS /etc/os-release) file(READ /etc/os-release OS_RELEASE) - string(REGEX MATCH "ID(_LIKE?)=debian" DEBIAN ${OS_RELEASE}) - string(REGEX MATCH "ID(_LIKE?)=fedora" FEDORA ${OS_RELEASE}) - string(REGEX MATCH "ID(_LIKE?)=ubuntu" UBUNTU ${OS_RELEASE}) + string(REGEX MATCH "ID(_LIKE)?=debian" DEBIAN ${OS_RELEASE}) + string(REGEX MATCH "ID(_LIKE)?=fedora" FEDORA ${OS_RELEASE}) + string(REGEX MATCH "ID(_LIKE)?=ubuntu" UBUNTU ${OS_RELEASE}) +elseif(EXISTS /etc/lsb-release) + file(READ /etc/lsb-release OS_RELEASE) + string(REGEX MATCH "DISTRIB_ID=[Uu]buntu" UBUNTU ${OS_RELEASE}) + string(REGEX MATCH "DISTRIB_ID=[Db]ebian" DEBIAN ${OS_RELEASE}) endif() - -if(DEBIAN) +if(UBUNTU) + set(SOCI_LIBDIR "lib") +elseif(DEBIAN) execute_process(COMMAND uname -m OUTPUT_VARIABLE SOCI_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE) From 60c947340f58f556f93743558c8afdb9f48a31c6 Mon Sep 17 00:00:00 2001 From: Viacheslav Naydenov Date: Sun, 10 Feb 2013 10:53:48 +0400 Subject: [PATCH 4/9] Build Firebird backend using patch from Sergei Nikulov --- src/backends/firebird/CMakeLists.txt | 9 +++ src/backends/firebird/test/CMakeLists.txt | 5 ++ src/backends/firebird/test/test-firebird.cpp | 59 +++++++++----------- src/cmake/SociDependencies.cmake | 3 +- src/cmake/dependencies/Firebird.cmake | 6 ++ src/cmake/modules/FindFirebird.cmake | 35 ++++++++++++ 6 files changed, 84 insertions(+), 33 deletions(-) create mode 100644 src/backends/firebird/CMakeLists.txt create mode 100644 src/backends/firebird/test/CMakeLists.txt create mode 100644 src/cmake/dependencies/Firebird.cmake create mode 100644 src/cmake/modules/FindFirebird.cmake diff --git a/src/backends/firebird/CMakeLists.txt b/src/backends/firebird/CMakeLists.txt new file mode 100644 index 000000000..9af2acd42 --- /dev/null +++ b/src/backends/firebird/CMakeLists.txt @@ -0,0 +1,9 @@ +soci_backend(Firebird + DEPENDS Firebird + HEADERS soci-firebird.h common.h + DESCRIPTION "SOCI backend for Firebird database engine" + AUTHORS "TBD" + MAINTAINERS "TBD") + +add_subdirectory(test) + diff --git a/src/backends/firebird/test/CMakeLists.txt b/src/backends/firebird/test/CMakeLists.txt new file mode 100644 index 000000000..d01a60a13 --- /dev/null +++ b/src/backends/firebird/test/CMakeLists.txt @@ -0,0 +1,5 @@ +soci_backend_test( + BACKEND Firebird + SOURCE test-firebird.cpp + CONNSTR "dummy") + diff --git a/src/backends/firebird/test/test-firebird.cpp b/src/backends/firebird/test/test-firebird.cpp index 1283926e8..757db0d8e 100644 --- a/src/backends/firebird/test/test-firebird.cpp +++ b/src/backends/firebird/test/test-firebird.cpp @@ -14,6 +14,7 @@ #include #include #include +#include using namespace soci; @@ -86,6 +87,7 @@ void test2() sql << "delete from test2"; } +#if 0 { char msg[] = "Hello, Firebird!"; char buf1[100], buf2[100], buf3[100]; @@ -96,18 +98,7 @@ void test2() sql << "insert into test2(p1, p2) values (?,?)", use(b1, 100), use(b1, 100); sql << "select p1, p2 from test2", into(b2, 100), into(b3, 100); - assert( - buf2[0] == 'H' && buf3[0] == 'H' && - buf2[1] == 'e' && buf3[1] == 'e' && - buf2[2] == 'l' && buf3[2] == 'l' && - buf2[3] == 'l' && buf3[3] == 'l' && - buf2[4] == 'o' && buf3[4] == 'o' && - buf2[5] == ',' && buf3[5] == ',' && - buf2[6] == ' ' && buf3[6] == ' ' && - buf2[7] == 'F' && buf3[7] == 'F' && - buf2[8] == 'i' && buf3[8] == 'i' && - buf2[9] == 'r' && buf3[9] == 'r' && - buf2[10] == '\0' && buf3[10] == '\0'); + assert(!std::strcmp(buf2, buf3) && !std::strcmp(buf2, "Hello, Fir")); sql << "delete from test2"; } @@ -121,18 +112,19 @@ void test2() use(buf1), use(buf1); sql << "select p1, p2 from test2", into(buf2), into(buf3); - assert( - buf2[0] == 'H' && buf3[0] == 'H' && - buf2[1] == 'e' && buf3[1] == 'e' && - buf2[2] == 'l' && buf3[2] == 'l' && - buf2[3] == 'l' && buf3[3] == 'l' && - buf2[4] == 'o' && buf3[4] == 'o' && - buf2[5] == ',' && buf3[5] == ',' && - buf2[6] == ' ' && buf3[6] == ' ' && - buf2[7] == 'F' && buf3[7] == 'F' && - buf2[8] == 'i' && buf3[8] == 'i' && - buf2[9] == 'r' && buf3[9] == 'r' && - buf2[10] == '\0' && buf3[10] == '\0'); + assert(!std::strcmp(buf2, buf3) && !std::strcmp(buf2, "Hello, Fir")); + + sql << "delete from test2"; + } +#endif + + { + std::string b1("Hello, Firebird!"), b2, b3; + + sql << "insert into test2(p1, p2) values (?,?)", use(b1), use(b1); + sql << "select p1, p2 from test2", into(b2), into(b3); + + assert(b2 == b3 && b2 == "Hello, Fir"); sql << "delete from test2"; } @@ -144,7 +136,9 @@ void test2() sql << "insert into test2(p1) values(\'" << msg << "\')"; char buf[20]; - sql << "select p1 from test2", into(buf); + std::string buf_str; + sql << "select p1 from test2", into(buf_str); + std::strcpy(buf, buf_str.c_str()); assert(std::strncmp(buf, msg, 5) == 0); assert(std::strncmp(buf+5, " ", 5) == 0); @@ -322,7 +316,8 @@ void test5() assert(ind == i_null); char buf[4]; - sql << "select \'Hello\' from rdb$database", into(buf, ind); + std::string buf_str; + sql << "select \'Hello\' from rdb$database", into(buf_str, ind); assert(ind == i_truncated); sql << "select 5 from rdb$database where 0 = 1", into(i, ind); @@ -1069,9 +1064,9 @@ void test11() // Support for soci Common Tests // -struct table_creator_1 : public tests::table_creator_base +struct TableCreator1 : public tests::table_creator_base { - table_creator_1(session & sql) + TableCreator1(session & sql) : tests::table_creator_base(sql) { sql << "create table soci_test(id integer, val integer, c char, " @@ -1082,9 +1077,9 @@ struct table_creator_1 : public tests::table_creator_base } }; -struct table_creator_2 : public tests::table_creator_base +struct TableCreator2 : public tests::table_creator_base { - table_creator_2(session & sql) + TableCreator2(session & sql) : tests::table_creator_base(sql) { sql << "create table soci_test(\"num_float\" float, \"num_int\" integer, " @@ -1094,9 +1089,9 @@ struct table_creator_2 : public tests::table_creator_base } }; -struct table_creator_3 : public tests::table_creator_base +struct TableCreator3 : public tests::table_creator_base { - table_creator_3(session & sql) + TableCreator3(session & sql) : tests::table_creator_base(sql) { // CommonTest uses lower-case column names, diff --git a/src/cmake/SociDependencies.cmake b/src/cmake/SociDependencies.cmake index a38f5b294..060e446c6 100644 --- a/src/cmake/SociDependencies.cmake +++ b/src/cmake/SociDependencies.cmake @@ -24,7 +24,8 @@ set(SOCI_BACKENDS_DB_DEPENDENCIES ODBC Oracle PostgreSQL - SQLite3) + SQLite3 + Firebird) set(SOCI_BACKENDS_ALL_DEPENDENCIES Boost diff --git a/src/cmake/dependencies/Firebird.cmake b/src/cmake/dependencies/Firebird.cmake new file mode 100644 index 000000000..73c8f598e --- /dev/null +++ b/src/cmake/dependencies/Firebird.cmake @@ -0,0 +1,6 @@ +set(Firebird_FIND_QUIETLY TRUE) + +find_package(Firebird) + +boost_external_report(Firebird INCLUDE_DIR LIBRARIES VERSION) + diff --git a/src/cmake/modules/FindFirebird.cmake b/src/cmake/modules/FindFirebird.cmake new file mode 100644 index 000000000..e7317edd2 --- /dev/null +++ b/src/cmake/modules/FindFirebird.cmake @@ -0,0 +1,35 @@ +############################################################## +# Copyright (c) 2008 Daniel Pfeifer # +# # +# Distributed under the Boost Software License, Version 1.0. # +############################################################## + +# This module defines +# FIREBIRD_INCLUDE_DIR - where to find ibase.h +# FIREBIRD_LIBRARIES - the libraries to link against to use FIREBIRD +# FIREBIRD_FOUND - true if FIREBIRD was found + +cmake_minimum_required(VERSION 2.6) + +find_path(FIREBIRD_INCLUDE_DIR ibase.h + /usr/include + $ENV{ProgramFiles}/Firebird/*/include +) + +find_library(FIREBIRD_LIBRARIES + NAMES + fbclient + fbclient_ms + PATHS + /usr/lib + $ENV{ProgramFiles}/Firebird/*/lib +) + +# fbembed ? + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Firebird + DEFAULT_MSG FIREBIRD_LIBRARIES FIREBIRD_INCLUDE_DIR) + +mark_as_advanced(FIREBIRD_INCLUDE_DIR FIREBIRD_LIBRARIES) + From a85b995385bfbfd960e794dcc52baea04071e5fe Mon Sep 17 00:00:00 2001 From: Viacheslav Naydenov Date: Sun, 10 Feb 2013 13:41:57 +0400 Subject: [PATCH 5/9] Firebird backend: Fix into() binding for 64bit integers --- src/backends/firebird/common.h | 4 ++-- src/cmake/modules/FindFirebird.cmake | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/backends/firebird/common.h b/src/backends/firebird/common.h index 37e4bdd61..5070b625a 100644 --- a/src/backends/firebird/common.h +++ b/src/backends/firebird/common.h @@ -114,9 +114,9 @@ T1 from_isc(XSQLVAR * var) case SQL_SHORT: return static_cast(*reinterpret_cast(var->sqldata)/tens); case SQL_LONG: - return static_cast(*reinterpret_cast(var->sqldata)/tens); + return static_cast(*reinterpret_cast(var->sqldata)/tens); case SQL_INT64: - return static_cast(*reinterpret_cast(var->sqldata)/tens); + return static_cast(*reinterpret_cast(var->sqldata)/tens); case SQL_FLOAT: return static_cast(*reinterpret_cast(var->sqldata)); case SQL_DOUBLE: diff --git a/src/cmake/modules/FindFirebird.cmake b/src/cmake/modules/FindFirebird.cmake index e7317edd2..4fa279df2 100644 --- a/src/cmake/modules/FindFirebird.cmake +++ b/src/cmake/modules/FindFirebird.cmake @@ -9,8 +9,6 @@ # FIREBIRD_LIBRARIES - the libraries to link against to use FIREBIRD # FIREBIRD_FOUND - true if FIREBIRD was found -cmake_minimum_required(VERSION 2.6) - find_path(FIREBIRD_INCLUDE_DIR ibase.h /usr/include $ENV{ProgramFiles}/Firebird/*/include From 4c3cb6297717f46ca68dec5f468b8fca3d98ebd3 Mon Sep 17 00:00:00 2001 From: Viacheslav Naydenov Date: Mon, 11 Feb 2013 11:18:05 +0400 Subject: [PATCH 6/9] Fix Firebird backend to pass all the tests --- src/backends/firebird/common.h | 22 ++++++++------ src/backends/firebird/soci-firebird.h | 1 + src/backends/firebird/statement.cpp | 7 ++++- src/backends/firebird/test/test-firebird.cpp | 30 +++++++------------- src/backends/firebird/vector-into-type.cpp | 2 +- 5 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/backends/firebird/common.h b/src/backends/firebird/common.h index 5070b625a..25d2895be 100644 --- a/src/backends/firebird/common.h +++ b/src/backends/firebird/common.h @@ -66,21 +66,27 @@ void to_isc(void * val, XSQLVAR * var) break; case SQL_LONG: { - long tmp = static_cast(value*tens); - memcpy(var->sqldata, &tmp, sizeof(long)); + int tmp = static_cast(value*tens); + memcpy(var->sqldata, &tmp, sizeof(int)); } break; case SQL_INT64: { - ISC_INT64 tmp = static_cast(value*tens); - memcpy(var->sqldata, &tmp, sizeof(ISC_INT64)); + long long tmp = static_cast(value*tens); + memcpy(var->sqldata, &tmp, sizeof(long long)); } break; case SQL_FLOAT: - memcpy(var->sqldata, &value, sizeof(float)); - break; + { + float sql_value = static_cast(value); + memcpy(var->sqldata, &sql_value, sizeof(float)); + break; + } case SQL_DOUBLE: - memcpy(var->sqldata, &value, sizeof(double)); + { + double sql_value = static_cast(value); + memcpy(var->sqldata, &sql_value, sizeof(double)); + } break; default: throw soci_error("Incorrect data type for numeric conversion"); @@ -114,7 +120,7 @@ T1 from_isc(XSQLVAR * var) case SQL_SHORT: return static_cast(*reinterpret_cast(var->sqldata)/tens); case SQL_LONG: - return static_cast(*reinterpret_cast(var->sqldata)/tens); + return static_cast(*reinterpret_cast(var->sqldata)/tens); case SQL_INT64: return static_cast(*reinterpret_cast(var->sqldata)/tens); case SQL_FLOAT: diff --git a/src/backends/firebird/soci-firebird.h b/src/backends/firebird/soci-firebird.h index cb8332050..04acf8faf 100644 --- a/src/backends/firebird/soci-firebird.h +++ b/src/backends/firebird/soci-firebird.h @@ -209,6 +209,7 @@ struct firebird_statement_backend : details::statement_backend protected: int rowsFetched_; + bool endOfRowSet_; virtual void exchangeData(bool gotData, int row); virtual void prepareSQLDA(XSQLDA ** sqldap, int size = 10); diff --git a/src/backends/firebird/statement.cpp b/src/backends/firebird/statement.cpp index c3d9e731e..a222e5467 100644 --- a/src/backends/firebird/statement.cpp +++ b/src/backends/firebird/statement.cpp @@ -17,7 +17,7 @@ using namespace soci::details::firebird; firebird_statement_backend::firebird_statement_backend(firebird_session_backend &session) : session_(session), stmtp_(0), sqldap_(NULL), sqlda2p_(NULL), - boundByName_(false), boundByPos_(false), rowsFetched_(0), + boundByName_(false), boundByPos_(false), rowsFetched_(0), endOfRowSet_(false), intoType_(eStandard), useType_(eStandard), procedure_(false) {} @@ -460,6 +460,9 @@ firebird_statement_backend::execute(int number) statement_backend::exec_fetch_result firebird_statement_backend::fetch(int number) { + if (endOfRowSet_) + return ef_no_data; + ISC_STATUS stat[stat_size]; for (size_t i = 0; i(sqldap_->sqld); ++i) @@ -483,11 +486,13 @@ firebird_statement_backend::fetch(int number) } else if (fetch_stat == 100L) { + endOfRowSet_ = true; return ef_no_data; } else { // error + endOfRowSet_ = true; throw_iscerror(stat); return ef_no_data; // unreachable, for compiler only } diff --git a/src/backends/firebird/test/test-firebird.cpp b/src/backends/firebird/test/test-firebird.cpp index 757db0d8e..2542a1913 100644 --- a/src/backends/firebird/test/test-firebird.cpp +++ b/src/backends/firebird/test/test-firebird.cpp @@ -87,7 +87,7 @@ void test2() sql << "delete from test2"; } -#if 0 +#if 0 // SOCI doesn't support binding into(char *, ...) anymore, use std::string { char msg[] = "Hello, Firebird!"; char buf1[100], buf2[100], buf3[100]; @@ -315,10 +315,11 @@ void test5() sql << "select NULL from rdb$database", into(i, ind); assert(ind == i_null); +#if 0 // SOCI doesn't support binding into(char *, ...) anymore, use std::string char buf[4]; - std::string buf_str; - sql << "select \'Hello\' from rdb$database", into(buf_str, ind); + sql << "select \'Hello\' from rdb$database", into(buf, ind); assert(ind == i_truncated); +#endif sql << "select 5 from rdb$database where 0 = 1", into(i, ind); assert(sql.got_data() == false); @@ -336,18 +337,9 @@ void test5() "Null value fetched and no indicator defined."); } - try - { - // expect error - sql << "select 5 from rdb$database where 0 = 1", into(i); - assert(false); - } - catch (soci_error const &e) - { - std::string error = e.what(); - assert(error == - "No data fetched and no indicator defined."); - } + // expect no data + sql << "select 5 from rdb$database where 0 = 1", into(i); + assert(!sql.got_data()); } std::cout << "test 5 passed" << std::endl; @@ -1082,8 +1074,8 @@ struct TableCreator2 : public tests::table_creator_base TableCreator2(session & sql) : tests::table_creator_base(sql) { - sql << "create table soci_test(\"num_float\" float, \"num_int\" integer, " - "\"name\" varchar(20), \"sometime\" timestamp, \"chr\" char)"; + sql << "create table soci_test(num_float float, num_int integer, " + "name varchar(20), sometime timestamp, chr char)"; sql.commit(); sql.begin(); } @@ -1097,8 +1089,8 @@ struct TableCreator3 : public tests::table_creator_base // CommonTest uses lower-case column names, // so we need to enforce such names here. // That's why column names are enclosed in "" - sql << "create table soci_test(\"name\" varchar(100) not null, " - "\"phone\" varchar(15))"; + sql << "create table soci_test(name varchar(100) not null, " + "phone varchar(15))"; sql.commit(); sql.begin(); } diff --git a/src/backends/firebird/vector-into-type.cpp b/src/backends/firebird/vector-into-type.cpp index 6f2442480..f53457247 100644 --- a/src/backends/firebird/vector-into-type.cpp +++ b/src/backends/firebird/vector-into-type.cpp @@ -112,7 +112,7 @@ void firebird_vector_into_type_backend::post_fetch( // buffers during fetch() if (gotData) { - std::size_t rows = statement_.inds_[0].size(); + std::size_t rows = statement_.rowsFetched_; for (std::size_t i = 0; i Date: Sat, 9 Feb 2013 23:39:49 +0000 Subject: [PATCH 7/9] Add missing ODBC tests to CMake configuration (issue #62) Travis config update required (issue #49) --- src/backends/odbc/test/CMakeLists.txt | 12 ++++++++++++ src/backends/odbc/test/test-access.dsn | 2 +- src/backends/odbc/test/test-mssql.dsn | 2 +- src/backends/odbc/test/test-mysql.dsn | 2 +- src/backends/odbc/test/test-odbc-mssql.cpp | 3 +-- src/backends/odbc/test/test-odbc-mysql.cpp | 13 +++++++++---- 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/backends/odbc/test/CMakeLists.txt b/src/backends/odbc/test/CMakeLists.txt index 59a89ec69..0bd29b4a2 100644 --- a/src/backends/odbc/test/CMakeLists.txt +++ b/src/backends/odbc/test/CMakeLists.txt @@ -4,6 +4,18 @@ soci_backend_test( SOURCE test-odbc-access.cpp CONNSTR "test-access.dsn") +soci_backend_test( + NAME mssql + BACKEND ODBC + SOURCE test-odbc-mssql.cpp + CONNSTR "test-mssql.dsn") + +soci_backend_test( + NAME mysql + BACKEND ODBC + SOURCE test-odbc-mysql.cpp + CONNSTR "test-mysql.dsn") + soci_backend_test( NAME postgresql BACKEND ODBC diff --git a/src/backends/odbc/test/test-access.dsn b/src/backends/odbc/test/test-access.dsn index d695319f0..597ff131d 100644 --- a/src/backends/odbc/test/test-access.dsn +++ b/src/backends/odbc/test/test-access.dsn @@ -10,4 +10,4 @@ MaxBufferSize=2048 FIL=MS Access DriverId=25 DefaultDir=.\ -DBQ=.\soci.mdb +DBQ=.\soci_test.mdb diff --git a/src/backends/odbc/test/test-mssql.dsn b/src/backends/odbc/test/test-mssql.dsn index aef33476f..f96dc7011 100644 --- a/src/backends/odbc/test/test-mssql.dsn +++ b/src/backends/odbc/test/test-mssql.dsn @@ -1,7 +1,7 @@ [ODBC] DRIVER=SQL Native Client UID=David -DATABASE=socitest +DATABASE=soci_test WSID=NANO APP=Microsoft Data Access Components Trusted_Connection=Yes diff --git a/src/backends/odbc/test/test-mysql.dsn b/src/backends/odbc/test/test-mysql.dsn index 3e7c7a40b..edb0011e8 100644 --- a/src/backends/odbc/test/test-mysql.dsn +++ b/src/backends/odbc/test/test-mysql.dsn @@ -1,6 +1,6 @@ [ODBC] DRIVER=MySQL ODBC 3.51 Driver -DATABASE=socitest +DATABASE=soci_test USER=root PORT=0 OPTION=0 diff --git a/src/backends/odbc/test/test-odbc-mssql.cpp b/src/backends/odbc/test/test-odbc-mssql.cpp index bf26f9026..38db4fd5f 100644 --- a/src/backends/odbc/test/test-odbc-mssql.cpp +++ b/src/backends/odbc/test/test-odbc-mssql.cpp @@ -18,8 +18,7 @@ using namespace soci; using namespace soci::tests; std::string connectString; -backend_factory const &backEnd = odbc; - +backend_factory const &backEnd = *soci::factory_odbc(); // DDL Creation objects for common tests struct table_creator_one : public table_creator_base diff --git a/src/backends/odbc/test/test-odbc-mysql.cpp b/src/backends/odbc/test/test-odbc-mysql.cpp index d4fe31bc3..437234fb4 100644 --- a/src/backends/odbc/test/test-odbc-mysql.cpp +++ b/src/backends/odbc/test/test-odbc-mysql.cpp @@ -18,7 +18,7 @@ using namespace soci; using namespace soci::tests; std::string connectString; -backend_factory const &backEnd = odbc; +backend_factory const &backEnd = *soci::factory_odbc(); // DDL Creation objects for common tests struct table_creator_one : public table_creator_base @@ -45,7 +45,7 @@ struct table_creator_two : public table_creator_base struct table_creator_three : public table_creator_base { - table_creator_three(ession & sql) + table_creator_three(session & sql) : table_creator_base(sql) { sql << "create table soci_test(name varchar(100) not null, " @@ -69,12 +69,17 @@ class test_context : public test_context_base return new table_creator_one(s); } - table_creator_base * tableCreator2(session& s) const + table_creator_base * table_creator_2(session& s) const { return new table_creator_two(s); } - table_creator_base * tableCreator3(session& s) const + table_creator_base * table_creator_3(session& s) const + { + return new table_creator_three(s); + } + + table_creator_base * table_creator_4(session& s) const { return new table_creator_three(s); } From 1469f848ca52d308b9524231dac1dc32899eb27f Mon Sep 17 00:00:00 2001 From: Viacheslav Naydenov Date: Tue, 12 Feb 2013 21:22:15 +0400 Subject: [PATCH 8/9] Playing with setTextParam() --- src/backends/firebird/common.cpp | 37 +++++++++++++++++++++ src/backends/firebird/standard-use-type.cpp | 4 +++ src/backends/firebird/statement.cpp | 2 ++ 3 files changed, 43 insertions(+) diff --git a/src/backends/firebird/common.cpp b/src/backends/firebird/common.cpp index a5549244a..df0c7051d 100644 --- a/src/backends/firebird/common.cpp +++ b/src/backends/firebird/common.cpp @@ -10,7 +10,9 @@ #include // FireBird #include #include +#include #include +#include #include namespace soci @@ -82,6 +84,7 @@ void tmDecode(short type, void * src, std::tm * dst) void setTextParam(char const * s, std::size_t size, char * buf_, XSQLVAR * var) { + std::cerr << "setTextParam: var->sqltype=" << var->sqltype << std::endl; short sz = 0; if (size < static_cast(var->sqllen)) { @@ -105,6 +108,39 @@ void setTextParam(char const * s, std::size_t size, char * buf_, memset(buf_+sz, ' ', var->sqllen - sz); } } + else if ((var->sqltype & ~1) == SQL_INT64) + { + long long t; + std::stringstream input(s); + input >> t; + if (input.bad()) + throw soci_error("Could not parse integer value."); + memcpy(buf_, &t, sizeof(t)); + to_isc(buf_, var); + } + else if ((var->sqltype & ~1) == SQL_TIMESTAMP) + { + unsigned short year, month, day, hour, min, sec; + if (std::sscanf(s, "%hu-%hu-%huT%hu:%hu:%hu", + &year, &month, &day, &hour, &min, &sec) != 6) + { + if (std::sscanf(s, "%hu-%hu-%hu %hu:%hu:%hu", + &year, &month, &day, &hour, &min, &sec) != 6) + { + throw soci_error("Could not parse timestamp value."); + } + } + std::tm t; + memset(&t, 0, sizeof(t)); + t.tm_year = year - 1900; + t.tm_mon = month - 1; + t.tm_mday = day; + t.tm_hour = hour; + t.tm_min = min; + t.tm_sec = sec; + memcpy(buf_, &t, sizeof(t)); + tmEncode(var->sqltype, &t, buf_); + } else { throw soci_error("Unexpected string type."); @@ -113,6 +149,7 @@ void setTextParam(char const * s, std::size_t size, char * buf_, std::string getTextParam(XSQLVAR const *var) { + std::cerr << "getTextParam: var->sqltype=" << var->sqltype << std::endl; short size; std::size_t offset = 0; diff --git a/src/backends/firebird/standard-use-type.cpp b/src/backends/firebird/standard-use-type.cpp index 1511e791e..282e29877 100644 --- a/src/backends/firebird/standard-use-type.cpp +++ b/src/backends/firebird/standard-use-type.cpp @@ -77,6 +77,7 @@ void firebird_standard_use_type_backend::bind_by_name( void firebird_standard_use_type_backend::pre_use(indicator const * ind) { + indISCHolder_ = 0; if (ind) { switch (*ind) @@ -97,6 +98,9 @@ void firebird_standard_use_type_backend::exchangeData() { XSQLVAR *var = statement_.sqlda2p_->sqlvar+position_; + if (0 != indISCHolder_) + return; + switch (type_) { case x_char: diff --git a/src/backends/firebird/statement.cpp b/src/backends/firebird/statement.cpp index a222e5467..13ed0ac19 100644 --- a/src/backends/firebird/statement.cpp +++ b/src/backends/firebird/statement.cpp @@ -10,6 +10,7 @@ #include "error-firebird.h" #include #include +#include using namespace soci; using namespace soci::details; @@ -286,6 +287,7 @@ void firebird_statement_backend::rewriteQuery( void firebird_statement_backend::prepare(std::string const & query, statement_type /* eType */) { + std::cerr << "prepare: query=" << query << std::endl; // clear named parametes names_.clear(); From 870013c0d50601f3bbe08d1b16a51c09d34c4c99 Mon Sep 17 00:00:00 2001 From: Viacheslav Naydenov Date: Wed, 13 Feb 2013 20:36:11 +0400 Subject: [PATCH 9/9] Binding input params: allow to pass strings --- src/backends/firebird/common.cpp | 78 +++++++++++++++++++++++++------- src/backends/firebird/common.h | 42 +++++++++++++++-- 2 files changed, 99 insertions(+), 21 deletions(-) diff --git a/src/backends/firebird/common.cpp b/src/backends/firebird/common.cpp index df0c7051d..5a871c221 100644 --- a/src/backends/firebird/common.cpp +++ b/src/backends/firebird/common.cpp @@ -97,48 +97,94 @@ void setTextParam(char const * s, std::size_t size, char * buf_, if ((var->sqltype & ~1) == SQL_VARYING) { - memcpy(buf_, &sz, sizeof(short)); - memcpy(buf_ + sizeof(short), s, sz); + std::memcpy(buf_, &sz, sizeof(short)); + std::memcpy(buf_ + sizeof(short), s, sz); } else if ((var->sqltype & ~1) == SQL_TEXT) { - memcpy(buf_, s, sz); + std::memcpy(buf_, s, sz); if (sz < var->sqllen) { - memset(buf_+sz, ' ', var->sqllen - sz); + std::memset(buf_+sz, ' ', var->sqllen - sz); } } + else if ((var->sqltype & ~1) == SQL_SHORT) + { + unsigned short t1; + short t2; + if (!*str2int(s, t1)) + std::memcpy(buf_, &t1, sizeof(t1)); + else if (!*str2int(s, t2)) + std::memcpy(buf_, &t2, sizeof(t2)); + else + throw soci_error("Could not parse int16 value."); + to_isc(buf_, var); + } + else if ((var->sqltype & ~1) == SQL_LONG) + { + unsigned t1; + int t2; + if (!*str2int(s, t1)) + std::memcpy(buf_, &t1, sizeof(t1)); + else if (!*str2int(s, t2)) + std::memcpy(buf_, &t2, sizeof(t2)); + else + throw soci_error("Could not parse int32 value."); + to_isc(buf_, var); + } else if ((var->sqltype & ~1) == SQL_INT64) { - long long t; - std::stringstream input(s); - input >> t; - if (input.bad()) - throw soci_error("Could not parse integer value."); - memcpy(buf_, &t, sizeof(t)); + unsigned long long t1; + long long t2; + if (!*str2int(s, t1)) + std::memcpy(buf_, &t1, sizeof(t1)); + else if (!*str2int(s, t2)) + std::memcpy(buf_, &t2, sizeof(t2)); + else + throw soci_error("Could not parse int64 value."); to_isc(buf_, var); } - else if ((var->sqltype & ~1) == SQL_TIMESTAMP) + else if ((var->sqltype & ~1) == SQL_TIMESTAMP + or (var->sqltype & ~1) == SQL_TYPE_DATE) { unsigned short year, month, day, hour, min, sec; - if (std::sscanf(s, "%hu-%hu-%huT%hu:%hu:%hu", + if (std::sscanf(s, "%hu-%hu-%hu %hu:%hu:%hu", &year, &month, &day, &hour, &min, &sec) != 6) { - if (std::sscanf(s, "%hu-%hu-%hu %hu:%hu:%hu", + if (std::sscanf(s, "%hu-%hu-%huT%hu:%hu:%hu", &year, &month, &day, &hour, &min, &sec) != 6) { - throw soci_error("Could not parse timestamp value."); + hour = min = sec = 0; + if (std::sscanf(s, "%hu-%hu-%hu", &year, &month, &day) != 3) + { + throw soci_error("Could not parse timestamp value."); + } } } std::tm t; - memset(&t, 0, sizeof(t)); + std::memset(&t, 0, sizeof(t)); t.tm_year = year - 1900; t.tm_mon = month - 1; t.tm_mday = day; t.tm_hour = hour; t.tm_min = min; t.tm_sec = sec; - memcpy(buf_, &t, sizeof(t)); + std::memcpy(buf_, &t, sizeof(t)); + tmEncode(var->sqltype, &t, buf_); + } + else if ((var->sqltype & ~1) == SQL_TYPE_TIME) + { + unsigned short hour, min, sec; + if (std::sscanf(s, "%hu:%hu:%hu", &hour, &min, &sec) != 3) + { + throw soci_error("Could not parse timestamp value."); + } + std::tm t; + std::memset(&t, 0, sizeof(t)); + t.tm_hour = hour; + t.tm_min = min; + t.tm_sec = sec; + std::memcpy(buf_, &t, sizeof(t)); tmEncode(var->sqltype, &t, buf_); } else diff --git a/src/backends/firebird/common.h b/src/backends/firebird/common.h index 25d2895be..e6c12d714 100644 --- a/src/backends/firebird/common.h +++ b/src/backends/firebird/common.h @@ -37,6 +37,38 @@ void setTextParam(char const * s, std::size_t size, char * buf_, std::string getTextParam(XSQLVAR const *var); +template +const char *str2int(const char * s, IntType &out) +{ + int sign = 1; + if ('+' == *s) + ++s; + else if ('-' == *s) + { + sign = -1; + ++s; + } + IntType res = 0; + for (out = 0; *s; ++s, out = res) + { + int d = *s - '0'; + if (d < 0 || d > 9) + return s; + res = res * 10 + d * sign; + if (1 == sign) + { + if (res < out) + return s; + } + else + { + if (res > out) + return s; + } + } + return s; +} + template void to_isc(void * val, XSQLVAR * var) { @@ -67,25 +99,25 @@ void to_isc(void * val, XSQLVAR * var) case SQL_LONG: { int tmp = static_cast(value*tens); - memcpy(var->sqldata, &tmp, sizeof(int)); + std::memcpy(var->sqldata, &tmp, sizeof(int)); } break; case SQL_INT64: { long long tmp = static_cast(value*tens); - memcpy(var->sqldata, &tmp, sizeof(long long)); + std::memcpy(var->sqldata, &tmp, sizeof(long long)); } break; case SQL_FLOAT: { float sql_value = static_cast(value); - memcpy(var->sqldata, &sql_value, sizeof(float)); - break; + std::memcpy(var->sqldata, &sql_value, sizeof(float)); } + break; case SQL_DOUBLE: { double sql_value = static_cast(value); - memcpy(var->sqldata, &sql_value, sizeof(double)); + std::memcpy(var->sqldata, &sql_value, sizeof(double)); } break; default: