add ability to supply a key_field (attribute name) to be used for feature ids + fix potential table alias quoting failure

This commit is contained in:
Dane Springmeyer 2011-06-13 21:58:11 +00:00
parent 4e229ac516
commit c093d2ad4d
4 changed files with 57 additions and 22 deletions

View File

@ -69,6 +69,7 @@ postgis_datasource::postgis_datasource(parameters const& params, bool bind)
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<int>("cursor_size",0)),
row_limit_(*params_.get<int>("row_limit",0)),
type_(datasource::Vector),
@ -150,13 +151,13 @@ void postgis_datasource::bind() const
{
std::ostringstream s;
s << "SELECT f_geometry_column, srid FROM ";
s << GEOMETRY_COLUMNS <<" WHERE f_table_name='" << unquote(geometry_table_) <<"'";
s << GEOMETRY_COLUMNS <<" WHERE f_table_name='" << mapnik::unquote_sql(geometry_table_) <<"'";
if (schema_.length() > 0)
s << " AND f_table_schema='" << unquote(schema_) << "'";
s << " AND f_table_schema='" << mapnik::unquote_sql(schema_) << "'";
if (geometry_field_.length() > 0)
s << " AND f_geometry_column='" << unquote(geometry_field_) << "'";
s << " AND f_geometry_column='" << mapnik::unquote_sql(geometry_field_) << "'";
/*
if (show_queries_)
@ -371,13 +372,6 @@ std::string postgis_datasource::populate_tokens(const std::string& sql, double c
}
std::string postgis_datasource::unquote(const std::string& sql)
{
std::string table_name = boost::algorithm::to_lower_copy(sql);
boost::algorithm::trim_if(table_name,boost::algorithm::is_any_of("\""));
return table_name;
}
boost::shared_ptr<IResultSet> postgis_datasource::get_resultset(boost::shared_ptr<Connection> const &conn, const std::string &sql) const
{
if (cursor_fetch_size_ > 0)
@ -463,12 +457,15 @@ featureset_ptr postgis_datasource::features(const query& q) const
else
s << "AsBinary(\"" << geometryColumn_ << "\") AS geom";
if (!key_field_.empty())
mapnik::quote_attr(s,key_field_);
std::set<std::string> const& props=q.property_names();
std::set<std::string>::const_iterator pos=props.begin();
std::set<std::string>::const_iterator end=props.end();
while (pos != end)
{
s << ",\"" << *pos << "\"";
mapnik::quote_attr(s,*pos);
++pos;
}
@ -481,7 +478,7 @@ featureset_ptr postgis_datasource::features(const query& q) const
}
boost::shared_ptr<IResultSet> rs = get_resultset(conn, s.str());
return boost::make_shared<postgis_featureset>(rs,desc_.get_encoding(),multiple_geometries_,props.size());
return boost::make_shared<postgis_featureset>(rs,desc_.get_encoding(),multiple_geometries_,!key_field_.empty(),props.size());
}
else
{
@ -533,12 +530,15 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt) const
else
s << "AsBinary(\"" << geometryColumn_ << "\") AS geom";
if (!key_field_.empty())
mapnik::quote_attr(s,key_field_);
std::vector<attribute_descriptor>::const_iterator itr = desc_.get_descriptors().begin();
std::vector<attribute_descriptor>::const_iterator end = desc_.get_descriptors().end();
unsigned size=0;
while (itr != end)
{
s << ",\"" << itr->get_name() << "\"";
mapnik::quote_attr(s,itr->get_name());
++itr;
++size;
}
@ -553,7 +553,7 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt) const
}
boost::shared_ptr<IResultSet> rs = get_resultset(conn, s.str());
return boost::make_shared<postgis_featureset>(rs,desc_.get_encoding(),multiple_geometries_, size);
return boost::make_shared<postgis_featureset>(rs,desc_.get_encoding(),multiple_geometries_, !key_field_.empty(), size);
}
}
return featureset_ptr();
@ -597,11 +597,11 @@ box2d<double> postgis_datasource::envelope() const
if (schema_.length() > 0)
{
s << unquote(schema_) << "','";
s << mapnik::unquote_sql(schema_) << "','";
}
s << unquote(geometry_table_) << "','"
<< unquote(geometryColumn_) << "') as ext) as tmp";
s << mapnik::unquote_sql(geometry_table_) << "','"
<< mapnik::unquote_sql(geometryColumn_) << "') as ext) as tmp";
}
else
{

View File

@ -59,6 +59,7 @@ class postgis_datasource : public datasource
mutable std::string schema_;
mutable std::string geometry_table_;
const std::string geometry_field_;
const std::string key_field_;
const int cursor_fetch_size_;
const int row_limit_;
mutable std::string geometryColumn_;

View File

@ -52,33 +52,65 @@ using mapnik::feature_factory;
postgis_featureset::postgis_featureset(boost::shared_ptr<IResultSet> const& rs,
std::string const& encoding,
bool multiple_geometries,
bool key_field=false,
unsigned num_attrs=0)
: rs_(rs),
multiple_geometries_(multiple_geometries),
num_attrs_(num_attrs),
tr_(new transcoder(encoding)),
totalGeomSize_(0),
feature_id_(1) {}
feature_id_(1),
key_field_(key_field) {}
feature_ptr postgis_featureset::next()
{
if (rs_->next())
{
feature_ptr feature(feature_factory::create(feature_id_));
++feature_id_;
// new feature
feature_ptr feature;
unsigned pos = 1;
if (key_field_) {
// create feature with user driven id from attribute
int oid = rs_->getTypeOID(pos);
if (oid == 20 || oid == 21 || oid == 23) {
const char* buf = rs_->getValue(pos);
int val;
if (oid == 20)
val = int8net(buf);
else if (oid == 21)
val = int4net(buf);
else if (oid == 23)
val = int2net(buf);
feature = feature_factory::create(val);
} else {
std::ostringstream s;
s << "invalid type for key_field '" << oid << "'";
std::string name = rs_->getFieldName(pos);
s << " for " << name;
throw mapnik::datasource_exception( s.str() );
}
++pos;
} else {
// fallback to auto-incrementing id
feature = feature_factory::create(feature_id_);
++feature_id_;
}
// parse geometry
int size = rs_->getFieldLength(0);
const char *data = rs_->getValue(0);
geometry_utils::from_wkb(*feature,data,size,multiple_geometries_);
totalGeomSize_+=size;
for (unsigned pos=1;pos<num_attrs_+1;++pos)
for ( ;pos<num_attrs_+1;++pos)
{
std::string name = rs_->getFieldName(pos);
if (!rs_->isNull(pos))
{
const char* buf=rs_->getValue(pos);
const char* buf = rs_->getValue(pos);
int oid = rs_->getTypeOID(pos);
if (oid==16) //bool

View File

@ -49,10 +49,12 @@ private:
boost::scoped_ptr<mapnik::transcoder> tr_;
int totalGeomSize_;
int feature_id_;
bool key_field_;
public:
postgis_featureset(boost::shared_ptr<IResultSet> const& rs,
std::string const& encoding,
bool multiple_geometries,
bool key_field,
unsigned num_attrs);
mapnik::feature_ptr next();
~postgis_featureset();