Skip to content

C++ compile time odbc binding generator (supports BLOBs)

Notifications You must be signed in to change notification settings

serge-klim/odbcx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

odbcx

Build Status Build status codecov

C++ compile time odbc binding generator.

Requirements

How it works:

Let's say that there is test table defined like this:

	 CREATE TABLE test (
	     ID INTEGER GENERATED by default on null as IDENTITY,
	     TS TIMESTAMP,
	     TARGET VARCHAR2(100),
	     MESSAGETYPE VARCHAR2(100),
	     N INTEGER,
	     DATA BLOB
	 );

First of odbc connection has to be established:

    auto env = odbcx::handle::allocate<SQL_HANDLE_ENV>();
    odbcx::handle::set_attribute(env, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3_80);
    auto  dbc = odbcx::handle::allocate<SQL_HANDLE_DBC>(env);
    odbcx::connect(dbc, "Driver={PostgreSQL ANSI};server=localhost;database=test;UID=user;PWD=password;");

now let's clenup the test table to make sure that the rest of example will work:

    odbcx::query(dbc, "delete from test");

and make sure there is no records in the test table:

    auto n = odbcx::query_one<long>(dbc, "SELECT count(id) FROM test");
    assert(n.get() == 0);

odbcx::query_one<long> will generate binding for long, prepares statement, execute it and fetch result. It returns std/boost::optional<long>.

let's insert some data into the test table:

        auto type1 = std::string{ "type 1" };
        odbcx::query(dbc, "insert into test (target, messagetype, n) values(?,?,?)", "first", type1, 500);
        odbcx::query(dbc, "insert into test (target, messagetype, pb) values(?,?,?)", std::string{ "second" },
						  		  	   				 	type1, std::vector<std::uint8_t>(100 * 1024, 0xF));
        auto empty = std::string{};
        odbcx::query(dbc, "insert into test (target, messagetype, pb) values(?,?,?)",
						  		  	   				 empty, type1, std::vector<std::uint8_t>{});

for any arguments on top of connection handle and SQL odbcx::query will generate input bindings and execute prepareded query.

    auto cursor = odbcx::query<std::tuple<int, SQL_TIMESTAMP_STRUCT, std::string, std::vector<std::uint8_t>>>
	 								(dbc, "SELECT id, ts, target, pb FROM test where messagetype = ?", type1);
    auto range = cursor.fetch();
    for (auto const& rec : range)
    {
        auto const& id = std::get<int>(rec);
        auto const& ts = std::get<SQL_TIMESTAMP_STRUCT>(rec);
        auto const& target = std::get<std::string>(rec);
        auto const& blob = std::get<std::vector<std::uint8_t>>(rec);
    }

cursor.fetch() will return std::tuple<int, SQL_TIMESTAMP_STRUCT, std::string, std::vector<std::uint8_t>> boost::iterator_range

Then let's define what we want to query from the table, that's where Boost.Fusion can be very handy:

	namespace data
	{
		struct Test
		{
			int id;
			SQL_TIMESTAMP_STRUCT ts;
			std::vector<char> target;
			std::string messagetype;
			std::vector<std::uint8_t> pb;
		};
	} // namespace data

	BOOST_FUSION_ADAPT_STRUCT(
		data::Test,
		id,
		ts,
		target,
		messagetype,
		pb
	)

In this case I defined whole table. Now l'ets query the table:

   auto cursor = auto odbcx::select<data::Test>{}.from("test")).exec(dbc);

And iterate through result:

   auto range = cursor.fetch();
   for (auto const& rec : range)
   {
	   //...
   }

query could be more complex than simple select:

    auto target = std::string{ "target x" };
    auto cursor1 = odbcx::select<data::Test>{}.from("test").where("target=?", target).exec(dbc);
    auto cursor2 = odbcx::select<data::Test>{}.from("test").as("alias").where("alias.target=?", target).exec(dbc);

nullable fields can be wrapped in std/boost::optional

About

C++ compile time odbc binding generator (supports BLOBs)

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published