Skip to content

Instantly share code, notes, and snippets.

@rcoup
Created May 7, 2013 20:21
Show Gist options
  • Save rcoup/5535776 to your computer and use it in GitHub Desktop.
Save rcoup/5535776 to your computer and use it in GitHub Desktop.
Test case for Mapnik #1823
/*
Test case for Mapnik #1823
*/
#include <postgis/postgis_datasource.hpp>
#include <mapnik/params.hpp>
#include <iostream>
#include <mapnik/map.hpp>
using namespace mapnik;
using namespace std;
using namespace boost;
/* table_(*params.get<std::string>("table", "")),
schema_(""),
geometry_table_(*params.get<std::string>("geometry_table", "")),
geometry_field_(*params.get<std::string>("geometry_field", "")),
key_field_(*params.get<std::string>("key_field", "")),
cursor_fetch_size_(*params.get<mapnik::value_integer>("cursor_size", 0)),
row_limit_(*params.get<int>("row_limit", 0)),
type_(datasource::Vector),
srid_(*params.get<int>("srid", 0)),
extent_initialized_(false),
simplify_geometries_(false),
desc_(*params.get<std::string>("type"), "utf-8"),
creator_(params.get<std::string>("host"),
params.get<std::string>("port"),
params.get<std::string>("dbname"),
params.get<std::string>("user"),
params.get<std::string>("password"),
params.get<std::string>("connect_timeout", "4")),
*/
void get_and_close_connection()
{
parameters p;
p["table"] = "pgbench_accounts";
p["host"] = "";
p["type"] = "utf-8";
p["geometry_field"] = "the_geom";
ConnectionCreator<Connection> creator_(p.get<std::string>("host"),
p.get<std::string>("port"),
p.get<std::string>("dbname"),
p.get<std::string>("user"),
p.get<std::string>("password"),
p.get<std::string>("connect_timeout", "4"));
//ConnectionManager::instance().registerPool(creator_, 1,1);
boost::shared_ptr< Pool<Connection,ConnectionCreator> > pool = ConnectionManager::instance().getPool(creator_.id());
if (pool)
{
shared_ptr<Connection> conn = pool->borrowObject();
if (!conn)
{
cout << "Failed to borrow connection" << endl;
return;
}
if (conn->isOK())
{
cout << "Connection " << conn->status() << endl;
conn->close();
cout << "Connection " << conn->status() << endl;
return;
}
cout << "Connection not OK" << endl;
}
}
featureset_ptr do_a_query(std::string table_hack)
{
std::cout << table_hack << std::endl;
parameters p;
p["table"] = table_hack;
p["host"] = "";
p["type"] = "utf-8";
p["geometry_field"] = "the_geom";
p["srid"] = "0";
p["cursor_size"] = 10;
p["max_size"] = 2;
postgis_datasource ds(p);
if (ds.name())
cout << ds.name() << endl;
box2d<double> b(0,0,1,1);
query q(b);
q.add_property_name("the_id");
featureset_ptr fs = ds.features(q);
return fs;
}
int main(void) {
//featureset_ptr fs = do_a_query("(select 2 as the_id, the_geom from pgbench_accounts) as pgbench_accounts");
//std::cout << table_hack << std::endl;
parameters p1;
p1["table"] = "(select 1 as the_id, the_geom from pgbench_accounts) as pgbench_accounts";
p1["host"] = "";
p1["type"] = "utf-8";
p1["geometry_field"] = "the_geom";
p1["srid"] = 0;
p1["cursor_size"] = 10;
p1["max_size"] = 3;
postgis_datasource ds1(p1);
if (ds1.name())
cout << ds1.name() <<endl;
box2d<double> b1(0,0,1,1);
query q1(b1);
q1.add_property_name("the_id");
featureset_ptr fs = ds1.features(q1);
cout << "grab a feature" << endl;
feature_ptr f = fs->next();
cout << "F " << f->get("the_id") << " " << (f?f->size():-1) << endl;
f = fs->next();
cout << "F " << f->get("the_id") << " " << (f?f->size():-1) << endl;
p1["table"] = "(select 2 as the_id, the_geom from pgbench_accounts) as pgbench_accounts";
postgis_datasource ds2(p1);
if (ds2.name())
cout << ds2.name() <<endl;
box2d<double> b2(0,0,1,1);
query q2(b2);
q2.add_property_name("the_id");
featureset_ptr fs2 = ds2.features(q2);
//featureset_ptr fs2 = do_a_query("(select 3 as the_id, the_geom from pgbench_accounts) as pgbench_accounts");
//fs2->next();
cout << "mess with the pool" << endl;
get_and_close_connection();
get_and_close_connection();
get_and_close_connection();
get_and_close_connection();
cout << "mess with the pool done" << endl;
cout << "grab another feature" << endl;
for (int ii = 0; ii < 12 && (f = fs->next()); ++ii)
cout << "F " << f->get("the_id") << " " << (f?f->size():-1) << endl;
return 0;
}
@thjc
Copy link

thjc commented May 8, 2013

The basic principle of the test is as follows:

  1. Precondition is a db with some geo data in it, and at least 11 rows of data (i.e. more than the cursor size)
  2. We set up a data source that connect to the DB
  3. Grab the first batch of data from the datasource, this sets up the server side cursor
  4. at this stage the connection is returned to the pool, despite the cursor still having a reference to it.
  5. we directly grab a connection from the pool (which will give us the same connection in use by the cursor)
  6. any manipulation of the connection is now potentially unsafe with respect to the cursor...in this test case we simply close it.
  7. access beyound the cursor size then triggers a batch read from the server which fails as the connection that the dataset still has an implicit connection to is invalid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment