diff options
| -rw-r--r-- | libpqpp/pq-bulkselectcommand.cpp | 53 | ||||
| -rw-r--r-- | libpqpp/pq-bulkselectcommand.h | 29 | ||||
| -rw-r--r-- | libpqpp/pq-connection.cpp | 5 | ||||
| -rw-r--r-- | libpqpp/unittests/testpq.cpp | 31 | 
4 files changed, 118 insertions, 0 deletions
diff --git a/libpqpp/pq-bulkselectcommand.cpp b/libpqpp/pq-bulkselectcommand.cpp new file mode 100644 index 0000000..27674f5 --- /dev/null +++ b/libpqpp/pq-bulkselectcommand.cpp @@ -0,0 +1,53 @@ +#include "pq-bulkselectcommand.h" +#include "pq-connection.h" +#include "pq-column.h" +#include "pq-error.h" + +PQ::BulkSelectCommand::BulkSelectCommand(Connection * conn, const std::string & sql, unsigned int no) : +	DB::Command(sql), +	DB::SelectCommand(sql), +	PQ::Command(conn, sql, no), +	executed(false) +{ +	prepareSql(preparedSql, sql); +} + +PQ::BulkSelectCommand::~BulkSelectCommand() +{ +	if (execRes) { +		PQclear(execRes); +	} +} + +void +PQ::BulkSelectCommand::execute() +{ +	if (!executed) { +		execRes = c->checkResult( +				PQexecParams(c->conn, preparedSql.c_str(), values.size(), NULL, &values.front(), &lengths.front(), NULL, 0), +				PGRES_TUPLES_OK); +		nTuples = PQntuples(execRes); +		tuple = -1; +		unsigned int nFields = PQnfields(execRes); +		for (unsigned int f = 0; f < nFields; f += 1) { +			insertColumn(DB::ColumnPtr(new Column(this, f))); +		} +		executed = true; +	} +} + +bool +PQ::BulkSelectCommand::fetch() +{ +	execute(); +	if (++tuple < nTuples) { +		return true; +	} +	else { +		PQclear(execRes); +		execRes = NULL; +		executed = false; +		return false; +	} +} + diff --git a/libpqpp/pq-bulkselectcommand.h b/libpqpp/pq-bulkselectcommand.h new file mode 100644 index 0000000..aeda42d --- /dev/null +++ b/libpqpp/pq-bulkselectcommand.h @@ -0,0 +1,29 @@ +#ifndef PQ_BULKSELECTCOMMAND_H +#define PQ_BULKSELECTCOMMAND_H + +#include <selectcommand.h> +#include "pq-selectbase.h" +#include "pq-command.h" +#include <vector> +#include <map> + +namespace PQ { +	class Connection; +	class Column; +	class BulkSelectCommand : public DB::SelectCommand, public SelectBase, public Command { +		public: +			BulkSelectCommand(Connection *, const std::string & sql, unsigned int no); +			virtual ~BulkSelectCommand(); + +			bool fetch() override; +			void execute() override; + +		private: +			mutable bool executed; +			std::string preparedSql; +	}; +} + +#endif + + diff --git a/libpqpp/pq-connection.cpp b/libpqpp/pq-connection.cpp index 49867a4..078272e 100644 --- a/libpqpp/pq-connection.cpp +++ b/libpqpp/pq-connection.cpp @@ -1,5 +1,6 @@  #include "pq-connection.h"  #include "pq-error.h" +#include "pq-bulkselectcommand.h"  #include "pq-cursorselectcommand.h"  #include "pq-modifycommand.h"  #include <unistd.h> @@ -97,6 +98,10 @@ PQ::Connection::ping() const  DB::SelectCommand *  PQ::Connection::newSelectCommand(const std::string & sql)  { +	// Yes, this is a hack +	if (sql.find("libdbpp:no-cursor") != (std::string::size_type)-1) { +		return new BulkSelectCommand(this, sql, pstmntNo++); +	}  	return new CursorSelectCommand(this, sql, pstmntNo++);  } diff --git a/libpqpp/unittests/testpq.cpp b/libpqpp/unittests/testpq.cpp index 64d60d9..f5cb760 100644 --- a/libpqpp/unittests/testpq.cpp +++ b/libpqpp/unittests/testpq.cpp @@ -287,6 +287,37 @@ BOOST_AUTO_TEST_CASE( statementReuse )  	delete ro;  } +BOOST_AUTO_TEST_CASE( bulkSelect ) +{ +	auto ro = DB::MockDatabase::openConnectionTo("pqmock"); +	auto sel = ro->newSelectCommand("SELECT * FROM test WHERE id > ? --libdbpp:no-cursor"); +	sel->bindParamI(0, 1); +	int totalInt = 0, count = 0; +	sel->forEachRow<int64_t>([&totalInt, &count](auto i) { +			totalInt += i; +			count += 1; +		}); +	delete sel; +	BOOST_REQUIRE_EQUAL(20, totalInt); +	BOOST_REQUIRE_EQUAL(8, count); +	delete ro; +} + +BOOST_AUTO_TEST_CASE( insertReturning ) +{ +	auto ro = DB::MockDatabase::openConnectionTo("pqmock"); +	auto sel = ro->newSelectCommand("INSERT INTO test(id, fl) VALUES(1, 3) RETURNING id + fl --libdbpp:no-cursor"); +	int totalInt = 0, count = 0; +	sel->forEachRow<int64_t>([&totalInt, &count](auto i) { +			totalInt += i; +			count += 1; +		}); +	delete sel; +	BOOST_REQUIRE_EQUAL(4, totalInt); +	BOOST_REQUIRE_EQUAL(1, count); +	delete ro; +} +  BOOST_AUTO_TEST_CASE( closeOnError )  {  	auto ro = DB::ConnectionPtr(DB::MockDatabase::openConnectionTo("pqmock"));  | 
