pgraster: copy quoting and interpolation changes from postgis

This commit is contained in:
Mickey Rose 2017-02-09 15:23:39 +01:00
parent e35c1ca106
commit 428ba432b1
2 changed files with 164 additions and 187 deletions

View file

@ -41,10 +41,10 @@
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>
#pragma GCC diagnostic pop
// stl
#include <cfloat> // FLT_MAX
#include <string>
#include <algorithm>
#include <set>
@ -53,28 +53,19 @@
DATASOURCE_PLUGIN(pgraster_datasource)
const double pgraster_datasource::FMAX = std::numeric_limits<float>::max();
const std::string pgraster_datasource::RASTER_COLUMNS = "raster_columns";
const std::string pgraster_datasource::RASTER_OVERVIEWS = "raster_overviews";
const std::string pgraster_datasource::SPATIAL_REF_SYS = "spatial_ref_system";
using std::shared_ptr;
using mapnik::attribute_descriptor;
using mapnik::sql_utils::identifier;
using mapnik::sql_utils::literal;
using mapnik::value_integer;
namespace {
// TODO: move to sql_utils
std::string quote_ident(std::string& s) {
return "\"" + s + "\""; // TODO: escape internal quotes
}
};
pgraster_datasource::pgraster_datasource(parameters const& params)
: datasource(params),
table_(*params.get<std::string>("table", "")),
schema_(""),
raster_table_(*params.get<std::string>("raster_table", "")),
raster_field_(*params.get<std::string>("raster_field", "")),
key_field_(*params.get<std::string>("key_field", "")),
@ -94,10 +85,7 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
params.get<std::string>("user"),
params.get<std::string>("password"),
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!"),
re_tokens_("!(@?\\w+)!"), // matches !mapnik_var! or !@user_var!
pool_max_size_(*params_.get<value_integer>("max_size", 10)),
persist_connection_(*params.get<mapnik::boolean_type>("persist_connection", true)),
extent_from_subquery_(*params.get<mapnik::boolean_type>("extent_from_subquery", false)),
@ -152,13 +140,15 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
if (raster_table_.empty())
{
raster_table_ = mapnik::sql_utils::table_from_sql(table_);
mapnik::sql_utils::table_from_sql
(table_, parsed_schema_, parsed_table_);
// non-trivial subqueries (having no FROM) make it
// impossible to use overviews
// TODO: improve "table_from_sql" ?
if ( raster_table_[raster_table_.find_first_not_of(" \t\r\n")] == '(' )
auto nsp = table_.find_first_not_of(" \t\r\n");
if (nsp != std::string::npos && table_[nsp] == '(')
{
raster_table_.clear();
if ( use_overviews_ )
{
std::ostringstream err;
@ -176,12 +166,10 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
}
}
}
std::string::size_type idx = raster_table_.find_last_of('.');
if (idx != std::string::npos)
else
{
schema_ = raster_table_.substr(0, idx);
raster_table_ = raster_table_.substr(idx + 1);
mapnik::sql_utils::table_from_sql
(raster_table_, parsed_schema_, parsed_table_);
}
// If we do not know either the geometry_field or the srid or we
@ -194,10 +182,10 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
// the table parameter references a table, view, or subselect not
// registered in the geometry columns.
//
geometryColumn_ = mapnik::sql_utils::unquote_double(raster_field_);
if (!raster_table_.empty() && (
geometryColumn_ = mapnik::sql_utils::unquote_copy('"', raster_field_);
if (!parsed_table_.empty() && (
geometryColumn_.empty() || srid_ == 0 ||
(schema_.empty() && use_overviews_) ||
(parsed_schema_.empty() && use_overviews_) ||
! extent_initialized_
))
{
@ -213,21 +201,15 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
s << ", st_xmin(extent) xmin, st_ymin(extent) ymin"
<< ", st_xmax(extent) xmax, st_ymax(extent) ymax";
}
s << " FROM "
<< RASTER_COLUMNS << " WHERE r_table_name='"
<< mapnik::sql_utils::unquote_double(raster_table_)
<< "'";
if (! schema_.empty())
s << " FROM " << RASTER_COLUMNS
<< " WHERE r_table_name=" << literal(parsed_table_);
if (!parsed_schema_.empty())
{
s << " AND r_table_schema='"
<< mapnik::sql_utils::unquote_double(schema_)
<< "'";
s << " AND r_table_schema=" << literal(parsed_schema_);
}
if (! raster_field_.empty())
if (!geometryColumn_.empty())
{
s << " AND r_raster_column='"
<< mapnik::sql_utils::unquote_double(raster_field_)
<< "'";
s << " AND r_raster_column=" << literal(geometryColumn_);
}
MAPNIK_LOG_DEBUG(pgraster) <<
"pgraster_datasource: running query " << s.str();
@ -265,9 +247,9 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
}
}
}
if ( schema_.empty() )
if (parsed_schema_.empty())
{
schema_ = rs->getValue("r_table_schema");
parsed_schema_ = rs->getValue("r_table_schema");
}
}
else
@ -288,8 +270,10 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
{
s.str("");
s << "SELECT ST_SRID(\"" << geometryColumn_ << "\") AS srid FROM "
<< populate_tokens(table_) << " WHERE \"" << geometryColumn_ << "\" IS NOT NULL LIMIT 1;";
s << "SELECT ST_SRID(" << identifier(geometryColumn_)
<< ") AS srid FROM " << populate_tokens(table_)
<< " WHERE " << identifier(geometryColumn_)
<< " IS NOT NULL LIMIT 1";
shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
if (rs->next())
@ -314,13 +298,13 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
if ( use_overviews_ )
{
std::ostringstream err;
if ( schema_.empty() )
if (parsed_schema_.empty())
{
err << "Pgraster Plugin: unable to lookup available table"
<< " overviews due to unknown schema";
throw mapnik::datasource_exception(err.str());
}
if ( geometryColumn_.empty() )
if (geometryColumn_.empty())
{
err << "Pgraster Plugin: unable to lookup available table"
<< " overviews due to unknown column name";
@ -337,13 +321,10 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
" raster_overviews o,"
" raster_columns r "
"where"
" o.r_table_schema = '"
<< mapnik::sql_utils::unquote_double(schema_)
<< "' and o.r_table_name = '"
<< mapnik::sql_utils::unquote_double(raster_table_)
<< "' and o.r_raster_column = '"
<< mapnik::sql_utils::unquote_double(geometryColumn_)
<< "' and r.r_table_schema = o.o_table_schema"
" o.r_table_schema = " << literal(parsed_schema_)
<< " and o.r_table_name = " << literal(parsed_table_)
<< " and o.r_raster_column = " << literal(geometryColumn_)
<< " and r.r_table_schema = o.o_table_schema"
" and r.r_table_name = o.o_table_name"
" and r.r_raster_column = o.o_raster_column"
" ORDER BY scl ASC";
@ -373,7 +354,7 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
rs->close();
if ( overviews_.empty() ) {
MAPNIK_LOG_DEBUG(pgraster) << "pgraster_datasource: no overview found for "
<< schema_ << "." << raster_table_ << "." << geometryColumn_;
<< parsed_schema_ << "." << parsed_table_ << "." << geometryColumn_;
}
}
@ -390,18 +371,15 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
"WHERE a.attnum > 0 AND a.attrelid = c.oid "
"AND a.atttypid = t.oid AND c.relnamespace = n.oid "
"AND c.oid = i.indrelid AND i.indisprimary = 't' "
"AND t.typname !~ '^geom' AND c.relname ="
<< " '" << mapnik::sql_utils::unquote_double(raster_table_) << "' "
"AND t.typname !~ '^geom' AND c.relname = " << literal(parsed_table_) << " "
//"AND a.attnum = ANY (i.indkey) " // postgres >= 8.1
<< "AND (i.indkey[0]=a.attnum OR i.indkey[1]=a.attnum OR i.indkey[2]=a.attnum "
"OR i.indkey[3]=a.attnum OR i.indkey[4]=a.attnum OR i.indkey[5]=a.attnum "
"OR i.indkey[6]=a.attnum OR i.indkey[7]=a.attnum OR i.indkey[8]=a.attnum "
"OR i.indkey[9]=a.attnum) ";
if (! schema_.empty())
if (!parsed_schema_.empty())
{
s << "AND n.nspname='"
<< mapnik::sql_utils::unquote_double(schema_)
<< "' ";
s << "AND n.nspname=" << literal(parsed_schema_) << ' ';
}
s << "ORDER BY a.attnum";
@ -420,7 +398,7 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
key_field_ = std::string(key_field_string);
MAPNIK_LOG_DEBUG(pgraster) << "pgraster_datasource: auto-detected key field of '"
<< key_field_ << "' on table '" << raster_table_ << "'";
<< key_field_ << "' on table '" << parsed_table_ << "'";
}
}
else
@ -431,7 +409,7 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
err << "PostGIS Plugin: Error: '"
<< rs_key->getValue(0)
<< "' on table '"
<< raster_table_
<< parsed_table_
<< "' is not a valid integer primary key field\n";
throw mapnik::datasource_exception(err.str());
}
@ -451,9 +429,11 @@ pgraster_datasource::pgraster_datasource(parameters const& params)
// but still not known at this point, then throw
if (*autodetect_key_field && key_field_.empty())
{
throw mapnik::datasource_exception(std::string("PostGIS Plugin: Error: primary key required")
+ " but could not be detected for table '" +
raster_table_ + "', please supply 'key_field' option to specify field to use for primary key");
throw mapnik::datasource_exception(
"PostGIS Plugin: Error: primary key required"
" but could not be detected for table '"
+ parsed_table_ + "', please supply 'key_field'"
" option to specify field to use for primary key");
}
if (srid_ == 0)
@ -639,77 +619,76 @@ std::string pgraster_datasource::sql_bbox(box2d<double> const& env) const
std::string pgraster_datasource::populate_tokens(std::string const& sql) const
{
std::string populated_sql = sql;
if (boost::algorithm::icontains(sql, bbox_token_))
{
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_))
{
std::ostringstream ss;
ss << 0;
boost::algorithm::replace_all(populated_sql, pixel_width_token_, ss.str());
}
if (boost::algorithm::icontains(sql, pixel_height_token_))
{
std::ostringstream ss;
ss << 0;
boost::algorithm::replace_all(populated_sql, pixel_height_token_, ss.str());
}
return populated_sql;
return populate_tokens(sql, FLT_MAX,
box2d<double>(-FLT_MAX, -FLT_MAX, FLT_MAX, FLT_MAX),
0, 0, mapnik::attributes{}, false);
}
std::string pgraster_datasource::populate_tokens(std::string const& sql, double scale_denom, box2d<double> const& env, double pixel_width, double pixel_height) const
std::string pgraster_datasource::populate_tokens(std::string const& sql,
double scale_denom,
box2d<double> const& env,
double pixel_width,
double pixel_height,
mapnik::attributes const& vars,
bool intersect) const
{
std::string populated_sql = sql;
std::string box = sql_bbox(env);
std::ostringstream populated_sql;
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;
ss << scale_denom;
boost::algorithm::replace_all(populated_sql, scale_denom_token_, ss.str());
populated_sql.write(start, m[0].first - start);
start = m[0].second;
auto m1 = boost::make_iterator_range(m[1].first, m[1].second);
if (m1.front() == '@')
{
std::string var_name(m1.begin() + 1, m1.end());
auto itr = vars.find(var_name);
if (itr != vars.end())
{
auto var_value = itr->second.to_string();
populated_sql << literal(var_value);
}
else
{
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!
}
}
if (boost::algorithm::icontains(sql, pixel_width_token_))
{
std::ostringstream ss;
ss << pixel_width;
boost::algorithm::replace_all(populated_sql, pixel_width_token_, ss.str());
}
populated_sql.write(start, end - start);
if (boost::algorithm::icontains(sql, pixel_height_token_))
if (intersect)
{
std::ostringstream ss;
ss << pixel_height;
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);
return populated_sql;
}
else
{
std::ostringstream s;
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_))
{
@ -717,11 +696,13 @@ std::string pgraster_datasource::populate_tokens(std::string const& sql, double
}
else
{
s << " WHERE \"" << geometryColumn_ << "\" && " << box;
populated_sql << " WHERE "
<< identifier(geometryColumn_) << " && "
<< sql_bbox(env);
}
return populated_sql + s.str();
}
return populated_sql.str();
}
@ -849,19 +830,19 @@ featureset_ptr pgraster_datasource::features_with_context(query const& q,process
std::ostringstream s_error;
s_error << "PostGIS: geometry name lookup failed for table '";
if (! schema_.empty())
if (!parsed_schema_.empty())
{
s_error << schema_ << ".";
s_error << parsed_schema_ << ".";
}
s_error << raster_table_
s_error << parsed_table_
<< "'. Please manually provide the 'geometry_field' parameter or add an entry "
<< "in the geometry_columns for '";
if (! schema_.empty())
if (!parsed_schema_.empty())
{
s_error << schema_ << ".";
s_error << parsed_schema_ << ".";
}
s_error << raster_table_ << "'.";
s_error << parsed_table_ << "'.";
throw mapnik::datasource_exception(s_error.str());
}
@ -874,6 +855,7 @@ featureset_ptr pgraster_datasource::features_with_context(query const& q,process
std::string table_with_bbox;
std::string col = geometryColumn_;
table_with_bbox = table_; // possibly a subquery
if ( use_overviews_ && !overviews_.empty()) {
std::string sch = overviews_[0].schema;
@ -901,18 +883,12 @@ featureset_ptr pgraster_datasource::features_with_context(query const& q,process
<< " 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);
boost::algorithm::replace_all(table_with_bbox, parsed_table_, tab);
boost::algorithm::replace_all(table_with_bbox, parsed_schema_, sch);
boost::algorithm::replace_all(table_with_bbox, geometryColumn_, col);
}
table_with_bbox = populate_tokens(table_with_bbox, scale_denom, box,
px_gw, px_gh, q.variables());
std::ostringstream s;
@ -924,21 +900,21 @@ featureset_ptr pgraster_datasource::features_with_context(query const& q,process
if (clip_rasters_) s << "ST_Clip(";
s << "\"" << col << "\"";
s << identifier(col);
if (clip_rasters_) {
s << ", ST_Expand(" << sql_bbox(box)
<< ", greatest(abs(ST_ScaleX(\""
<< col << "\")), abs(ST_ScaleY(\""
<< col << "\")))))";
<< ", greatest(abs(ST_ScaleX("
<< identifier(col) << ")), abs(ST_ScaleY("
<< identifier(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))";
s << ", least(1.0, abs(ST_ScaleX(" << identifier(col)
<< "))::float8/" << scale
<< "), least(1.0, abs(ST_ScaleY(" << identifier(col)
<< "))::float8/" << scale << "))";
// TODO: if band_ is given, we'll interpret as indexed so
// the rescaling must NOT ruin it (use algorithm mode!)
}
@ -954,14 +930,14 @@ featureset_ptr pgraster_datasource::features_with_context(query const& q,process
if (! key_field_.empty())
{
mapnik::sql_utils::quote_attr(s, key_field_);
s << ',' << identifier(key_field_);
ctx->push(key_field_);
for (; pos != end; ++pos)
{
if (*pos != key_field_)
{
mapnik::sql_utils::quote_attr(s, *pos);
s << ',' << identifier(*pos);
ctx->push(*pos);
}
}
@ -970,7 +946,7 @@ featureset_ptr pgraster_datasource::features_with_context(query const& q,process
{
for (; pos != end; ++pos)
{
mapnik::sql_utils::quote_attr(s, *pos);
s << ',' << identifier(*pos);
ctx->push(*pos);
}
}
@ -1017,39 +993,39 @@ featureset_ptr pgraster_datasource::features_at_point(coord2d const& pt, double
std::ostringstream s_error;
s_error << "PostGIS: geometry name lookup failed for table '";
if (! schema_.empty())
if (!parsed_schema_.empty())
{
s_error << schema_ << ".";
s_error << parsed_schema_ << ".";
}
s_error << raster_table_
s_error << parsed_table_
<< "'. Please manually provide the 'geometry_field' parameter or add an entry "
<< "in the geometry_columns for '";
if (! schema_.empty())
if (!parsed_schema_.empty())
{
s_error << schema_ << ".";
s_error << parsed_schema_ << ".";
}
s_error << raster_table_ << "'.";
s_error << parsed_table_ << "'.";
throw mapnik::datasource_exception(s_error.str());
}
std::ostringstream s;
s << "SELECT ST_AsBinary(\"" << geometryColumn_ << "\") AS geom";
s << "SELECT ST_AsBinary(" << identifier(geometryColumn_) << ") AS geom";
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
auto const& desc = desc_.get_descriptors();
if (!key_field_.empty())
{
mapnik::sql_utils::quote_attr(s, key_field_);
s << ',' << identifier(key_field_);
ctx->push(key_field_);
for (auto const& attr_info : desc)
{
std::string const& name = attr_info.get_name();
if (name != key_field_)
{
mapnik::sql_utils::quote_attr(s, name);
s << ',' << identifier(name);
ctx->push(name);
}
}
@ -1059,13 +1035,14 @@ featureset_ptr pgraster_datasource::features_at_point(coord2d const& pt, double
for (auto const& attr_info : desc)
{
std::string const& name = attr_info.get_name();
mapnik::sql_utils::quote_attr(s, name);
s << ',' << identifier(name);
ctx->push(name);
}
}
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);
std::string table_with_bbox = populate_tokens(table_, FLT_MAX, box, 0, 0,
mapnik::attributes{});
s << " FROM " << table_with_bbox;
@ -1098,9 +1075,9 @@ box2d<double> pgraster_datasource::envelope() const
{
std::ostringstream s;
std::string col = mapnik::sql_utils::unquote_double(geometryColumn_);
std::string sch = mapnik::sql_utils::unquote_double(schema_);
std::string tab = mapnik::sql_utils::unquote_double(raster_table_);
std::string col = geometryColumn_;
std::string sch = parsed_schema_;
std::string tab = parsed_table_;
if ( ! overviews_.empty() )
{
@ -1120,7 +1097,7 @@ box2d<double> pgraster_datasource::envelope() const
{
s_error << sch << ".";
}
s_error << raster_table_ << "' because we cannot determine the raster field name."
s_error << parsed_table_ << "' because we cannot determine the raster field name."
<< "\nPlease provide either an 'extent' parameter to skip this query, "
<< "a 'raster_field' and/or 'raster_table' parameter, or add "
<< "standard constraints to your raster table.";
@ -1140,20 +1117,20 @@ box2d<double> pgraster_datasource::envelope() const
throw mapnik::datasource_exception("Pgraster Plugin: " + s_error.str());
}
s << "SELECT ST_XMin(ext),ST_YMin(ext),ST_XMax(ext),ST_YMax(ext)"
<< " FROM (SELECT ST_Estimated_Extent('";
<< " FROM (SELECT ST_Estimated_Extent(";
if (! sch.empty())
{
s << mapnik::sql_utils::unquote_double(sch) << "','";
s << literal(sch) << ',';
}
s << mapnik::sql_utils::unquote_double(tab) << "','"
<< mapnik::sql_utils::unquote_double(col) << "') as ext) as tmp";
s << literal(tab) << ','
<< literal(col) << ") as ext) as tmp";
}
else
{
s << "SELECT ST_XMin(ext),ST_YMin(ext),ST_XMax(ext),ST_YMax(ext)"
<< " FROM (SELECT ST_Extent(" << quote_ident(col) << "::geometry) as ext from ";
<< " FROM (SELECT ST_Extent(" << identifier(col) << "::geometry) as ext from ";
if (extent_from_subquery_)
{
@ -1165,12 +1142,12 @@ box2d<double> pgraster_datasource::envelope() const
{
if (! sch.empty())
{
s << quote_ident(sch) << ".";
s << identifier(sch) << ".";
}
// but if the subquery does not limit records then querying the
// actual table will be faster as indexes can be used
s << quote_ident(tab) << ") as tmp";
s << identifier(tab) << ") as tmp";
}
}

View file

@ -42,6 +42,7 @@
#include <boost/optional.hpp>
// stl
#include <regex>
#include <vector>
#include <string>
#include <memory>
@ -90,24 +91,26 @@ public:
private:
std::string sql_bbox(box2d<double> const& env) const;
std::string populate_tokens(std::string const& sql, double scale_denom, box2d<double> const& env, double pixel_width, double pixel_height) const;
std::string populate_tokens(std::string const& sql, double scale_denom,
box2d<double> const& env,
double pixel_width, double pixel_height,
mapnik::attributes const& vars,
bool intersect = true) 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;
static const std::string RASTER_COLUMNS;
static const std::string RASTER_OVERVIEWS;
static const std::string SPATIAL_REF_SYS;
static const double FMAX;
const std::string uri_;
const std::string username_;
const std::string password_;
// table name (schema qualified or not) or subquery
const std::string table_;
// schema name (possibly extracted from table_)
std::string schema_;
// table name (possibly extracted from table_)
std::string raster_table_;
const std::string raster_table_; // possibly schema-qualified
const std::string raster_field_;
std::string parsed_schema_; // extracted from raster_table_ or table_
std::string parsed_table_; // extracted from raster_table_ or table_
std::string key_field_;
mapnik::value_integer cursor_fetch_size_;
mapnik::value_integer row_limit_;
@ -129,10 +132,7 @@ private:
bool clip_rasters_;
layer_descriptor desc_;
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_;
std::regex re_tokens_;
int pool_max_size_;
bool persist_connection_;
bool extent_from_subquery_;