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 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 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 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_); }
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 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(); }