From c093d2ad4dfe34ad24fbbc05b589072e0587e447 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 13 Jun 2011 21:58:11 +0000 Subject: [PATCH] add ability to supply a key_field (attribute name) to be used for feature ids + fix potential table alias quoting failure --- plugins/input/postgis/postgis_datasource.cpp | 34 ++++++++-------- plugins/input/postgis/postgis_datasource.hpp | 1 + plugins/input/postgis/postgis_featureset.cpp | 42 +++++++++++++++++--- plugins/input/postgis/postgis_featureset.hpp | 2 + 4 files changed, 57 insertions(+), 22 deletions(-) diff --git a/plugins/input/postgis/postgis_datasource.cpp b/plugins/input/postgis/postgis_datasource.cpp index bc3e8cdb4..062dcd922 100644 --- a/plugins/input/postgis/postgis_datasource.cpp +++ b/plugins/input/postgis/postgis_datasource.cpp @@ -69,6 +69,7 @@ postgis_datasource::postgis_datasource(parameters const& params, bool bind) schema_(""), geometry_table_(*params_.get("geometry_table","")), geometry_field_(*params_.get("geometry_field","")), + key_field_(*params_.get("key_field","")), cursor_fetch_size_(*params_.get("cursor_size",0)), row_limit_(*params_.get("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 postgis_datasource::get_resultset(boost::shared_ptr 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 const& props=q.property_names(); std::set::const_iterator pos=props.begin(); std::set::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 rs = get_resultset(conn, s.str()); - return boost::make_shared(rs,desc_.get_encoding(),multiple_geometries_,props.size()); + return boost::make_shared(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::const_iterator itr = desc_.get_descriptors().begin(); std::vector::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 rs = get_resultset(conn, s.str()); - return boost::make_shared(rs,desc_.get_encoding(),multiple_geometries_, size); + return boost::make_shared(rs,desc_.get_encoding(),multiple_geometries_, !key_field_.empty(), size); } } return featureset_ptr(); @@ -597,11 +597,11 @@ box2d 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 { diff --git a/plugins/input/postgis/postgis_datasource.hpp b/plugins/input/postgis/postgis_datasource.hpp index e7b290112..0203afe56 100644 --- a/plugins/input/postgis/postgis_datasource.hpp +++ b/plugins/input/postgis/postgis_datasource.hpp @@ -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_; diff --git a/plugins/input/postgis/postgis_featureset.cpp b/plugins/input/postgis/postgis_featureset.cpp index 272da61b6..de86ab9ae 100644 --- a/plugins/input/postgis/postgis_featureset.cpp +++ b/plugins/input/postgis/postgis_featureset.cpp @@ -52,33 +52,65 @@ using mapnik::feature_factory; postgis_featureset::postgis_featureset(boost::shared_ptr 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;posgetFieldName(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 diff --git a/plugins/input/postgis/postgis_featureset.hpp b/plugins/input/postgis/postgis_featureset.hpp index f436dcc56..d7ca61ec5 100644 --- a/plugins/input/postgis/postgis_featureset.hpp +++ b/plugins/input/postgis/postgis_featureset.hpp @@ -49,10 +49,12 @@ private: boost::scoped_ptr tr_; int totalGeomSize_; int feature_id_; + bool key_field_; public: postgis_featureset(boost::shared_ptr const& rs, std::string const& encoding, bool multiple_geometries, + bool key_field, unsigned num_attrs); mapnik::feature_ptr next(); ~postgis_featureset();