featureset_ptr ogr_datasource::features(query const& q) const { if (! is_bound_) bind(); if (dataset_ && layer_.is_valid()) { OGRLayer* layer = layer_.layer(); if (indexed_) { filter_in_box filter(q.get_bbox()); return featureset_ptr(new ogr_index_featureset<filter_in_box>(*dataset_, *layer, filter, index_name_, desc_.get_encoding(), multiple_geometries_)); } else { return featureset_ptr(new ogr_featureset (*dataset_, *layer, q.get_bbox(), desc_.get_encoding(), multiple_geometries_)); } } return featureset_ptr(); }
featureset_ptr ogr_datasource::features(query const& q) const { if (!is_bound_) bind(); if (dataset_ && layer_) { // TODO - actually filter fields! // http://trac.osgeo.org/gdal/wiki/rfc29_desired_fields // http://trac.osgeo.org/gdal/wiki/rfc28_sqlfunc #if 0 std::ostringstream s; s << "select "; 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(); while (pos != end) { s <<",\""<<*pos<<"\""; ++pos; } s << " from " << layerName_ ; // execute existing SQL OGRLayer* layer = dataset_->ExecuteSQL (s.str(), poly); // layer must be freed dataset_->ReleaseResultSet (layer); #endif if (indexed_) { filter_in_box filter(q.get_bbox()); return featureset_ptr(new ogr_index_featureset<filter_in_box> (*dataset_, *layer_, filter, index_name_, desc_.get_encoding(), multiple_geometries_)); } else { return featureset_ptr(new ogr_featureset (*dataset_, *layer_, q.get_bbox(), desc_.get_encoding(), multiple_geometries_)); } } return featureset_ptr(); }
featureset_ptr shape_datasource::features(const query& q) const { if (!is_bound_) bind(); filter_in_box filter(q.get_bbox()); if (indexed_) { shape_->shp().seek(0); // TODO - use boost::make_shared - #760 return featureset_ptr (new shape_index_featureset<filter_in_box>(filter, *shape_, q.property_names(), desc_.get_encoding(), shape_name_, row_limit_)); } else { return boost::make_shared<shape_featureset<filter_in_box> >(filter, shape_name_, q.property_names(), desc_.get_encoding(), file_length_, row_limit_); } }
featureset_ptr geos_datasource::features(query const& q) const { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "geos_datasource::features"); #endif const mapnik::box2d<double> extent = q.get_bbox(); std::ostringstream s; s << "POLYGON((" << extent.minx() << " " << extent.miny() << "," << extent.maxx() << " " << extent.miny() << "," << extent.maxx() << " " << extent.maxy() << "," << extent.minx() << " " << extent.maxy() << "," << extent.minx() << " " << extent.miny() << "))"; MAPNIK_LOG_DEBUG(geos) << "geos_datasource: Using extent=" << s.str(); return boost::make_shared<geos_featureset>(*geometry_, GEOSGeomFromWKT(s.str().c_str()), geometry_id_, geometry_data_, geometry_data_name_, desc_.get_encoding()); }
featureset_ptr geos_datasource::features(query const& q) const { if (!is_bound_) bind(); const mapnik::box2d<double> extent = q.get_bbox(); std::ostringstream s; s << "POLYGON((" << extent.minx() << " " << extent.miny() << "," << extent.maxx() << " " << extent.miny() << "," << extent.maxx() << " " << extent.maxy() << "," << extent.minx() << " " << extent.maxy() << "," << extent.minx() << " " << extent.miny() << "))"; #ifdef MAPNIK_DEBUG clog << "GEOS Plugin: using extent: " << s.str() << endl; #endif return boost::make_shared<geos_featureset>(*geometry_, GEOSGeomFromWKT(s.str().c_str()), geometry_id_, geometry_data_, geometry_data_name_, desc_.get_encoding(), multiple_geometries_); }
featureset_ptr shape_datasource::features(query const& q) const { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "shape_datasource::features"); #endif filter_in_box filter(q.get_bbox()); if (indexed_) { std::unique_ptr<shape_io> shape_ptr = std::make_unique<shape_io>(shape_name_); return featureset_ptr (new shape_index_featureset<filter_in_box>(filter, std::move(shape_ptr), q.property_names(), desc_.get_encoding(), shape_name_, row_limit_)); } else { return std::make_shared<shape_featureset<filter_in_box> >(filter, shape_name_, q.property_names(), desc_.get_encoding(), file_length_, row_limit_); } }
featureset_ptr shape_datasource::features(const query& q) const { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "shape_datasource::features"); #endif filter_in_box filter(q.get_bbox()); if (indexed_) { shape_->shp().seek(0); // TODO - use std::make_shared - #760 return featureset_ptr (new shape_index_featureset<filter_in_box>(filter, *shape_, q.property_names(), desc_.get_encoding(), shape_name_, row_limit_)); } else { return std::make_shared<shape_featureset<filter_in_box> >(filter, shape_name_, q.property_names(), desc_.get_encoding(), file_length_, row_limit_); } }
featureset_ptr raster_datasource::features(query const& q) const { if (! is_bound_) bind(); mapnik::CoordTransform t(width_, height_, extent_, 0, 0); mapnik::box2d<double> intersect = extent_.intersect(q.get_bbox()); mapnik::box2d<double> ext = t.forward(intersect); const int width = int(ext.maxx() + 0.5) - int(ext.minx() + 0.5); const int height = int(ext.maxy() + 0.5) - int(ext.miny() + 0.5); #ifdef MAPNIK_DEBUG std::clog << "Raster Plugin: BOX SIZE(" << width << " " << height << ")" << std::endl; #endif if (multi_tiles_) { #ifdef MAPNIK_DEBUG std::clog << "Raster Plugin: MULTI-TILED policy" << std::endl; #endif tiled_multi_file_policy policy(filename_, format_, tile_size_, extent_, q.get_bbox(), width_, height_, tile_stride_); return boost::make_shared<raster_featureset<tiled_multi_file_policy> >(policy, extent_, q); } else if (width * height > 512*512) { #ifdef MAPNIK_DEBUG std::clog << "Raster Plugin: TILED policy" << std::endl; #endif tiled_file_policy policy(filename_, format_, 256, extent_, q.get_bbox(), width_, height_); return boost::make_shared<raster_featureset<tiled_file_policy> >(policy, extent_, q); } else { #ifdef MAPNIK_DEBUG std::clog << "Raster Plugin: SINGLE FILE" << std::endl; #endif raster_info info(filename_, format_, extent_, width_, height_); single_file_policy policy(info); return boost::make_shared<raster_featureset<single_file_policy> >(policy, extent_, q); } }
featureset_ptr ogr_datasource::features(query const& q) const { if (! is_bound_) bind(); #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "ogr_datasource::features"); #endif if (dataset_ && layer_.is_valid()) { // First we validate query fields: https://github.com/mapnik/mapnik/issues/792 std::vector<attribute_descriptor> const& desc_ar = desc_.get_descriptors(); // feature context (schema) mapnik::context_ptr ctx = boost::make_shared<mapnik::context_type>(); std::vector<attribute_descriptor>::const_iterator itr = desc_ar.begin(); std::vector<attribute_descriptor>::const_iterator end = desc_ar.end(); for (; itr!=end; ++itr) ctx->push(itr->get_name()); // TODO only push query attributes validate_attribute_names(q, desc_ar); OGRLayer* layer = layer_.layer(); if (indexed_) { filter_in_box filter(q.get_bbox()); return featureset_ptr(new ogr_index_featureset<filter_in_box>(ctx, *layer, filter, index_name_, desc_.get_encoding())); } else { return featureset_ptr(new ogr_featureset(ctx, *layer, q.get_bbox(), desc_.get_encoding())); } } return featureset_ptr(); }
raster_featureset<LookupPolicy>::raster_featureset(LookupPolicy const& policy,query const& q) : policy_(policy), id_(1), extent_(q.get_bbox()), t_(q.get_width(),q.get_height(),extent_), curIter_(policy_.query(extent_)), endIter_(policy_.end()) {}
featureset_ptr shape_datasource::features(const query& q) const { filter_in_box filter(q.get_bbox()); if (indexed_) { return featureset_ptr(new shape_index_featureset<filter_in_box>(filter,shape_name_,q.property_names())); } return featureset_ptr(new shape_featureset<filter_in_box>(filter,shape_name_,q.property_names(),file_length_)); }
featureset_ptr osm_datasource::features(const query& q) const { filter_in_box filter(q.get_bbox()); // so we need to filter osm features by bbox here... return std::make_shared<osm_featureset<filter_in_box> >(filter, osm_data_, q.property_names(), desc_.get_encoding()); }
raster_featureset<LookupPolicy>::raster_featureset(LookupPolicy const& policy, box2d<double> const& extent, query const& q) : policy_(policy), feature_id_(1), extent_(extent), bbox_(q.get_bbox()), curIter_(policy_.begin()), endIter_(policy_.end()) { }
raster_featureset<LookupPolicy>::raster_featureset(LookupPolicy const& policy, box2d<double> const& extent, query const& q) : policy_(policy), feature_id_(1), ctx_(boost::make_shared<mapnik::context_type>()), extent_(extent), bbox_(q.get_bbox()), curIter_(policy_.begin()), endIter_(policy_.end()) { }
featureset_ptr raster_datasource::features(query const& q) const { if (! is_bound_) bind(); mapnik::CoordTransform t(width_, height_, extent_, 0, 0); mapnik::box2d<double> intersect = extent_.intersect(q.get_bbox()); mapnik::box2d<double> ext = t.forward(intersect); const int width = int(ext.maxx() + 0.5) - int(ext.minx() + 0.5); const int height = int(ext.maxy() + 0.5) - int(ext.miny() + 0.5); MAPNIK_LOG_DEBUG(raster) << "raster_datasource: Box size=" << width << "," << height; if (multi_tiles_) { MAPNIK_LOG_DEBUG(raster) << "raster_datasource: Multi-Tiled policy"; tiled_multi_file_policy policy(filename_, format_, tile_size_, extent_, q.get_bbox(), width_, height_, tile_stride_); return boost::make_shared<raster_featureset<tiled_multi_file_policy> >(policy, extent_, q); } else if (width * height > (tile_size_ * tile_size_ << 2)) { MAPNIK_LOG_DEBUG(raster) << "raster_datasource: Tiled policy"; tiled_file_policy policy(filename_, format_, tile_size_, extent_, q.get_bbox(), width_, height_); return boost::make_shared<raster_featureset<tiled_file_policy> >(policy, extent_, q); } else { MAPNIK_LOG_DEBUG(raster) << "raster_datasource: Single file"; raster_info info(filename_, format_, extent_, width_, height_); single_file_policy policy(info); return boost::make_shared<raster_featureset<single_file_policy> >(policy, extent_, q); } }
featureset_ptr occi_datasource::features(query const& q) const { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "occi_datasource::features"); #endif box2d<double> const& box = q.get_bbox(); const double px_gw = 1.0 / std::get<0>(q.resolution()); const double px_gh = 1.0 / std::get<1>(q.resolution()); const double scale_denom = q.scale_denominator(); std::ostringstream s; s << "SELECT "; if (use_wkb_) { s << "SDO_UTIL.TO_WKBGEOMETRY(" << geometry_field_ << ")"; } else { s << geometry_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(); mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>(); for (; pos != end; ++pos) { s << ", " << *pos; ctx->push(*pos); } std::string query = populate_tokens(table_, scale_denom, box, px_gw, px_gh); if (use_spatial_index_) { std::ostringstream spatial_sql; spatial_sql << " WHERE SDO_FILTER("; spatial_sql << geometry_field_ << "," << sql_bbox(box); spatial_sql << ", 'querytype = WINDOW') = 'TRUE'"; if (boost::algorithm::ifind_first(query, "WHERE")) { boost::algorithm::ireplace_first(query, "WHERE", spatial_sql.str() + " AND "); } else if (boost::algorithm::ifind_first(query, table_name_)) { boost::algorithm::ireplace_first(query, table_name_, table_name_ + " " + spatial_sql.str()); } else { MAPNIK_LOG_WARN(occi) << "occi_datasource: cannot determine where to add the spatial filter declaration"; } } s << " FROM " << query; if (row_limit_ > 0) { s << " WHERE ROWNUM < " << row_limit_; } MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); return std::make_shared<occi_featureset>(pool_, conn_, ctx, s.str(), desc_.get_encoding(), use_connection_pool_, use_wkb_, row_prefetch_); }
static boost::python::tuple getinitargs(query const& q) { return boost::python::make_tuple(q.get_bbox(),q.resolution()); }
featureset_ptr postgis_datasource::features_with_context(query const& q,processor_context_ptr proc_ctx) const { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "postgis_datasource::features_with_context"); #endif box2d<double> const& box = q.get_bbox(); double scale_denom = q.scale_denominator(); CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id()); if (pool) { shared_ptr<Connection> conn; if ( asynchronous_request_ ) { // limit use to num_async_request_ => if reached don't borrow the last connexion object std::shared_ptr<postgis_processor_context> pgis_ctxt = std::static_pointer_cast<postgis_processor_context>(proc_ctx); if ( pgis_ctxt->num_async_requests_ < max_async_connections_ ) { conn = pool->borrowObject(); pgis_ctxt->num_async_requests_++; } } else { // Always get a connection in synchronous mode conn = pool->borrowObject(); if(!conn ) { throw mapnik::datasource_exception("Postgis Plugin: Null connection"); } } if (geometryColumn_.empty()) { std::ostringstream s_error; s_error << "PostGIS: geometry name lookup failed for table '"; if (! schema_.empty()) { s_error << schema_ << "."; } s_error << geometry_table_ << "'. Please manually provide the 'geometry_field' parameter or add an entry " << "in the geometry_columns for '"; if (! schema_.empty()) { s_error << schema_ << "."; } s_error << geometry_table_ << "'."; throw mapnik::datasource_exception(s_error.str()); } std::ostringstream s; const double px_gw = 1.0 / std::get<0>(q.resolution()); const double px_gh = 1.0 / std::get<1>(q.resolution()); s << "SELECT ST_AsBinary("; if (simplify_geometries_) { s << "ST_Simplify("; } s << "\"" << geometryColumn_ << "\""; if (simplify_geometries_) { // 1/20 of pixel seems to be a good compromise to avoid // drop of collapsed polygons. // See https://github.com/mapnik/mapnik/issues/1639 const double tolerance = std::min(px_gw, px_gh) / 20.0; s << ", " << tolerance << ")"; } s << ") AS geom"; mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>(); 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(); if (! key_field_.empty()) { mapnik::sql_utils::quote_attr(s, key_field_); ctx->push(key_field_); for (; pos != end; ++pos) { if (*pos != key_field_) { mapnik::sql_utils::quote_attr(s, *pos); ctx->push(*pos); } } } else { for (; pos != end; ++pos) { mapnik::sql_utils::quote_attr(s, *pos); ctx->push(*pos); } } std::string table_with_bbox = populate_tokens(table_, scale_denom, box, px_gw, px_gh, q.variables()); s << " FROM " << table_with_bbox; if (row_limit_ > 0) { s << " LIMIT " << row_limit_; } std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool, proc_ctx); return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty()); } return featureset_ptr(); }
featureset_ptr occi_datasource::features(query const& q) const { if (!is_bound_) bind(); box2d<double> const& box=q.get_bbox(); std::ostringstream s; s << "SELECT " << geometry_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(); while (pos != end) { s << ", " << *pos; ++pos; } s << " FROM "; std::string query (table_); std::string table_name = mapnik::table_from_sql(query); if (use_spatial_index_) { std::ostringstream spatial_sql; spatial_sql << std::setprecision(16); spatial_sql << " WHERE SDO_FILTER(" << geometry_field_ << ","; spatial_sql << " MDSYS.SDO_GEOMETRY(" << SDO_GTYPE_2DPOLYGON << "," << srid_ << ",NULL,"; spatial_sql << " MDSYS.SDO_ELEM_INFO_ARRAY(1," << SDO_ETYPE_POLYGON << "," << SDO_INTERPRETATION_RECTANGLE << "),"; spatial_sql << " MDSYS.SDO_ORDINATE_ARRAY("; spatial_sql << box.minx() << "," << box.miny() << ", "; spatial_sql << box.maxx() << "," << box.maxy() << ")), 'querytype=WINDOW') = 'TRUE'"; if (boost::algorithm::ifind_first(query, "WHERE")) { boost::algorithm::ireplace_first(query, "WHERE", spatial_sql.str() + " AND "); } else if (boost::algorithm::ifind_first(query, table_name)) { boost::algorithm::ireplace_first(query, table_name, table_name + " " + spatial_sql.str()); } else { #ifdef MAPNIK_DEBUG std::clog << "OCCI Plugin: cannot determine where to add the spatial filter declaration" << std::endl; #endif } } if (row_limit_ > 0) { std::string row_limit_string = "rownum < " + row_limit_; if (boost::algorithm::ifind_first(query, "WHERE")) { boost::algorithm::ireplace_first(query, "WHERE", row_limit_string + " AND "); } else if (boost::algorithm::ifind_first(query, table_name)) { boost::algorithm::ireplace_first(query, table_name, table_name + " " + row_limit_string); } else { #ifdef MAPNIK_DEBUG std::clog << "OCCI Plugin: cannot determine where to add the row limit declaration" << std::endl; #endif } } s << query; #ifdef MAPNIK_DEBUG std::clog << "OCCI Plugin: " << s.str() << std::endl; #endif return featureset_ptr (new occi_featureset (pool_, conn_, s.str(), desc_.get_encoding(), multiple_geometries_, use_connection_pool_, row_prefetch_, props.size())); }
featureset_ptr occi_datasource::features(query const& q) const { if (! is_bound_) bind(); #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "occi_datasource::features"); #endif box2d<double> const& box = q.get_bbox(); std::ostringstream s; s << "SELECT "; if (use_wkb_) { s << "SDO_UTIL.TO_WKBGEOMETRY(" << geometry_field_ << ")"; } else { s << geometry_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(); mapnik::context_ptr ctx = boost::make_shared<mapnik::context_type>(); for (; pos != end; ++pos) { s << ", " << *pos; ctx->push(*pos); } s << " FROM "; std::string query(table_); if (use_spatial_index_) { std::ostringstream spatial_sql; spatial_sql << std::setprecision(16); spatial_sql << " WHERE SDO_FILTER(" << geometry_field_ << ","; spatial_sql << " MDSYS.SDO_GEOMETRY(" << SDO_GTYPE_2DPOLYGON << "," << srid_ << ",NULL,"; spatial_sql << " MDSYS.SDO_ELEM_INFO_ARRAY(1," << SDO_ETYPE_POLYGON << "," << SDO_INTERPRETATION_RECTANGLE << "),"; spatial_sql << " MDSYS.SDO_ORDINATE_ARRAY("; spatial_sql << box.minx() << "," << box.miny() << ", "; spatial_sql << box.maxx() << "," << box.maxy() << ")), 'querytype=WINDOW') = 'TRUE'"; if (boost::algorithm::ifind_first(query, "WHERE")) { boost::algorithm::ireplace_first(query, "WHERE", spatial_sql.str() + " AND "); } else if (boost::algorithm::ifind_first(query, table_name_)) { boost::algorithm::ireplace_first(query, table_name_, table_name_ + " " + spatial_sql.str()); } else { MAPNIK_LOG_WARN(occi) << "occi_datasource: cannot determine where to add the spatial filter declaration"; } } if (row_limit_ > 0) { std::ostringstream row_limit_string; row_limit_string << "rownum < " << row_limit_; if (boost::algorithm::ifind_first(query, "WHERE")) { boost::algorithm::ireplace_first(query, "WHERE", row_limit_string.str() + " AND "); } else if (boost::algorithm::ifind_first(query, table_name_)) { boost::algorithm::ireplace_first(query, table_name_, table_name_ + " " + row_limit_string.str()); } else { MAPNIK_LOG_WARN(occi) << "occi_datasource: Cannot determine where to add the row limit declaration"; } } s << query; MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); return boost::make_shared<occi_featureset>(pool_, conn_, ctx, s.str(), desc_.get_encoding(), use_connection_pool_, use_wkb_, row_prefetch_); }
featureset_ptr pgraster_datasource::features_with_context(query const& q,processor_context_ptr proc_ctx) const { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "pgraster_datasource::features_with_context"); #endif box2d<double> const& box = q.get_bbox(); double scale_denom = q.scale_denominator(); CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id()); if (pool) { shared_ptr<Connection> conn; if ( asynchronous_request_ ) { // limit use to num_async_request_ => if reached don't borrow the last connexion object std::shared_ptr<postgis_processor_context> pgis_ctxt = std::static_pointer_cast<postgis_processor_context>(proc_ctx); if ( pgis_ctxt->num_async_requests_ < max_async_connections_ ) { conn = pool->borrowObject(); pgis_ctxt->num_async_requests_++; } } else { // Always get a connection in synchronous mode conn = pool->borrowObject(); if(!conn ) { throw mapnik::datasource_exception("Pgraster Plugin: Null connection"); } } if (geometryColumn_.empty()) { std::ostringstream s_error; s_error << "PostGIS: geometry name lookup failed for table '"; if (! schema_.empty()) { s_error << schema_ << "."; } s_error << raster_table_ << "'. Please manually provide the 'geometry_field' parameter or add an entry " << "in the geometry_columns for '"; if (! schema_.empty()) { s_error << schema_ << "."; } s_error << raster_table_ << "'."; throw mapnik::datasource_exception(s_error.str()); } const double px_gw = 1.0 / std::get<0>(q.resolution()); const double px_gh = 1.0 / std::get<1>(q.resolution()); MAPNIK_LOG_DEBUG(pgraster) << "pgraster_datasource: px_gw=" << px_gw << " px_gh=" << px_gh; std::string table_with_bbox; std::string col = geometryColumn_; if ( use_overviews_ && !overviews_.empty()) { std::string sch = overviews_[0].schema; std::string tab = overviews_[0].table; col = overviews_[0].column; const double scale = std::min(px_gw, px_gh); std::vector<pgraster_overview>::const_reverse_iterator i; for (i=overviews_.rbegin(); i!=overviews_.rend(); ++i) { const pgraster_overview& o = *i; if ( o.scale < scale ) { sch = o.schema; tab = o.table; col = o.column; MAPNIK_LOG_DEBUG(pgraster) << "pgraster_datasource: using overview " << o.schema << "." << o.table << "." << o.column << " with scale=" << o.scale << " for min out scale=" << scale; break; } else { MAPNIK_LOG_DEBUG(pgraster) << "pgraster_datasource: overview " << o.schema << "." << o.table << "." << o.column << " with scale=" << o.scale << " not good for min out scale " << scale; } } table_with_bbox = table_; // possibly a subquery boost::algorithm::replace_all(table_with_bbox, mapnik::sql_utils::unquote_double(raster_table_), tab); boost::algorithm::replace_all(table_with_bbox, mapnik::sql_utils::unquote_double(schema_), sch); boost::algorithm::replace_all(table_with_bbox, mapnik::sql_utils::unquote_double(geometryColumn_), col); table_with_bbox = populate_tokens(table_with_bbox, scale_denom, box, px_gw, px_gh); } else { table_with_bbox = populate_tokens(table_, scale_denom, box, px_gw, px_gh); } std::ostringstream s; s << "SELECT ST_AsBinary("; if (band_) s << "ST_Band("; if (prescale_rasters_) s << "ST_Resize("; if (clip_rasters_) s << "ST_Clip("; s << "\"" << col << "\""; if (clip_rasters_) { s << ", ST_Expand(" << sql_bbox(box) << ", greatest(abs(ST_ScaleX(\"" << col << "\")), abs(ST_ScaleY(\"" << col << "\")))))"; } if (prescale_rasters_) { const double scale = std::min(px_gw, px_gh); s << ", least(abs(ST_ScaleX(\"" << col << "\"))::float8/" << scale << ", 1.0), least(abs(ST_ScaleY(\"" << col << "\"))::float8/" << scale << ", 1.0))"; // TODO: if band_ is given, we'll interpret as indexed so // the rescaling must NOT ruin it (use algorithm mode!) } if (band_) s << ", " << band_ << ")"; s << ") AS geom"; mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>(); 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(); if (! key_field_.empty()) { mapnik::sql_utils::quote_attr(s, key_field_); ctx->push(key_field_); for (; pos != end; ++pos) { if (*pos != key_field_) { mapnik::sql_utils::quote_attr(s, *pos); ctx->push(*pos); } } } else { for (; pos != end; ++pos) { mapnik::sql_utils::quote_attr(s, *pos); ctx->push(*pos); } } s << " FROM " << table_with_bbox; if (row_limit_ > 0) { s << " LIMIT " << row_limit_; } MAPNIK_LOG_DEBUG(pgraster) << "pgraster_datasource: " "features query: " << s.str(); std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool, proc_ctx); return std::make_shared<pgraster_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty(), band_ ? 1 : 0 // whatever band number is given we'd have // extracted with ST_Band above so it becomes // band number 1 ); } return mapnik::make_invalid_featureset(); }
featureset_ptr sqlite_datasource::features(query const& q) const { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "sqlite_datasource::features"); #endif if (dataset_) { mapnik::box2d<double> const& e = q.get_bbox(); std::ostringstream s; mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>(); s << "SELECT " << geometry_field_; if (!key_field_.empty()) { s << "," << key_field_; ctx->push(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(); for ( ;pos != end;++pos) { // TODO - should we restrict duplicate key query? //if (*pos != key_field_) s << ",[" << *pos << "]"; ctx->push(*pos); } s << " FROM "; std::string query(table_); 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_, intersects_token_); } else { query = populate_tokens(table_); } s << query ; if (row_limit_ > 0) { s << " LIMIT " << row_limit_; } if (row_offset_ > 0) { s << " OFFSET " << row_offset_; } MAPNIK_LOG_DEBUG(sqlite) << "sqlite_datasource: " << s.str(); std::shared_ptr<sqlite_resultset> rs(dataset_->execute_query(s.str())); return std::make_shared<sqlite_featureset>(rs, ctx, desc_.get_encoding(), e, format_, has_spatial_index_, using_subquery_); } return featureset_ptr(); }
featureset_ptr memory_datasource::features(const query& q) const { return std::make_shared<memory_featureset>(q.get_bbox(),*this,bbox_check_); }
featureset_ptr postgis_datasource::features(const query& q) const { if (!is_bound_) bind(); box2d<double> const& box = q.get_bbox(); double scale_denom = q.scale_denominator(); ConnectionManager *mgr=ConnectionManager::instance(); shared_ptr<Pool<Connection,ConnectionCreator> > pool=mgr->getPool(creator_.id()); if (pool) { shared_ptr<Connection> conn = pool->borrowObject(); if (conn && conn->isOK()) { PoolGuard<shared_ptr<Connection>,shared_ptr<Pool<Connection,ConnectionCreator> > > guard(conn,pool); if (!geometryColumn_.length() > 0) { std::ostringstream s_error; s_error << "PostGIS: geometry name lookup failed for table '"; if (schema_.length() > 0) { s_error << schema_ << "."; } s_error << geometry_table_ << "'. Please manually provide the 'geometry_field' parameter or add an entry " << "in the geometry_columns for '"; if (schema_.length() > 0) { s_error << schema_ << "."; } s_error << geometry_table_ << "'."; throw mapnik::datasource_exception(s_error.str()); } std::ostringstream s; s << "SELECT ST_AsBinary(\"" << geometryColumn_ << "\") AS geom"; if (!key_field_.empty()) mapnik::sql_utils::quote_attr(s,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(); while (pos != end) { mapnik::sql_utils::quote_attr(s,*pos); ++pos; } std::string table_with_bbox = populate_tokens(table_,scale_denom,box); s << " from " << table_with_bbox; if (row_limit_ > 0) { s << " LIMIT " << row_limit_; } boost::shared_ptr<IResultSet> rs = get_resultset(conn, s.str()); unsigned num_attr = props.size(); if (!key_field_.empty()) ++num_attr; return boost::make_shared<postgis_featureset>(rs,desc_.get_encoding(), !key_field_.empty(),num_attr); } else { throw mapnik::datasource_exception("Postgis Plugin: bad connection"); } } return featureset_ptr(); }
featureset_ptr memory_datasource::features(const query& q) const { return boost::make_shared<memory_featureset>(q.get_bbox(),*this); }
featureset_ptr memory_datasource::features(const query& q) const { return featureset_ptr(new memory_featureset(q.get_bbox(),*this)); }
featureset_ptr postgis_datasource::features(const query& q) const { if (! is_bound_) { bind(); } #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "postgis_datasource::features"); #endif box2d<double> const& box = q.get_bbox(); double scale_denom = q.scale_denominator(); shared_ptr< Pool<Connection,ConnectionCreator> > pool = ConnectionManager::instance().getPool(creator_.id()); if (pool) { shared_ptr<Connection> conn = pool->borrowObject(); if (conn && conn->isOK()) { PoolGuard<shared_ptr<Connection>, shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn ,pool); if (geometryColumn_.empty()) { std::ostringstream s_error; s_error << "PostGIS: geometry name lookup failed for table '"; if (! schema_.empty()) { s_error << schema_ << "."; } s_error << geometry_table_ << "'. Please manually provide the 'geometry_field' parameter or add an entry " << "in the geometry_columns for '"; if (! schema_.empty()) { s_error << schema_ << "."; } s_error << geometry_table_ << "'."; throw mapnik::datasource_exception(s_error.str()); } std::ostringstream s; const double px_gw = 1.0 / boost::get<0>(q.resolution()); const double px_gh = 1.0 / boost::get<1>(q.resolution()); s << "SELECT ST_AsBinary("; if (simplify_geometries_) { s << "ST_Simplify("; } s << "\"" << geometryColumn_ << "\""; if (simplify_geometries_) { const double tolerance = std::min(px_gw, px_gh) / 2.0; s << ", " << tolerance << ")"; } s << ") AS geom"; mapnik::context_ptr ctx = boost::make_shared<mapnik::context_type>(); 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(); if (! key_field_.empty()) { mapnik::sql_utils::quote_attr(s, key_field_); ctx->push(key_field_); for (; pos != end; ++pos) { if (*pos != key_field_) { mapnik::sql_utils::quote_attr(s, *pos); ctx->push(*pos); } } } else { for (; pos != end; ++pos) { mapnik::sql_utils::quote_attr(s, *pos); ctx->push(*pos); } } std::string table_with_bbox = populate_tokens(table_, scale_denom, box, px_gw, px_gh); s << " FROM " << table_with_bbox; if (row_limit_ > 0) { s << " LIMIT " << row_limit_; } boost::shared_ptr<IResultSet> rs = get_resultset(conn, s.str()); return boost::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty()); } else { std::string err_msg = "Postgis Plugin:"; if (conn) { err_msg += conn->status(); } else { err_msg += " Null connection"; } throw mapnik::datasource_exception(err_msg); } } return featureset_ptr(); }
featureset_ptr sqlite_datasource::features(query const& q) const { if (!is_bound_) bind(); if (dataset_) { mapnik::box2d<double> const& e = q.get_bbox(); std::ostringstream s; 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(); while (pos != end) { s << ",\"" << *pos << "\""; ++pos; } s << " FROM "; std::string query (table_); if (use_spatial_index_) { std::ostringstream spatial_sql; spatial_sql << std::setprecision(16); spatial_sql << " WHERE " << key_field_ << " IN (SELECT pkid FROM idx_" << geometry_table_ << "_" << geometry_field_; 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")) { boost::algorithm::ireplace_first(query, "WHERE", spatial_sql.str() + " AND "); } else if (boost::algorithm::ifind_first(query, geometry_table_)) { boost::algorithm::ireplace_first(query, table_, table_ + " " + spatial_sql.str()); } } s << query ; if (row_limit_ > 0) { s << " LIMIT " << row_limit_; } if (row_offset_ > 0) { s << " OFFSET " << row_offset_; } #ifdef MAPNIK_DEBUG std::clog << "Sqlite Plugin: " << s.str() << std::endl; #endif boost::shared_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str())); return boost::make_shared<sqlite_featureset>(rs, desc_.get_encoding(), format_, multiple_geometries_); } return featureset_ptr(); }
featureset_ptr postgis_datasource::features_with_context(query const& q,processor_context_ptr proc_ctx) const { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "postgis_datasource::features_with_context"); #endif box2d<double> const& box = q.get_bbox(); double scale_denom = q.scale_denominator(); CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id()); if (pool) { shared_ptr<Connection> conn; if ( asynchronous_request_ ) { // limit use to num_async_request_ => if reached don't borrow the last connexion object std::shared_ptr<postgis_processor_context> pgis_ctxt = std::static_pointer_cast<postgis_processor_context>(proc_ctx); if ( pgis_ctxt->num_async_requests_ < max_async_connections_ ) { conn = pool->borrowObject(); pgis_ctxt->num_async_requests_++; } } else { // Always get a connection in synchronous mode conn = pool->borrowObject(); if(!conn ) { throw mapnik::datasource_exception("Postgis Plugin: Null connection"); } } if (geometryColumn_.empty()) { std::ostringstream s_error; s_error << "PostGIS: geometry name lookup failed for table '"; if (! schema_.empty()) { s_error << schema_ << "."; } s_error << geometry_table_ << "'. Please manually provide the 'geometry_field' parameter or add an entry " << "in the geometry_columns for '"; if (! schema_.empty()) { s_error << schema_ << "."; } s_error << geometry_table_ << "'."; throw mapnik::datasource_exception(s_error.str()); } std::ostringstream s; const double px_gw = 1.0 / std::get<0>(q.resolution()); const double px_gh = 1.0 / std::get<1>(q.resolution()); const double px_sz = std::min(px_gw, px_gh); if (twkb_encoding_) { // This will only work against PostGIS 2.2, or a back-patched version // that has (a) a ST_Simplify with a "preserve collapsed" flag and // (b) a ST_RemoveRepeatedPoints with a tolerance parameter and // (c) a ST_AsTWKB implementation // What number of decimals of rounding does the pixel size imply? const int twkb_rounding = -1 * std::lround(log10(px_sz) + twkb_rounding_adjustment_) + 1; // And what's that in map units? const double twkb_tolerance = pow(10.0, -1.0 * twkb_rounding); s << "SELECT ST_AsTWKB("; s << "ST_Simplify("; s << "ST_RemoveRepeatedPoints("; if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz) { s << "ST_ClipByBox2D("; } s << "\"" << geometryColumn_ << "\""; // ! ST_ClipByBox2D() if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz) { s << "," << sql_bbox(box) << ")"; } // ! ST_RemoveRepeatedPoints() s << "," << twkb_tolerance << ")"; // ! ST_Simplify(), with parameter to keep collapsed geometries s << "," << twkb_tolerance << ",true)"; // ! ST_TWKB() s << "," << twkb_rounding << ") AS geom"; } else { s << "SELECT ST_AsBinary("; if (simplify_geometries_) { s << "ST_Simplify("; } if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz) { s << "ST_ClipByBox2D("; } if (simplify_geometries_ && simplify_snap_ratio_ > 0.0) { s<< "ST_SnapToGrid("; } // Geometry column! s << "\"" << geometryColumn_ << "\""; // ! ST_SnapToGrid() if (simplify_geometries_ && simplify_snap_ratio_ > 0.0) { const double tolerance = px_sz * simplify_snap_ratio_; s << "," << tolerance << ")"; } // ! ST_ClipByBox2D() if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz) { s << "," << sql_bbox(box) << ")"; } // ! ST_Simplify() if (simplify_geometries_) { const double tolerance = px_sz * simplify_dp_ratio_; s << ", " << tolerance; // Add parameter to ST_Simplify to keep collapsed geometries if (simplify_dp_preserve_) { s << ", true"; } s << ")"; } // ! ST_AsBinary() s << ") AS geom"; } mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>(); 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(); if (! key_field_.empty()) { mapnik::sql_utils::quote_attr(s, key_field_); if (key_field_as_attribute_) { ctx->push(key_field_); } for (; pos != end; ++pos) { if (*pos != key_field_) { mapnik::sql_utils::quote_attr(s, *pos); ctx->push(*pos); } } } else { for (; pos != end; ++pos) { mapnik::sql_utils::quote_attr(s, *pos); ctx->push(*pos); } } std::string table_with_bbox = populate_tokens(table_, scale_denom, box, px_gw, px_gh, q.variables()); s << " FROM " << table_with_bbox; if (row_limit_ > 0) { s << " LIMIT " << row_limit_; } std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool, proc_ctx); return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty(), key_field_as_attribute_, twkb_encoding_); } return mapnik::make_invalid_featureset(); }
featureset_ptr spatialite_datasource::features(query const& q) const { if (!is_bound_) bind(); if (dataset_) { mapnik::box2d<double> const& e = q.get_bbox(); std::ostringstream s; 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(); while (pos != end) { s << ",\"" << *pos << "\""; ++pos; } s << " FROM "; std::string query (table_); /* todo throw if select * and key_field == rowid? or add schema support so sqlite throws */ if (has_spatial_index_) { /* Use rtree to limit record id's to a given bbox then a btree to pull the records for those ids. */ std::ostringstream spatial_sql; spatial_sql << std::setprecision(16); spatial_sql << " WHERE " << 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() << ")"; if (boost::algorithm::ifind_first(query, "WHERE")) { boost::algorithm::ireplace_first(query, "WHERE", spatial_sql.str() + " AND "); } else if (boost::algorithm::ifind_first(query, geometry_table_)) { boost::algorithm::ireplace_first(query, table_, table_ + " " + spatial_sql.str()); } /* support UNION queries */ // #if 0 if(boost::algorithm::ifind_first(query, "union")) { /* use spatial index for UNION query, too */ boost::algorithm::ireplace_last(query, "WHERE", spatial_sql.str() + " AND "); } // #endif } s << query ; if (row_limit_ > 0) { s << " LIMIT " << row_limit_; } if (row_offset_ > 0) { s << " OFFSET " << row_offset_; } #ifdef MAPNIK_DEBUG std::clog << "Spatialite Plugin: table_: " << table_ << "\n\n"; std::clog << "Spatialite Plugin: query:" << s.str() << "\n\n"; #endif boost::shared_ptr<sqlite_resultset> rs(dataset_->execute_query(s.str())); return boost::make_shared<spatialite_featureset>(rs, desc_.get_encoding(), format_, multiple_geometries_, using_subquery_); } return featureset_ptr(); }