mirror of
https://github.com/mapnik/mapnik.git
synced 2025-12-08 20:13:09 +00:00
Following #223:
+ improvements to the wkb converter + improved sqlite index usage + added more parameters to sqlite datasource
This commit is contained in:
parent
1f5edf45f0
commit
2c81706eb5
@ -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&);
|
||||
|
||||
@ -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_));
|
||||
}
|
||||
|
||||
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
34
src/wkb.cpp
34
src/wkb.cpp
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user