diff --git a/plugins/input/sqlite/sqlite_datasource.cpp b/plugins/input/sqlite/sqlite_datasource.cpp index 01e393231..9ffce0557 100644 --- a/plugins/input/sqlite/sqlite_datasource.cpp +++ b/plugins/input/sqlite/sqlite_datasource.cpp @@ -77,15 +77,15 @@ sqlite_datasource::sqlite_datasource(parameters const& params, bool bind) { // TODO // - change param from 'file' to 'dbname' - // - require wkb_format? - // - split plugin into sqlite vs spatialite? - // - conversion/sqlite initialization tool - // - sync code with rasterlite + // - ensure that the supplied key_field is a valid "integer primary key" + // - move all intialization code to bind() boost::optional file = params_.get("file"); if (!file) throw datasource_exception("Sqlite Plugin: missing parameter"); - if (table_.empty()) throw mapnik::datasource_exception("Sqlite Plugin: missing parameter"); + if (table_.empty()) { + throw mapnik::datasource_exception("Sqlite Plugin: missing
parameter"); + } boost::optional key_field_name = params_.get("key_field"); if (key_field_name) { @@ -283,8 +283,8 @@ void sqlite_datasource::bind() const } } - // TODO - ensure that the supplied key_field is a valid "integer primary key" - desc_.add_descriptor(attribute_descriptor("rowid",mapnik::Integer)); + if (key_field_ == "rowid") + desc_.add_descriptor(attribute_descriptor("rowid",mapnik::Integer)); if (use_pragma_table_info) { @@ -295,6 +295,7 @@ void sqlite_datasource::bind() const while (rs->is_valid () && rs->step_next()) { found_table = true; + // TODO - support unicode strings? const char* fld_name = rs->column_text(1); std::string fld_type(rs->column_text(2)); boost::algorithm::to_lower(fld_type); @@ -425,7 +426,7 @@ void sqlite_datasource::bind() const // final fallback to gather extent if (!extent_initialized_ || !has_spatial_index_) { - /*if (use_spatial_index_ && key_field_ == "rowid" && boost::algorithm::icontains(geometry_table_,"from")) { + /*if (use_spatial_index_ && key_field_ == "rowid" && using_subquery_) { // this is an impossible situation because rowid will be null via a subquery throw datasource_exception("Sqlite Plugin: Using a spatial index will require creating one on the fly which is not possible unless you supply a 'key_field' value that references the primary key of your spatial table. To avoid using a spatial index set 'use_spatial_index'=false"); }*/ @@ -630,7 +631,7 @@ featureset_ptr sqlite_datasource::features(query const& q) const boost::shared_ptr rs (dataset_->execute_query (s.str())); - return boost::make_shared(rs, desc_.get_encoding(), format_, multiple_geometries_); + return boost::make_shared(rs, desc_.get_encoding(), format_, multiple_geometries_, using_subquery_); } return featureset_ptr(); @@ -694,7 +695,7 @@ featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt) const boost::shared_ptr rs (dataset_->execute_query (s.str())); - return boost::make_shared(rs, desc_.get_encoding(), format_, multiple_geometries_); + return boost::make_shared(rs, desc_.get_encoding(), format_, multiple_geometries_, using_subquery_); } return featureset_ptr(); diff --git a/plugins/input/sqlite/sqlite_featureset.cpp b/plugins/input/sqlite/sqlite_featureset.cpp index 27b3945e1..0ba6e1436 100644 --- a/plugins/input/sqlite/sqlite_featureset.cpp +++ b/plugins/input/sqlite/sqlite_featureset.cpp @@ -32,6 +32,7 @@ #include #include #include +#include // ogr #include "sqlite_featureset.hpp" @@ -48,16 +49,44 @@ using mapnik::feature_factory; sqlite_featureset::sqlite_featureset(boost::shared_ptr rs, std::string const& encoding, mapnik::wkbFormat format, - bool multiple_geometries) + bool multiple_geometries, + bool using_subquery) : rs_(rs), tr_(new transcoder(encoding)), format_(format), - multiple_geometries_(multiple_geometries) + multiple_geometries_(multiple_geometries), + using_subquery_(using_subquery) { } sqlite_featureset::~sqlite_featureset() {} +void sqlite_dequote(char *z){ + char quote; /* Quote character (if any ) */ + + quote = z[0]; + if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){ + int iIn = 1; /* Index of next byte to read from input */ + int iOut = 0; /* Index of next byte to write to output */ + + /* If the first byte was a '[', then the close-quote character is a ']' */ + if( quote=='[' ) quote = ']'; + + while( z[iIn] ){ + if( z[iIn]==quote ){ + if( z[iIn+1]!=quote ) break; + z[iOut++] = quote; + iIn += 2; + }else{ + z[iOut++] = z[iIn++]; + } + } + z[iOut] = '\0'; + } +} + + + feature_ptr sqlite_featureset::next() { if (rs_->is_valid () && rs_->step_next ()) @@ -68,56 +97,100 @@ feature_ptr sqlite_featureset::next() return feature_ptr(); int feature_id = rs_->column_integer (1); -#ifdef MAPNIK_DEBUG - // std::clog << "Sqlite Plugin: feature_oid=" << feature_id << std::endl; -#endif - feature_ptr feature(feature_factory::create(feature_id)); geometry_utils::from_wkb(*feature,data,size,multiple_geometries_,format_); for (int i = 2; i < rs_->column_count (); ++i) { - const int type_oid = rs_->column_type (i); - // TODO - avoid copying string - // TODO - handle single quotes - const char* fld_name = mapnik::unquote_sql2(rs_->column_name(i)).c_str(); - - switch (type_oid) - { - case SQLITE_INTEGER: - { - boost::put(*feature,fld_name,rs_->column_integer (i)); - break; - } - - case SQLITE_FLOAT: - { - boost::put(*feature,fld_name,rs_->column_double (i)); - break; - } - - case SQLITE_TEXT: - { - UnicodeString ustr = tr_->transcode (rs_->column_text (i)); - boost::put(*feature,fld_name,ustr); - break; - } + const int type_oid = rs_->column_type (i); + const char* fld_name = rs_->column_name(i); - case SQLITE_NULL: - { - boost::put(*feature,fld_name,mapnik::value_null()); - break; - } - - case SQLITE_BLOB: - break; - - default: -#ifdef MAPNIK_DEBUG - std::clog << "Sqlite Plugin: unhandled type_oid=" << type_oid << std::endl; -#endif - break; - } + if (!using_subquery_) + { + switch (type_oid) + { + case SQLITE_INTEGER: + { + boost::put(*feature,fld_name,rs_->column_integer (i)); + break; + } + + case SQLITE_FLOAT: + { + boost::put(*feature,fld_name,rs_->column_double (i)); + break; + } + + case SQLITE_TEXT: + { + int text_size; + const char * data = rs_->column_text(i,text_size); + UnicodeString ustr = tr_->transcode(data,text_size); + boost::put(*feature,fld_name,ustr); + break; + } + + case SQLITE_NULL: + { + boost::put(*feature,fld_name,mapnik::value_null()); + break; + } + + case SQLITE_BLOB: + break; + + default: + #ifdef MAPNIK_DEBUG + std::clog << "Sqlite Plugin: unhandled type_oid=" << type_oid << std::endl; + #endif + break; + } + } + else + { + // subqueries in sqlite lead to field double quoting which we need to strip + char fld_name2[strlen(fld_name)]; + strcpy(fld_name2,fld_name); + sqlite_dequote(fld_name2); + switch (type_oid) + { + case SQLITE_INTEGER: + { + boost::put(*feature,fld_name2,rs_->column_integer (i)); + break; + } + + case SQLITE_FLOAT: + { + boost::put(*feature,fld_name2,rs_->column_double (i)); + break; + } + + case SQLITE_TEXT: + { + int text_size; + const char * data = rs_->column_text(i,text_size); + UnicodeString ustr = tr_->transcode(data,text_size); + boost::put(*feature,fld_name2,ustr); + break; + } + + case SQLITE_NULL: + { + boost::put(*feature,fld_name2,mapnik::value_null()); + break; + } + + case SQLITE_BLOB: + break; + + default: + #ifdef MAPNIK_DEBUG + std::clog << "Sqlite Plugin: unhandled type_oid=" << type_oid << std::endl; + #endif + break; + } + } } return feature; diff --git a/plugins/input/sqlite/sqlite_featureset.hpp b/plugins/input/sqlite/sqlite_featureset.hpp index 0a025f096..d9d3eafd9 100644 --- a/plugins/input/sqlite/sqlite_featureset.hpp +++ b/plugins/input/sqlite/sqlite_featureset.hpp @@ -43,7 +43,8 @@ class sqlite_featureset : public mapnik::Featureset sqlite_featureset(boost::shared_ptr rs, std::string const& encoding, mapnik::wkbFormat format, - bool multiple_geometries); + bool multiple_geometries, + bool using_subquery); virtual ~sqlite_featureset(); mapnik::feature_ptr next(); private: @@ -51,6 +52,7 @@ class sqlite_featureset : public mapnik::Featureset boost::scoped_ptr tr_; mapnik::wkbFormat format_; bool multiple_geometries_; + bool using_subquery_; }; #endif // SQLITE_FEATURESET_HPP diff --git a/plugins/input/sqlite/sqlite_types.hpp b/plugins/input/sqlite/sqlite_types.hpp index 43514578f..1d3574557 100644 --- a/plugins/input/sqlite/sqlite_types.hpp +++ b/plugins/input/sqlite/sqlite_types.hpp @@ -96,6 +96,12 @@ public: return sqlite3_column_double (stmt_, col); } + const char* column_text (int col, int& len) + { + len = sqlite3_column_bytes (stmt_, col); + return (const char*) sqlite3_column_text (stmt_, col); + } + const char* column_text (int col) { return (const char*) sqlite3_column_text (stmt_, col); @@ -104,7 +110,6 @@ public: const void* column_blob (int col, int& bytes) { bytes = sqlite3_column_bytes (stmt_, col); - return sqlite3_column_blob (stmt_, col); }