Commit 4c998db2 authored by Mateusz Loskot's avatar Mateusz Loskot

Do not deallocate non-existing prepared statement

This is refinement of fix submitted in #107 and fixes #116
parent 05e64112
......@@ -10,6 +10,7 @@
#include "error.h"
#include <soci-platform.h>
#include <libpq/libpq-fs.h> // libpq
#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
......@@ -169,6 +170,8 @@ void postgresql_statement_backend::prepare(std::string const & query,
if (stType == st_repeatable_query)
{
assert(statementName_.empty());
// Holding the name temporarily in this var because
// if it fails to prepare it we can't DEALLOCATE it.
std::string statementName = session_.get_next_statement_name();
......@@ -179,8 +182,6 @@ void postgresql_statement_backend::prepare(std::string const & query,
{
throw soci_error("Cannot prepare statement.");
}
// Now it's safe to save this info.
statementName_ = statementName;
ExecStatusType status = PQresultStatus(result);
if (status != PGRES_COMMAND_OK)
......@@ -189,6 +190,9 @@ void postgresql_statement_backend::prepare(std::string const & query,
throw_postgresql_soci_error(result);
}
PQclear(result);
// Now it's safe to save this info.
statementName_ = statementName;
}
stType_ = stType;
......
......@@ -658,6 +658,43 @@ void test_json()
}
}
struct table_creator_text : public table_creator_base
{
table_creator_text(session& sql) : table_creator_base(sql)
{
sql << "drop table if exists soci_test;";
sql << "create table soci_test(name varchar(20))";
}
};
// Test deallocate_prepared_statement called for non-existing statement
// which creation failed due to invalid SQL syntax.
// https://github.com/SOCI/soci/issues/116
void test_statement_prepare_failure()
{
{
session sql(backEnd, connectString);
table_creator_text tableCreator(sql);
try
{
// types mismatch should lead to PQprepare failure
statement get_trades =
(sql.prepare
<< "select * from soci_test where name=9999");
assert(false);
}
catch(soci_error const& e)
{
std::string const msg(e.what());
// poor-man heuristics
assert(msg.find("prepared statement") == std::string::npos);
assert(msg.find("operator does not exist") != std::string::npos);
}
}
std::cout << "test_statement_prepare_failure passed" << std::endl;
}
//
// Support for soci Common Tests
//
......@@ -786,6 +823,7 @@ int main(int argc, char** argv)
test12();
test_bytea();
test_json();
test_statement_prepare_failure();
std::cout << "\nOK, all tests passed.\n\n";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment