postgis: revamp substitution of special tokens in query
- replace boost::regex with std::regex - use regex to match both !mapnikvar! and !@uservar! - no longer support @uservar (without surrounding !s)
This commit is contained in:
parent
195c3e14ce
commit
d331b9d66a
3 changed files with 69 additions and 105 deletions
|
@ -52,7 +52,6 @@ libraries = copy(plugin_env['LIBS'])
|
||||||
|
|
||||||
if env['PLUGIN_LINKING'] == 'shared':
|
if env['PLUGIN_LINKING'] == 'shared':
|
||||||
libraries.append('boost_system%s' % env['BOOST_APPEND'])
|
libraries.append('boost_system%s' % env['BOOST_APPEND'])
|
||||||
libraries.append('boost_regex%s' % env['BOOST_APPEND'])
|
|
||||||
libraries.insert(0,env['MAPNIK_NAME'])
|
libraries.insert(0,env['MAPNIK_NAME'])
|
||||||
libraries.append(env['ICU_LIB_NAME'])
|
libraries.append(env['ICU_LIB_NAME'])
|
||||||
|
|
||||||
|
|
|
@ -38,11 +38,10 @@
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#include <mapnik/warning_ignore.hpp>
|
#include <mapnik/warning_ignore.hpp>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/tokenizer.hpp>
|
|
||||||
#include <boost/regex.hpp>
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
// stl
|
// stl
|
||||||
|
#include <cfloat> // FLT_MAX
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -52,12 +51,13 @@
|
||||||
|
|
||||||
DATASOURCE_PLUGIN(postgis_datasource)
|
DATASOURCE_PLUGIN(postgis_datasource)
|
||||||
|
|
||||||
const double postgis_datasource::FMAX = std::numeric_limits<float>::max();
|
|
||||||
const std::string postgis_datasource::GEOMETRY_COLUMNS = "geometry_columns";
|
const std::string postgis_datasource::GEOMETRY_COLUMNS = "geometry_columns";
|
||||||
const std::string postgis_datasource::SPATIAL_REF_SYS = "spatial_ref_system";
|
const std::string postgis_datasource::SPATIAL_REF_SYS = "spatial_ref_system";
|
||||||
|
|
||||||
using std::shared_ptr;
|
using std::shared_ptr;
|
||||||
using mapnik::attribute_descriptor;
|
using mapnik::attribute_descriptor;
|
||||||
|
using mapnik::sql_utils::identifier;
|
||||||
|
using mapnik::sql_utils::literal;
|
||||||
|
|
||||||
postgis_datasource::postgis_datasource(parameters const& params)
|
postgis_datasource::postgis_datasource(parameters const& params)
|
||||||
: datasource(params),
|
: datasource(params),
|
||||||
|
@ -79,10 +79,6 @@ postgis_datasource::postgis_datasource(parameters const& params)
|
||||||
params.get<std::string>("user"),
|
params.get<std::string>("user"),
|
||||||
params.get<std::string>("password"),
|
params.get<std::string>("password"),
|
||||||
params.get<std::string>("connect_timeout", "4")),
|
params.get<std::string>("connect_timeout", "4")),
|
||||||
bbox_token_("!bbox!"),
|
|
||||||
scale_denom_token_("!scale_denominator!"),
|
|
||||||
pixel_width_token_("!pixel_width!"),
|
|
||||||
pixel_height_token_("!pixel_height!"),
|
|
||||||
pool_max_size_(*params_.get<mapnik::value_integer>("max_size", 10)),
|
pool_max_size_(*params_.get<mapnik::value_integer>("max_size", 10)),
|
||||||
persist_connection_(*params.get<mapnik::boolean_type>("persist_connection", true)),
|
persist_connection_(*params.get<mapnik::boolean_type>("persist_connection", true)),
|
||||||
extent_from_subquery_(*params.get<mapnik::boolean_type>("extent_from_subquery", false)),
|
extent_from_subquery_(*params.get<mapnik::boolean_type>("extent_from_subquery", false)),
|
||||||
|
@ -99,8 +95,7 @@ postgis_datasource::postgis_datasource(parameters const& params)
|
||||||
simplify_prefilter_(*params_.get<mapnik::value_double>("simplify_prefilter", 0.0)),
|
simplify_prefilter_(*params_.get<mapnik::value_double>("simplify_prefilter", 0.0)),
|
||||||
simplify_dp_preserve_(false),
|
simplify_dp_preserve_(false),
|
||||||
simplify_clip_resolution_(*params_.get<mapnik::value_double>("simplify_clip_resolution", 0.0)),
|
simplify_clip_resolution_(*params_.get<mapnik::value_double>("simplify_clip_resolution", 0.0)),
|
||||||
// TODO - use for known tokens too: "(@\\w+|!\\w+!)"
|
re_tokens_("!(@?\\w+)!"), // matches !mapnik_var! or !@user_var!
|
||||||
pattern_(boost::regex("(@\\w+)",boost::regex::normal | boost::regbase::icase)),
|
|
||||||
// params below are for testing purposes only and may be removed at any time
|
// params below are for testing purposes only and may be removed at any time
|
||||||
intersect_min_scale_(*params.get<mapnik::value_integer>("intersect_min_scale", 0)),
|
intersect_min_scale_(*params.get<mapnik::value_integer>("intersect_min_scale", 0)),
|
||||||
intersect_max_scale_(*params.get<mapnik::value_integer>("intersect_max_scale", 0)),
|
intersect_max_scale_(*params.get<mapnik::value_integer>("intersect_max_scale", 0)),
|
||||||
|
@ -551,43 +546,9 @@ std::string postgis_datasource::sql_bbox(box2d<double> const& env) const
|
||||||
|
|
||||||
std::string postgis_datasource::populate_tokens(std::string const& sql) const
|
std::string postgis_datasource::populate_tokens(std::string const& sql) const
|
||||||
{
|
{
|
||||||
std::string populated_sql = sql;
|
return populate_tokens(sql, FLT_MAX,
|
||||||
|
box2d<double>(-FLT_MAX, -FLT_MAX, FLT_MAX, FLT_MAX),
|
||||||
if (boost::algorithm::icontains(sql, bbox_token_))
|
0, 0, mapnik::attributes{}, false);
|
||||||
{
|
|
||||||
box2d<double> max_env(-1.0 * FMAX, -1.0 * FMAX, FMAX, FMAX);
|
|
||||||
const std::string max_box = sql_bbox(max_env);
|
|
||||||
boost::algorithm::replace_all(populated_sql, bbox_token_, max_box);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boost::algorithm::icontains(sql, scale_denom_token_))
|
|
||||||
{
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << FMAX;
|
|
||||||
boost::algorithm::replace_all(populated_sql, scale_denom_token_, ss.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boost::algorithm::icontains(sql, pixel_width_token_))
|
|
||||||
{
|
|
||||||
boost::algorithm::replace_all(populated_sql, pixel_width_token_, "0");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boost::algorithm::icontains(sql, pixel_height_token_))
|
|
||||||
{
|
|
||||||
boost::algorithm::replace_all(populated_sql, pixel_height_token_, "0");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string copy2 = populated_sql;
|
|
||||||
std::list<std::string> l;
|
|
||||||
boost::regex_split(std::back_inserter(l), copy2, pattern_);
|
|
||||||
if (!l.empty())
|
|
||||||
{
|
|
||||||
for (auto const & token: l)
|
|
||||||
{
|
|
||||||
boost::algorithm::replace_all(populated_sql, token, "null");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return populated_sql;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string postgis_datasource::populate_tokens(
|
std::string postgis_datasource::populate_tokens(
|
||||||
|
@ -596,43 +557,66 @@ std::string postgis_datasource::populate_tokens(
|
||||||
box2d<double> const& env,
|
box2d<double> const& env,
|
||||||
double pixel_width,
|
double pixel_width,
|
||||||
double pixel_height,
|
double pixel_height,
|
||||||
mapnik::attributes const& vars) const
|
mapnik::attributes const& vars,
|
||||||
|
bool intersect) const
|
||||||
{
|
{
|
||||||
std::string populated_sql = sql;
|
std::ostringstream populated_sql;
|
||||||
std::string box = sql_bbox(env);
|
std::cmatch m;
|
||||||
|
char const* start = sql.data();
|
||||||
|
char const* end = start + sql.size();
|
||||||
|
|
||||||
if (boost::algorithm::icontains(populated_sql, scale_denom_token_))
|
while (std::regex_search(start, end, m, re_tokens_))
|
||||||
{
|
{
|
||||||
std::ostringstream ss;
|
populated_sql.write(start, m[0].first - start);
|
||||||
ss << scale_denom;
|
start = m[0].second;
|
||||||
boost::algorithm::replace_all(populated_sql, scale_denom_token_, ss.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boost::algorithm::icontains(sql, pixel_width_token_))
|
auto m1 = boost::make_iterator_range(m[1].first, m[1].second);
|
||||||
|
if (m1.front() == '@')
|
||||||
{
|
{
|
||||||
std::ostringstream ss;
|
std::string var_name(m1.begin() + 1, m1.end());
|
||||||
ss << pixel_width;
|
auto itr = vars.find(var_name);
|
||||||
boost::algorithm::replace_all(populated_sql, pixel_width_token_, ss.str());
|
if (itr != vars.end())
|
||||||
}
|
|
||||||
|
|
||||||
if (boost::algorithm::icontains(sql, pixel_height_token_))
|
|
||||||
{
|
{
|
||||||
std::ostringstream ss;
|
auto var_value = itr->second.to_string();
|
||||||
ss << pixel_height;
|
populated_sql << literal(var_value);
|
||||||
boost::algorithm::replace_all(populated_sql, pixel_height_token_, ss.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boost::algorithm::icontains(populated_sql, bbox_token_))
|
|
||||||
{
|
|
||||||
boost::algorithm::replace_all(populated_sql, bbox_token_, box);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::ostringstream s;
|
populated_sql << "NULL"; // undefined @variable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (boost::algorithm::equals(m1, "bbox"))
|
||||||
|
{
|
||||||
|
populated_sql << sql_bbox(env);
|
||||||
|
intersect = false;
|
||||||
|
}
|
||||||
|
else if (boost::algorithm::equals(m1, "pixel_height"))
|
||||||
|
{
|
||||||
|
populated_sql << pixel_height;
|
||||||
|
}
|
||||||
|
else if (boost::algorithm::equals(m1, "pixel_width"))
|
||||||
|
{
|
||||||
|
populated_sql << pixel_width;
|
||||||
|
}
|
||||||
|
else if (boost::algorithm::equals(m1, "scale_denominator"))
|
||||||
|
{
|
||||||
|
populated_sql << scale_denom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
populated_sql << "NULL"; // unrecognized !token!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
populated_sql.write(start, end - start);
|
||||||
|
|
||||||
|
if (intersect)
|
||||||
|
{
|
||||||
if (intersect_min_scale_ > 0 && (scale_denom <= intersect_min_scale_))
|
if (intersect_min_scale_ > 0 && (scale_denom <= intersect_min_scale_))
|
||||||
{
|
{
|
||||||
s << " WHERE ST_Intersects(\"" << geometryColumn_ << "\"," << box << ")";
|
populated_sql << " WHERE ST_Intersects("
|
||||||
|
<< identifier(geometryColumn_) << ", "
|
||||||
|
<< sql_bbox(env) << ")";
|
||||||
}
|
}
|
||||||
else if (intersect_max_scale_ > 0 && (scale_denom >= intersect_max_scale_))
|
else if (intersect_max_scale_ > 0 && (scale_denom >= intersect_max_scale_))
|
||||||
{
|
{
|
||||||
|
@ -640,29 +624,13 @@ std::string postgis_datasource::populate_tokens(
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s << " WHERE \"" << geometryColumn_ << "\" && " << box;
|
populated_sql << " WHERE "
|
||||||
}
|
<< identifier(geometryColumn_) << " && "
|
||||||
populated_sql += s.str();
|
<< sql_bbox(env);
|
||||||
}
|
|
||||||
std::string copy2 = populated_sql;
|
|
||||||
std::list<std::string> l;
|
|
||||||
boost::regex_split(std::back_inserter(l), copy2, pattern_);
|
|
||||||
if (!l.empty())
|
|
||||||
{
|
|
||||||
for (auto const & token: l)
|
|
||||||
{
|
|
||||||
auto itr = vars.find(token.substr(1,std::string::npos));
|
|
||||||
if (itr != vars.end())
|
|
||||||
{
|
|
||||||
boost::algorithm::replace_all(populated_sql, token, itr->second.to_string());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
boost::algorithm::replace_all(populated_sql, token, "null");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return populated_sql;
|
return populated_sql.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1015,7 +983,8 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt, double t
|
||||||
}
|
}
|
||||||
|
|
||||||
box2d<double> box(pt.x - tol, pt.y - tol, pt.x + tol, pt.y + tol);
|
box2d<double> box(pt.x - tol, pt.y - tol, pt.x + tol, pt.y + tol);
|
||||||
std::string table_with_bbox = populate_tokens(table_, FMAX, box, 0, 0, mapnik::attributes());
|
std::string table_with_bbox = populate_tokens(table_, FLT_MAX, box, 0, 0,
|
||||||
|
mapnik::attributes{});
|
||||||
|
|
||||||
s << " FROM " << table_with_bbox;
|
s << " FROM " << table_with_bbox;
|
||||||
|
|
||||||
|
|
|
@ -37,10 +37,10 @@
|
||||||
|
|
||||||
// boost
|
// boost
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <boost/regex.hpp>
|
|
||||||
|
|
||||||
// stl
|
// stl
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <regex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -84,12 +84,12 @@ private:
|
||||||
box2d<double> const& env,
|
box2d<double> const& env,
|
||||||
double pixel_width,
|
double pixel_width,
|
||||||
double pixel_height,
|
double pixel_height,
|
||||||
mapnik::attributes const& vars) const;
|
mapnik::attributes const& vars,
|
||||||
|
bool intersect = true) const;
|
||||||
std::string populate_tokens(std::string const& sql) const;
|
std::string populate_tokens(std::string const& sql) const;
|
||||||
std::shared_ptr<IResultSet> get_resultset(std::shared_ptr<Connection> &conn, std::string const& sql, CnxPool_ptr const& pool, processor_context_ptr ctx= processor_context_ptr()) const;
|
std::shared_ptr<IResultSet> get_resultset(std::shared_ptr<Connection> &conn, std::string const& sql, CnxPool_ptr const& pool, processor_context_ptr ctx= processor_context_ptr()) const;
|
||||||
static const std::string GEOMETRY_COLUMNS;
|
static const std::string GEOMETRY_COLUMNS;
|
||||||
static const std::string SPATIAL_REF_SYS;
|
static const std::string SPATIAL_REF_SYS;
|
||||||
static const double FMAX;
|
|
||||||
|
|
||||||
const std::string uri_;
|
const std::string uri_;
|
||||||
const std::string username_;
|
const std::string username_;
|
||||||
|
@ -109,10 +109,6 @@ private:
|
||||||
bool simplify_geometries_;
|
bool simplify_geometries_;
|
||||||
layer_descriptor desc_;
|
layer_descriptor desc_;
|
||||||
ConnectionCreator<Connection> creator_;
|
ConnectionCreator<Connection> creator_;
|
||||||
const std::string bbox_token_;
|
|
||||||
const std::string scale_denom_token_;
|
|
||||||
const std::string pixel_width_token_;
|
|
||||||
const std::string pixel_height_token_;
|
|
||||||
int pool_max_size_;
|
int pool_max_size_;
|
||||||
bool persist_connection_;
|
bool persist_connection_;
|
||||||
bool extent_from_subquery_;
|
bool extent_from_subquery_;
|
||||||
|
@ -126,7 +122,7 @@ private:
|
||||||
mapnik::value_double simplify_prefilter_;
|
mapnik::value_double simplify_prefilter_;
|
||||||
bool simplify_dp_preserve_;
|
bool simplify_dp_preserve_;
|
||||||
mapnik::value_double simplify_clip_resolution_;
|
mapnik::value_double simplify_clip_resolution_;
|
||||||
boost::regex pattern_;
|
std::regex re_tokens_;
|
||||||
int intersect_min_scale_;
|
int intersect_min_scale_;
|
||||||
int intersect_max_scale_;
|
int intersect_max_scale_;
|
||||||
bool key_field_as_attribute_;
|
bool key_field_as_attribute_;
|
||||||
|
|
Loading…
Reference in a new issue