Beispiel #1
0
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();
}
Beispiel #3
0
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();
}
Beispiel #4
0
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();
}