throw if table is not supplied, quote field names, use spatial index to get extent, and default to built in alias for the primary key ('rowid') if key_field is not supplied

This commit is contained in:
Dane Springmeyer 2011-03-31 22:32:22 +00:00
parent e9e805690f
commit 23639271fe

View file

@ -61,7 +61,8 @@ sqlite_datasource::sqlite_datasource(parameters const& params, bool bind)
metadata_(*params_.get<std::string>("metadata","")), metadata_(*params_.get<std::string>("metadata","")),
geometry_table_(*params_.get<std::string>("geometry_table","")), geometry_table_(*params_.get<std::string>("geometry_table","")),
geometry_field_(*params_.get<std::string>("geometry_field","the_geom")), geometry_field_(*params_.get<std::string>("geometry_field","the_geom")),
key_field_(*params_.get<std::string>("key_field","OGC_FID")), // http://www.sqlite.org/lang_createtable.html#rowid
key_field_(*params_.get<std::string>("key_field","rowid")),
row_offset_(*params_.get<int>("row_offset",0)), row_offset_(*params_.get<int>("row_offset",0)),
row_limit_(*params_.get<int>("row_limit",0)), row_limit_(*params_.get<int>("row_limit",0)),
desc_(*params_.get<std::string>("type"), *params_.get<std::string>("encoding","utf-8")), desc_(*params_.get<std::string>("type"), *params_.get<std::string>("encoding","utf-8")),
@ -70,6 +71,8 @@ sqlite_datasource::sqlite_datasource(parameters const& params, bool bind)
boost::optional<std::string> file = params_.get<std::string>("file"); boost::optional<std::string> file = params_.get<std::string>("file");
if (!file) throw datasource_exception("Sqlite Plugin: missing <file> parameter"); if (!file) throw datasource_exception("Sqlite Plugin: missing <file> parameter");
if (table_.empty()) throw mapnik::datasource_exception("Sqlite Plugin: missing <table> parameter");
boost::optional<std::string> wkb = params_.get<std::string>("wkb_format"); boost::optional<std::string> wkb = params_.get<std::string>("wkb_format");
if (wkb) if (wkb)
{ {
@ -109,6 +112,23 @@ void sqlite_datasource::bind() const
geometry_table_ = mapnik::table_from_sql(table_); geometry_table_ = mapnik::table_from_sql(table_);
} }
if (use_spatial_index_)
{
std::ostringstream s;
s << "SELECT COUNT (*) FROM sqlite_master";
s << " WHERE LOWER(name) = LOWER('idx_" << geometry_table_ << "_" << geometry_field_ << "')";
boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
if (rs->is_valid () && rs->step_next())
{
use_spatial_index_ = rs->column_integer (0) == 1;
}
if (!use_spatial_index_)
std::clog << "Sqlite Plugin: spatial index not found for table '"
<< geometry_table_ << "'" << std::endl;
}
if (metadata_ != "" && !extent_initialized_) if (metadata_ != "" && !extent_initialized_)
{ {
std::ostringstream s; std::ostringstream s;
@ -126,22 +146,23 @@ void sqlite_datasource::bind() const
extent_initialized_ = true; extent_initialized_ = true;
} }
} }
if (use_spatial_index_) if (!extent_initialized_ && use_spatial_index_)
{ {
std::ostringstream s; std::ostringstream s;
s << "SELECT COUNT (*) FROM sqlite_master"; s << "SELECT xmin, ymin, xmax, ymax FROM "
s << " WHERE LOWER(name) = LOWER('idx_" << geometry_table_ << "_" << geometry_field_ << "')"; << "idx_" << geometry_table_ << "_" << geometry_field_;
boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str())); boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
if (rs->is_valid () && rs->step_next()) if (rs->is_valid () && rs->step_next())
{ {
use_spatial_index_ = rs->column_integer (0) == 1; double xmin = rs->column_double (0);
} double ymin = rs->column_double (1);
double xmax = rs->column_double (2);
double ymax = rs->column_double (3);
#ifdef MAPNIK_DEBUG extent_.init (xmin,ymin,xmax,ymax);
if (! use_spatial_index_) extent_initialized_ = true;
std::clog << "Sqlite Plugin: cannot use the spatial index " << std::endl; }
#endif
} }
{ {
@ -152,7 +173,7 @@ void sqlite_datasource::bind() const
*/ */
std::ostringstream s; std::ostringstream s;
s << "SELECT " << fields_ << " FROM (" << geometry_table_ << ") LIMIT 1"; s << "SELECT " << fields_ << " FROM (" << table_ << ") LIMIT 1";
boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str())); boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
if (rs->is_valid () && rs->step_next()) if (rs->is_valid () && rs->step_next())
@ -237,9 +258,9 @@ featureset_ptr sqlite_datasource::features(query const& q) const
std::set<std::string>::const_iterator end = props.end(); std::set<std::string>::const_iterator end = props.end();
while (pos != end) while (pos != end)
{ {
s << "," << *pos << ""; s << ",\"" << *pos << "\"";
++pos; ++pos;
} }
s << " FROM "; s << " FROM ";
@ -249,11 +270,9 @@ featureset_ptr sqlite_datasource::features(query const& q) const
{ {
std::ostringstream spatial_sql; std::ostringstream spatial_sql;
spatial_sql << std::setprecision(16); spatial_sql << std::setprecision(16);
// TODO - rowid must be explicitly included in subselects spatial_sql << " WHERE " << key_field_ << " IN (SELECT pkid FROM idx_" << geometry_table_ << "_" << geometry_field_;
// should we use primary key here instead? spatial_sql << " WHERE xmax>=" << e.minx() << " AND xmin<=" << e.maxx() ;
spatial_sql << " WHERE rowid IN (SELECT pkid FROM idx_" << geometry_table_ << "_" << geometry_field_; spatial_sql << " AND ymax>=" << e.miny() << " AND ymin<=" << e.maxy() << ")";
spatial_sql << " WHERE xmax>=" << e.minx() << " AND xmin<=" << e.maxx() ;
spatial_sql << " AND ymax>=" << e.miny() << " AND ymin<=" << e.maxy() << ")";
if (boost::algorithm::ifind_first(query, "WHERE")) if (boost::algorithm::ifind_first(query, "WHERE"))
{ {
boost::algorithm::ireplace_first(query, "WHERE", spatial_sql.str() + " AND "); boost::algorithm::ireplace_first(query, "WHERE", spatial_sql.str() + " AND ");