+ improvements to the wkb converter
+ improved sqlite index usage
+ added more parameters to sqlite datasource
This commit is contained in:
Lucio Asnaghi 2009-02-10 19:09:16 +00:00
parent 1f5edf45f0
commit 2c81706eb5
7 changed files with 101 additions and 149 deletions

View File

@ -30,6 +30,13 @@
#include <mapnik/feature.hpp>
namespace mapnik
{
enum wkbFormat
{
wkbGeneric=1,
wkbAutodetect=2,
wkbSQLite=3
};
class MAPNIK_DECL geometry_utils
{
public:
@ -38,7 +45,7 @@ namespace mapnik
const char* wkb,
unsigned size,
bool multiple_geometries = false,
bool sqlite_format = false);
wkbFormat format = wkbGeneric);
private:
geometry_utils();
geometry_utils(geometry_utils const&);

View File

@ -58,14 +58,16 @@ sqlite_datasource::sqlite_datasource(parameters const& params)
extent_initialized_(false),
type_(datasource::Vector),
table_(*params.get<std::string>("table","")),
metadata_(*params.get<std::string>("metadata","")),
geometry_field_(*params.get<std::string>("geometry_field","geom")),
geocatalog_(*params.get<std::string>("geometry_catalog","geocatalog")),
key_field_(*params.get<std::string>("key_field","PK_UID")),
desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding","utf-8"))
{
boost::optional<std::string> file = params.get<std::string>("file");
if (!file) throw datasource_exception("missing <file> paramater");
multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false);
use_spatial_index_ = *params_.get<mapnik::boolean>("use_spatial_index",true);
dataset_ = new sqlite_connection (*file);
@ -104,36 +106,53 @@ sqlite_datasource::sqlite_datasource(parameters const& params)
}
}
#if 0
if (metadata_ != "" && ! extent_initialized_)
{
std::ostringstream s;
s << "select minx, miny, maxx, maxy from " << geocatalog_;
s << " where lower(table_name) = lower('" << table_ << "')";
boost::shared_ptr<sqlite_resultset> rs = dataset_->execute_query (s.str());
s << "select xmin, ymin, xmax, ymax from " << metadata_;
s << " where lower(f_table_name) = lower('" << table_ << "')";
boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
if (rs->is_valid () && rs->step_next())
{
double minx = rs->column_double (0);
double miny = rs->column_double (1);
double maxx = rs->column_double (2);
double maxy = rs->column_double (3);
double xmin = rs->column_double (0);
double ymin = rs->column_double (1);
double xmax = rs->column_double (2);
double ymax = rs->column_double (3);
extent_.init (minx,miny,maxx,maxy);
extent_.init (xmin,ymin,xmax,ymax);
extent_initialized_ = true;
}
}
#endif
if (use_spatial_index_)
{
std::ostringstream s;
s << "select * from " << table_ << " limit 1";
boost::shared_ptr<sqlite_resultset> rs = dataset_->execute_query (s.str());
s << "select count (*) sqlite_master";
s << " where name = 'idx_" << table_ << "_" << geometry_field_ << "'";
boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
if (rs->is_valid () && rs->step_next())
{
if (rs->column_integer (0) == 0)
{
#ifdef MAPNIK_DEBUG
clog << "cannot use the spatial index " << endl;
#endif
use_spatial_index_ = false;
}
}
}
{
/*
XXX - This is problematic, if we don't have at least a row,
we cannot determine the right columns types and names
as all column_type are SQLITE_NULL
*/
std::ostringstream s;
s << "select * from " << table_ << " limit 1";
boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
if (rs->is_valid () && rs->step_next())
{
/*
XXX - This is problematic, if we don't have at least a row,
we cannot determine the right columns types and names
as all column_type are SQLITE_NULL
*/
for (int i = 0; i < rs->column_count (); ++i)
{
const int type_oid = rs->column_type (i);
@ -141,23 +160,14 @@ sqlite_datasource::sqlite_datasource(parameters const& params)
switch (type_oid)
{
case SQLITE_INTEGER:
#ifdef MAPNIK_DEBUG
clog << fld_name << " integer" << endl;
#endif
desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer));
break;
case SQLITE_FLOAT:
#ifdef MAPNIK_DEBUG
clog << fld_name << " double" << endl;
#endif
desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double));
break;
case SQLITE_TEXT:
#ifdef MAPNIK_DEBUG
clog << fld_name << " text" << endl;
#endif
desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
break;
@ -207,17 +217,10 @@ featureset_ptr sqlite_datasource::features(query const& q) const
{
if (dataset_)
{
mapnik::Envelope<double> const& e = q.get_bbox();
#if 0
layer_->SetSpatialFilterRect (query_extent.minx(),
query_extent.miny(),
query_extent.maxx(),
query_extent.maxy());
#endif
std::ostringstream s;
s << "select " << geometry_field_ << ",PK_UID";
s << "select " << geometry_field_ << "," << 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();
@ -226,13 +229,21 @@ featureset_ptr sqlite_datasource::features(query const& q) const
s << "," << *pos << "";
++pos;
}
s << " from " << table_ << "," << "idx_" << table_ << "_" << geometry_field_;
s << " where " << table_<<".PK_UID="<< "idx_" << table_ << "_" << geometry_field_ << ".pkid" ;
s << " and xmax>=" << e.minx() << " and xmin<=" << e.maxx() ;
s << " and ymax>=" << e.miny() << " and ymin<=" << e.maxy() ;
std::cerr << s.str() << "\n";
boost::shared_ptr<sqlite_resultset> rs = dataset_->execute_query (s.str());
s << " from " << table_;
if (use_spatial_index_)
{
s << std::setprecision(16);
s << " where rowid in (select pkid from idx_" << table_ << "_" << geometry_field_;
s << " where xmax>=" << e.minx() << " and xmin<=" << e.maxx() ;
s << " and ymax>=" << e.miny() << " and ymin<=" << e.maxy() << ")";
}
#ifdef MAPNIK_DEBUG
std::cerr << "executing sql: " << s.str() << "\n";
#endif
boost::shared_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
return featureset_ptr (new sqlite_featureset(rs, desc_.get_encoding(), multiple_geometries_));
}

View File

@ -53,9 +53,10 @@ class sqlite_datasource : public mapnik::datasource
mutable bool extent_initialized_;
int type_;
sqlite_connection* dataset_;
std::string table_, geometry_field_, geocatalog_;
std::string table_, metadata_, geometry_field_, key_field_;
mapnik::layer_descriptor desc_;
bool multiple_geometries_;
bool use_spatial_index_;
};

View File

@ -53,8 +53,7 @@ sqlite_featureset::sqlite_featureset(boost::shared_ptr<sqlite_resultset> rs,
bool multiple_geometries)
: rs_(rs),
tr_(new transcoder(encoding)),
multiple_geometries_(multiple_geometries),
count_(0)
multiple_geometries_(multiple_geometries)
{
}
@ -64,17 +63,18 @@ feature_ptr sqlite_featureset::next()
{
if (rs_->is_valid () && rs_->step_next ())
{
feature_ptr feature(new Feature(count_));
#ifdef MAPNIK_DEBUG
clog << "feature_oid=" << count_ << endl;
#endif
int size;
const char* data = (const char *) rs_->column_blob (0, size);
geometry_utils::from_wkb(*feature,data,size,multiple_geometries_,true);
int feature_id = rs_->column_integer (1);
for (int i = 1; i < rs_->column_count (); ++i)
#ifdef MAPNIK_DEBUG
// clog << "feature_oid=" << feature_id << endl;
#endif
feature_ptr feature(new Feature(feature_id));
geometry_utils::from_wkb(*feature,data,size,multiple_geometries_,mapnik::wkbSQLite);
for (int i = 2; i < rs_->column_count (); ++i)
{
const int type_oid = rs_->column_type (i);
const char* fld_name = rs_->column_name (i);
@ -111,8 +111,6 @@ feature_ptr sqlite_featureset::next()
break;
}
}
count_++;
return feature;
}

View File

@ -48,7 +48,6 @@ class sqlite_featureset : public mapnik::Featureset
boost::shared_ptr<sqlite_resultset> rs_;
boost::scoped_ptr<mapnik::transcoder> tr_;
bool multiple_geometries_;
mutable int count_;
};
#endif // SQLITE_FEATURESET_HPP

View File

@ -141,47 +141,26 @@ public:
int rc = sqlite3_exec (db_, sql.c_str(), callback, 0, &error_message);
if (rc != SQLITE_OK)
{
std::clog << error_message << std::endl;
sqlite3_free (error_message);
}
return rc;
}
boost::shared_ptr<sqlite_resultset> execute_query (const std::string& sql)
sqlite_resultset* execute_query (const std::string& sql)
{
sqlite3_stmt* stmt = 0;
int rc = sqlite3_prepare_v2 (db_, sql.c_str(), -1, &stmt, 0);
if (rc != SQLITE_OK)
{
std::clog << sqlite3_errmsg(db_) << std::endl;
}
return boost::shared_ptr<sqlite_resultset> (new sqlite_resultset (stmt));
return new sqlite_resultset (stmt);
}
#if 0
std::vector<std::string> get_table_columns (const std::string& sql)
{
char** result;
char* error_message = 0;
int nrow, ncol;
std::vector<std::string> head;
int rc = sqlite3_exec (db_, sql.c_str(), &result, &nrow, &ncol, &error_message);
if (rc == SQLITE_OK)
{
for (int i = 0; i < ncol; ++i)
head.push_back (result[i]);
// for (int i = 0; i < ncol * nrow; ++i)
// vdata.push_back(result[ncol+i]);
}
sqlite3_free_table(result);
return head;
}
#endif
sqlite3* operator*()
{
return db_;
@ -192,60 +171,5 @@ private:
sqlite3* db_;
};
#if 0
static int callback (void *not_used, int argc, char **argv, char** column_name)
{
not_used = 0;
for (int i = 0; i < argc; i++)
{
std::cout << column_name[i] << " = " << (argv[i] ? argv[i] : "NULL") << std::endl;
}
return 0;
}
static int print_col (sqlite_resultset& rs, int col)
{
switch (rs.column_type (col))
{
case SQLITE_INTEGER:
std::cout << "INTEGER: " << rs.column_integer (col) << std::endl;
break;
case SQLITE_FLOAT:
std::cout << "FLOAT: " << rs.column_double (col) << std::endl;
break;
case SQLITE_TEXT:
std::cout << "TEXT: " << rs.column_text (col) << std::endl;
break;
case SQLITE_BLOB:
{
std::cout << "BLOB: ";
int size;
const char * data = (const char *) rs.column_blob (col, size);
for (int i = 0; i < size; i++)
{
std::cout << data [i] << " ";
}
std::cout << std::endl;
break;
}
case SQLITE_NULL:
std::cout << "Null " << std::endl;
break;
default:
std::cout << " *Cannot determine SQLITE TYPE* col=" << col << std::endl;
}
return 0;
}
#endif
#endif //SQLITE_TYPES_HPP

View File

@ -41,7 +41,7 @@ namespace mapnik
unsigned pos_;
wkbByteOrder byteOrder_;
bool needSwap_;
bool sqliteFormat_;
wkbFormat format_;
public:
@ -55,21 +55,29 @@ namespace mapnik
wkbGeometryCollection=7
};
wkb_reader(const char* wkb,unsigned size,bool sqliteFormat = false)
wkb_reader(const char* wkb,unsigned size,wkbFormat format)
: wkb_(wkb),
size_(size),
pos_(0),
sqliteFormat_(sqliteFormat)
format_(format)
{
if (sqliteFormat)
if (format_ == wkbAutodetect)
{
byteOrder_ = (wkbByteOrder) wkb_[1];
pos_ = 39;
// XXX - todo
}
else
switch (format_)
{
byteOrder_ = (wkbByteOrder) wkb_[0];
++pos_;
case wkbSQLite:
byteOrder_ = (wkbByteOrder) wkb_[1];
pos_ = 39;
break;
case wkbGeneric:
default:
byteOrder_ = (wkbByteOrder) wkb_[0];
pos_ = 1;
break;
}
#ifndef WORDS_BIGENDIAN
@ -351,9 +359,13 @@ namespace mapnik
}
};
void geometry_utils::from_wkb(Feature & feature,const char* wkb, unsigned size, bool multiple_geometries, bool sqlite_format)
void geometry_utils::from_wkb (Feature & feature,
const char* wkb,
unsigned size,
bool multiple_geometries,
wkbFormat format)
{
wkb_reader reader(wkb,size,sqlite_format);
wkb_reader reader(wkb,size,format);
if (multiple_geometries)
return reader.read_multi(feature);
else