add support for 'intersects' token in sqlite plugin - closes #809

This commit is contained in:
Dane Springmeyer 2011-12-16 10:05:54 -08:00
parent ea1e5cabb7
commit 04dd46315e
4 changed files with 58 additions and 11 deletions

View file

@ -14,6 +14,8 @@ For a complete change history, see the SVN log.
Mapnik 2.1.0
------------
- SQLite - Added support for !intersects! token in sql subselects (#809) allow custom positioning of rtree spatial filter.
- New CSV plugin - reads tabular files - autodetecting geo columns, newlines, and delimiters. Uses in-memory featureset for fast rendering and is not designed for large files (#902)
- Fixed bug in shield line placement when dx/dy are used to shift the label relative to the placement point (Matt Amos) (#908)

View file

@ -62,6 +62,7 @@ sqlite_datasource::sqlite_datasource(parameters const& params, bool bind)
key_field_(*params_.get<std::string>("key_field", "")),
row_offset_(*params_.get<int>("row_offset", 0)),
row_limit_(*params_.get<int>("row_limit", 0)),
intersects_token_("!intersects!"),
desc_(*params_.get<std::string>("type"), *params_.get<std::string>("encoding", "utf-8")),
format_(mapnik::wkbAuto)
{
@ -185,7 +186,8 @@ void sqlite_datasource::bind() const
if (using_subquery_)
{
std::ostringstream s;
s << "SELECT " << fields_ << " FROM (" << table_ << ") LIMIT 1";
std::string query = populate_tokens(table_);
s << "SELECT " << fields_ << " FROM (" << query << ") LIMIT 1";
found_types_via_subquery = sqlite_utils::detect_types_from_subquery(s.str(),geometry_field_,desc_,dataset_);
}
@ -306,6 +308,7 @@ void sqlite_datasource::bind() const
{
// TODO - clean this up - reducing arguments
std::string query = populate_tokens(table_);
if (!sqlite_utils::detect_extent(dataset_,
has_spatial_index_,
extent_,
@ -314,7 +317,7 @@ void sqlite_datasource::bind() const
geometry_field_,
geometry_table_,
key_field_,
table_))
query))
{
std::ostringstream s;
s << "Sqlite Plugin: extent could not be determined for table '"
@ -328,6 +331,17 @@ void sqlite_datasource::bind() const
is_bound_ = true;
}
std::string sqlite_datasource::populate_tokens(const std::string& sql) const
{
std::string populated_sql = sql;
if (boost::algorithm::ifind_first(populated_sql, intersects_token_))
{
// replace with dummy comparison that is true
boost::algorithm::ireplace_first(populated_sql, intersects_token_, "1=1");
}
return populated_sql;
}
sqlite_datasource::~sqlite_datasource()
{
}
@ -470,7 +484,16 @@ featureset_ptr sqlite_datasource::features(query const& q) const
if (! key_field_.empty() && has_spatial_index_)
{
// TODO - debug warn if fails
sqlite_utils::apply_spatial_filter(query,e,table_,key_field_,index_table_,geometry_table_);
sqlite_utils::apply_spatial_filter(query,
e,
table_,
key_field_,
index_table_,
geometry_table_,
intersects_token_); }
else
{
query = populate_tokens(table_);
}
s << query ;
@ -534,7 +557,17 @@ featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt) const
if (! key_field_.empty() && has_spatial_index_)
{
// TODO - debug warn if fails
sqlite_utils::apply_spatial_filter(query,e,table_,key_field_,index_table_,geometry_table_);
sqlite_utils::apply_spatial_filter(query,
e,
table_,
key_field_,
index_table_,
geometry_table_,
intersects_token_);
}
else
{
query = populate_tokens(table_);
}
s << query ;

View file

@ -70,6 +70,8 @@ private:
mutable std::string key_field_;
mutable int row_offset_;
mutable int row_limit_;
// TODO - also add to postgis.input
const std::string intersects_token_;
mutable mapnik::layer_descriptor desc_;
mutable mapnik::wkbFormat format_;
mutable bool use_spatial_index_;
@ -80,6 +82,7 @@ private:
// Fill init_statements with any statements
// needed to attach auxillary databases
void parse_attachdb(std::string const& attachdb) const;
std::string populate_tokens(const std::string& sql) const;
};
#endif // MAPNIK_SQLITE_DATASOURCE_HPP

View file

@ -113,23 +113,32 @@ public:
std::string const& table,
std::string const& key_field,
std::string const& index_table,
std::string const& geometry_table)
std::string const& geometry_table,
std::string const& intersects_token)
{
std::ostringstream spatial_sql;
spatial_sql << std::setprecision(16);
spatial_sql << " WHERE " << key_field << " IN (SELECT pkid FROM " << index_table;
spatial_sql << key_field << " IN (SELECT pkid FROM " << index_table;
spatial_sql << " WHERE xmax>=" << e.minx() << " AND xmin<=" << e.maxx() ;
spatial_sql << " AND ymax>=" << e.miny() << " AND ymin<=" << e.maxy() << ")";
// substitute first WHERE found if not using JOIN (because we can't know the WHERE is on the right table)
if (boost::algorithm::ifind_first(query, "WHERE") && !boost::algorithm::ifind_first(query, "JOIN"))
if (boost::algorithm::ifind_first(query, intersects_token))
{
boost::algorithm::ireplace_first(query, "WHERE", spatial_sql.str() + " AND ");
boost::algorithm::ireplace_all(query, intersects_token, spatial_sql.str());
return true;
}
// substitute first WHERE found if not using JOIN
// (because we can't know the WHERE is on the right table)
else if (boost::algorithm::ifind_first(query, "WHERE")
&& !boost::algorithm::ifind_first(query, "JOIN"))
{
std::string replace(" WHERE " + spatial_sql.str() + " AND ");
boost::algorithm::ireplace_first(query, "WHERE", replace);
return true;
}
// fallback to appending spatial filter at end of query
else if (boost::algorithm::ifind_first(query, geometry_table))
{
boost::algorithm::ireplace_first(query, table, table + " " + spatial_sql.str());
query = table + " WHERE " + spatial_sql.str();
return true;
}
return false;