postgis: pass floating-point numbers to queries in hexfloat format

This commit is contained in:
Mickey Rose 2019-09-24 23:58:59 +02:00
parent f365a9d2e4
commit 6c2faf346b
4 changed files with 59 additions and 21 deletions

View file

@ -34,6 +34,48 @@
namespace mapnik { namespace pgcommon {
// sql_float4
struct sql_float4
{
float value;
};
inline sql_float4 sql_float(float value)
{
return {value};
}
inline std::ostream & operator << (std::ostream & os, sql_float4 sf)
{
char const fmt[] = "float4 '%a'";
char buf[sizeof(fmt) + 25];
int len = std::snprintf(buf, sizeof(buf), fmt, sf.value);
return os.write(buf, std::min(len, int(sizeof(buf)) - 1));
}
// sql_float8
struct sql_float8
{
double value;
};
inline sql_float8 sql_float(double value)
{
return {value};
}
inline std::ostream & operator << (std::ostream & os, sql_float8 sf)
{
char const fmt[] = "float8 '%a'";
char buf[sizeof(fmt) + 25];
int len = std::snprintf(buf, sizeof(buf), fmt, sf.value);
return os.write(buf, std::min(len, int(sizeof(buf)) - 1));
}
// sql_bbox
struct sql_bbox : box2d<double>

View file

@ -60,6 +60,7 @@ const std::string pgraster_datasource::SPATIAL_REF_SYS = "spatial_ref_system";
using std::shared_ptr;
using mapnik::attribute_descriptor;
using mapnik::pgcommon::sql_bbox;
using mapnik::pgcommon::sql_float;
using mapnik::sql_utils::identifier;
using mapnik::sql_utils::literal;
using mapnik::value_integer;
@ -611,9 +612,6 @@ std::string pgraster_datasource::populate_tokens(std::string const& sql,
char const* start = sql.data();
char const* end = start + sql.size();
populated_sql.precision(16);
populated_sql << std::showpoint;
while (std::regex_search(start, end, m, re_tokens_))
{
populated_sql.write(start, m[0].first - start);
@ -641,15 +639,15 @@ std::string pgraster_datasource::populate_tokens(std::string const& sql,
}
else if (boost::algorithm::equals(m1, "pixel_height"))
{
populated_sql << pixel_height;
populated_sql << sql_float(pixel_height);
}
else if (boost::algorithm::equals(m1, "pixel_width"))
{
populated_sql << pixel_width;
populated_sql << sql_float(pixel_width);
}
else if (boost::algorithm::equals(m1, "scale_denominator"))
{
populated_sql << scale_denom;
populated_sql << sql_float(scale_denom);
}
else
{
@ -889,9 +887,9 @@ featureset_ptr pgraster_datasource::features_with_context(query const& q,process
if (prescale_rasters_) {
const double scale = std::min(px_gw, px_gh);
s << ", least(1.0, abs(ST_ScaleX(" << identifier(col)
<< "))::float8/" << scale
<< "))::float8/" << sql_float(scale)
<< "), least(1.0, abs(ST_ScaleY(" << identifier(col)
<< "))::float8/" << scale << "))";
<< "))::float8/" << sql_float(scale) << "))";
// TODO: if band_ is given, we'll interpret as indexed so
// the rescaling must NOT ruin it (use algorithm mode!)
}

View file

@ -56,6 +56,7 @@ const std::string postgis_datasource::SPATIAL_REF_SYS = "spatial_ref_system";
using std::shared_ptr;
using mapnik::attribute_descriptor;
using mapnik::pgcommon::sql_bbox;
using mapnik::pgcommon::sql_float;
using mapnik::sql_utils::identifier;
using mapnik::sql_utils::literal;
@ -521,9 +522,6 @@ std::string postgis_datasource::populate_tokens(
char const* start = sql.data();
char const* end = start + sql.size();
populated_sql.precision(16);
populated_sql << std::showpoint;
while (std::regex_search(start, end, m, re_tokens_))
{
populated_sql.write(start, m[0].first - start);
@ -551,15 +549,15 @@ std::string postgis_datasource::populate_tokens(
}
else if (boost::algorithm::equals(m1, "pixel_height"))
{
populated_sql << pixel_height;
populated_sql << sql_float(pixel_height);
}
else if (boost::algorithm::equals(m1, "pixel_width"))
{
populated_sql << pixel_width;
populated_sql << sql_float(pixel_width);
}
else if (boost::algorithm::equals(m1, "scale_denominator"))
{
populated_sql << scale_denom;
populated_sql << sql_float(scale_denom);
}
else
{
@ -779,9 +777,9 @@ featureset_ptr postgis_datasource::features_with_context(query const& q,processo
}
// ! ST_RemoveRepeatedPoints()
s << "," << twkb_tolerance << ")";
s << "," << sql_float(twkb_tolerance) << ")";
// ! ST_Simplify(), with parameter to keep collapsed geometries
s << "," << twkb_tolerance << ",true)";
s << "," << sql_float(twkb_tolerance) << ",true)";
// ! ST_TWKB()
s << "," << twkb_rounding << ") AS geom";
}
@ -808,7 +806,7 @@ featureset_ptr postgis_datasource::features_with_context(query const& q,processo
if (simplify_geometries_ && simplify_snap_ratio_ > 0.0)
{
const double tolerance = px_sz * simplify_snap_ratio_;
s << "," << tolerance << ")";
s << "," << sql_float(tolerance) << ")";
}
// ! ST_ClipByBox2D()
@ -821,7 +819,7 @@ featureset_ptr postgis_datasource::features_with_context(query const& q,processo
if (simplify_geometries_)
{
const double tolerance = px_sz * simplify_dp_ratio_;
s << ", " << tolerance;
s << ", " << sql_float(tolerance);
// Add parameter to ST_Simplify to keep collapsed geometries
if (simplify_dp_preserve_)
{

View file

@ -316,9 +316,9 @@ TEST_CASE("postgis") {
auto feature = featureset->next();
CHECKED_IF(feature != nullptr)
{
CHECK(feature->get("t_pixel_width").to_string() == "numeric");
CHECK(feature->get("t_pixel_height").to_string() == "numeric");
CHECK(feature->get("t_scale_denom").to_string() == "numeric");
CHECK(feature->get("t_pixel_width").to_string() == "double precision");
CHECK(feature->get("t_pixel_height").to_string() == "double precision");
CHECK(feature->get("t_scale_denom").to_string() == "double precision");
}
}