641 lines
22 KiB
C++
641 lines
22 KiB
C++
/*****************************************************************************
|
|
*
|
|
* This file is part of Mapnik (c++ mapping toolkit)
|
|
*
|
|
* Copyright (C) 2015 Artem Pavlenko
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "occi_datasource.hpp"
|
|
#include "occi_featureset.hpp"
|
|
|
|
// mapnik
|
|
#include <mapnik/debug.hpp>
|
|
#include <mapnik/boolean.hpp>
|
|
#include <mapnik/sql_utils.hpp>
|
|
#include <mapnik/timer.hpp>
|
|
#include <mapnik/value_types.hpp>
|
|
|
|
// boost
|
|
#include <boost/algorithm/string.hpp>
|
|
#include <boost/tokenizer.hpp>
|
|
|
|
// stl
|
|
#include <string>
|
|
#include <algorithm>
|
|
#include <set>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
|
|
using mapnik::datasource;
|
|
using mapnik::parameters;
|
|
using mapnik::query;
|
|
using mapnik::featureset_ptr;
|
|
using mapnik::layer_descriptor;
|
|
using mapnik::attribute_descriptor;
|
|
using mapnik::datasource_exception;
|
|
using mapnik::box2d;
|
|
using mapnik::coord2d;
|
|
|
|
using oracle::occi::Environment;
|
|
using oracle::occi::Connection;
|
|
using oracle::occi::Statement;
|
|
using oracle::occi::ResultSet;
|
|
using oracle::occi::MetaData;
|
|
using oracle::occi::SQLException;
|
|
using oracle::occi::Type;
|
|
using oracle::occi::StatelessConnectionPool;
|
|
|
|
const double occi_datasource::FMAX = std::numeric_limits<double>::max();
|
|
const std::string occi_datasource::METADATA_TABLE = "USER_SDO_GEOM_METADATA";
|
|
|
|
DATASOURCE_PLUGIN(occi_datasource)
|
|
|
|
occi_datasource::occi_datasource(parameters const& params)
|
|
: datasource (params),
|
|
type_(datasource::Vector),
|
|
fields_(*params.get<std::string>("fields", "*")),
|
|
geometry_field_(*params.get<std::string>("geometry_field", "")),
|
|
srid_initialized_(false),
|
|
extent_initialized_(false),
|
|
bbox_token_("!bbox!"),
|
|
scale_denom_token_("!scale_denominator!"),
|
|
pixel_width_token_("!pixel_width!"),
|
|
pixel_height_token_("!pixel_height!"),
|
|
desc_(occi_datasource::name(), *params.get<std::string>("encoding", "utf-8")),
|
|
use_wkb_(*params.get<mapnik::boolean_type>("use_wkb", false)),
|
|
row_limit_(*params.get<mapnik::value_integer>("row_limit", 0)),
|
|
row_prefetch_(*params.get<mapnik::value_integer>("row_prefetch", 100)),
|
|
pool_(0),
|
|
conn_(0)
|
|
{
|
|
#ifdef MAPNIK_STATS
|
|
mapnik::progress_timer __stats__(std::clog, "occi_datasource::init");
|
|
#endif
|
|
|
|
if (! params.get<std::string>("user")) throw datasource_exception("OCCI Plugin: no <user> specified");
|
|
if (! params.get<std::string>("password")) throw datasource_exception("OCCI Plugin: no <password> specified");
|
|
if (! params.get<std::string>("host")) throw datasource_exception("OCCI Plugin: no <host> string specified");
|
|
|
|
boost::optional<std::string> table = params.get<std::string>("table");
|
|
if (! table)
|
|
{
|
|
throw datasource_exception("OCCI Plugin: no <table> parameter specified");
|
|
}
|
|
else
|
|
{
|
|
table_ = *table;
|
|
}
|
|
estimate_extent_ = *params.get<mapnik::boolean_type>("estimate_extent",false);
|
|
use_spatial_index_ = *params.get<mapnik::boolean_type>("use_spatial_index",true);
|
|
use_connection_pool_ = *params.get<mapnik::boolean_type>("use_connection_pool",true);
|
|
|
|
boost::optional<std::string> ext = params.get<std::string>("extent");
|
|
if (ext) extent_initialized_ = extent_.from_string(*ext);
|
|
|
|
boost::optional<mapnik::value_integer> srid = params.get<mapnik::value_integer>("srid");
|
|
if (srid)
|
|
{
|
|
srid_ = *srid;
|
|
srid_initialized_ = true;
|
|
}
|
|
|
|
// connect to environment
|
|
if (use_connection_pool_)
|
|
{
|
|
try
|
|
{
|
|
pool_ = occi_environment::instance().create_pool(
|
|
*params.get<std::string>("user"),
|
|
*params.get<std::string>("password"),
|
|
*params.get<std::string>("host"),
|
|
*params.get<mapnik::value_integer>("max_size", 5),
|
|
*params.get<mapnik::value_integer>("initial_size", 1),
|
|
1);
|
|
}
|
|
catch (SQLException& ex)
|
|
{
|
|
throw datasource_exception("OCCI Plugin: " + ex.getMessage());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
conn_ = occi_environment::instance().create_connection(
|
|
*params.get<std::string>("user"),
|
|
*params.get<std::string>("password"),
|
|
*params.get<std::string>("host"));
|
|
}
|
|
catch (SQLException& ex)
|
|
{
|
|
throw datasource_exception("OCCI Plugin: " + ex.getMessage());
|
|
}
|
|
}
|
|
|
|
// extract real table name
|
|
table_name_ = mapnik::sql_utils::table_from_sql(table_);
|
|
|
|
// get SRID and/or GEOMETRY_FIELD from metadata table only if we need to
|
|
if (! srid_initialized_ || geometry_field_ == "")
|
|
{
|
|
#ifdef MAPNIK_STATS
|
|
mapnik::progress_timer __stats__(std::clog, "occi_datasource::get_srid_and_geometry_field");
|
|
#endif
|
|
|
|
std::ostringstream s;
|
|
s << "SELECT srid, column_name FROM " << METADATA_TABLE << " WHERE";
|
|
s << " LOWER(table_name) = LOWER('" << table_name_ << "')";
|
|
|
|
if (geometry_field_ != "")
|
|
{
|
|
s << " AND LOWER(column_name) = LOWER('" << geometry_field_ << "')";
|
|
}
|
|
|
|
MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str();
|
|
|
|
try
|
|
{
|
|
occi_connection_ptr conn;
|
|
if (use_connection_pool_) conn.set_pool(pool_);
|
|
else conn.set_connection(conn_, false);
|
|
|
|
ResultSet* rs = conn.execute_query(s.str());
|
|
if (rs && rs->next ())
|
|
{
|
|
if (! srid_initialized_)
|
|
{
|
|
srid_ = rs->getInt(1);
|
|
srid_initialized_ = true;
|
|
}
|
|
|
|
if (geometry_field_ == "")
|
|
{
|
|
geometry_field_ = rs->getString(2);
|
|
}
|
|
}
|
|
}
|
|
catch (SQLException& ex)
|
|
{
|
|
throw datasource_exception("OCCI Plugin: " + ex.getMessage());
|
|
}
|
|
}
|
|
|
|
// get columns description
|
|
{
|
|
#ifdef MAPNIK_STATS
|
|
mapnik::progress_timer __stats__(std::clog, "occi_datasource::get_column_description");
|
|
#endif
|
|
|
|
std::ostringstream s;
|
|
s << "SELECT " << fields_ << " FROM (" << table_name_ << ") WHERE ROWNUM < 1";
|
|
|
|
MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str();
|
|
|
|
try
|
|
{
|
|
occi_connection_ptr conn;
|
|
if (use_connection_pool_) conn.set_pool(pool_);
|
|
else conn.set_connection(conn_, false);
|
|
|
|
ResultSet* rs = conn.execute_query(s.str());
|
|
if (rs)
|
|
{
|
|
std::vector<MetaData> listOfColumns = rs->getColumnListMetaData();
|
|
|
|
for (unsigned int i = 0; i < listOfColumns.size(); ++i)
|
|
{
|
|
MetaData columnObj = listOfColumns[i];
|
|
|
|
std::string fld_name = columnObj.getString(MetaData::ATTR_NAME);
|
|
int type_oid = columnObj.getInt(MetaData::ATTR_DATA_TYPE);
|
|
|
|
/*
|
|
int type_code = columnObj.getInt(MetaData::ATTR_TYPECODE);
|
|
if (type_code == OCCI_TYPECODE_OBJECT)
|
|
{
|
|
desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
|
|
continue;
|
|
}
|
|
*/
|
|
|
|
switch (type_oid)
|
|
{
|
|
case oracle::occi::OCCIBOOL:
|
|
desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Boolean));
|
|
break;
|
|
case oracle::occi::OCCIINT:
|
|
case oracle::occi::OCCIUNSIGNED_INT:
|
|
desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer));
|
|
break;
|
|
case oracle::occi::OCCIFLOAT:
|
|
case oracle::occi::OCCIBFLOAT:
|
|
case oracle::occi::OCCIDOUBLE:
|
|
case oracle::occi::OCCIBDOUBLE:
|
|
case oracle::occi::OCCINUMBER:
|
|
case oracle::occi::OCCI_SQLT_NUM:
|
|
desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double));
|
|
break;
|
|
case oracle::occi::OCCICHAR:
|
|
case oracle::occi::OCCISTRING:
|
|
case oracle::occi::OCCI_SQLT_AFC:
|
|
case oracle::occi::OCCI_SQLT_AVC:
|
|
case oracle::occi::OCCI_SQLT_CHR:
|
|
case oracle::occi::OCCI_SQLT_LNG:
|
|
case oracle::occi::OCCI_SQLT_LVC:
|
|
case oracle::occi::OCCI_SQLT_STR:
|
|
case oracle::occi::OCCI_SQLT_VCS:
|
|
case oracle::occi::OCCI_SQLT_VNU:
|
|
case oracle::occi::OCCI_SQLT_VBI:
|
|
case oracle::occi::OCCI_SQLT_VST:
|
|
case oracle::occi::OCCIROWID:
|
|
case oracle::occi::OCCI_SQLT_RDD:
|
|
case oracle::occi::OCCI_SQLT_RID:
|
|
case oracle::occi::OCCIDATE:
|
|
case oracle::occi::OCCI_SQLT_DAT:
|
|
case oracle::occi::OCCI_SQLT_DATE:
|
|
case oracle::occi::OCCI_SQLT_TIME:
|
|
case oracle::occi::OCCI_SQLT_TIME_TZ:
|
|
case oracle::occi::OCCITIMESTAMP:
|
|
case oracle::occi::OCCI_SQLT_TIMESTAMP:
|
|
case oracle::occi::OCCI_SQLT_TIMESTAMP_LTZ:
|
|
case oracle::occi::OCCI_SQLT_TIMESTAMP_TZ:
|
|
desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
|
|
break;
|
|
case oracle::occi::OCCIINTERVALDS:
|
|
case oracle::occi::OCCIINTERVALYM:
|
|
case oracle::occi::OCCI_SQLT_INTERVAL_YM:
|
|
case oracle::occi::OCCI_SQLT_INTERVAL_DS:
|
|
case oracle::occi::OCCIANYDATA:
|
|
case oracle::occi::OCCIBLOB:
|
|
case oracle::occi::OCCIBFILE:
|
|
case oracle::occi::OCCIBYTES:
|
|
case oracle::occi::OCCICLOB:
|
|
case oracle::occi::OCCIVECTOR:
|
|
case oracle::occi::OCCIMETADATA:
|
|
case oracle::occi::OCCIPOBJECT:
|
|
case oracle::occi::OCCIREF:
|
|
case oracle::occi::OCCIREFANY:
|
|
case oracle::occi::OCCISTREAM:
|
|
case oracle::occi::OCCICURSOR:
|
|
case oracle::occi::OCCI_SQLT_FILE:
|
|
case oracle::occi::OCCI_SQLT_CFILE:
|
|
case oracle::occi::OCCI_SQLT_REF:
|
|
case oracle::occi::OCCI_SQLT_CLOB:
|
|
case oracle::occi::OCCI_SQLT_BLOB:
|
|
case oracle::occi::OCCI_SQLT_RSET:
|
|
MAPNIK_LOG_WARN(occi) << "occi_datasource: Unsupported datatype "
|
|
<< occi_enums::resolve_datatype(type_oid)
|
|
<< " (type_oid=" << type_oid << ")";
|
|
break;
|
|
default:
|
|
MAPNIK_LOG_WARN(occi) << "occi_datasource: Unknown datatype "
|
|
<< "(type_oid=" << type_oid << ")";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (SQLException& ex)
|
|
{
|
|
throw datasource_exception(ex.getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
occi_datasource::~occi_datasource()
|
|
{
|
|
if (use_connection_pool_)
|
|
{
|
|
if (pool_ != 0)
|
|
{
|
|
occi_environment::instance().destroy_pool(pool_);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (conn_ != 0)
|
|
{
|
|
occi_environment::instance().destroy_connection(conn_);
|
|
}
|
|
}
|
|
}
|
|
|
|
const char * occi_datasource::name()
|
|
{
|
|
return "occi";
|
|
}
|
|
|
|
mapnik::datasource::datasource_t occi_datasource::type() const
|
|
{
|
|
return type_;
|
|
}
|
|
|
|
box2d<double> occi_datasource::envelope() const
|
|
{
|
|
if (extent_initialized_) return extent_;
|
|
|
|
double lox = 0.0, loy = 0.0, hix = 0.0, hiy = 0.0;
|
|
|
|
|
|
if (estimate_extent_)
|
|
{
|
|
#ifdef MAPNIK_STATS
|
|
mapnik::progress_timer __stats__(std::clog, "occi_datasource::envelope(estimate_extent)");
|
|
#endif
|
|
|
|
std::ostringstream s;
|
|
s << "SELECT MIN(c.x), MIN(c.y), MAX(c.x), MAX(c.y) FROM ";
|
|
s << " (SELECT SDO_AGGR_MBR(" << geometry_field_ << ") shape FROM " << table_ << ") a, ";
|
|
s << " TABLE(SDO_UTIL.GETVERTICES(a.shape)) c";
|
|
|
|
MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str();
|
|
|
|
try
|
|
{
|
|
occi_connection_ptr conn;
|
|
if (use_connection_pool_) conn.set_pool(pool_);
|
|
else conn.set_connection(conn_, false);
|
|
|
|
ResultSet* rs = conn.execute_query(s.str());
|
|
if (rs && rs->next())
|
|
{
|
|
lox = rs->getDouble(1);
|
|
loy = rs->getDouble(2);
|
|
hix = rs->getDouble(3);
|
|
hiy = rs->getDouble(4);
|
|
extent_.init(lox, loy, hix, hiy);
|
|
extent_initialized_ = true;
|
|
}
|
|
}
|
|
catch (SQLException& ex)
|
|
{
|
|
throw datasource_exception("OCCI Plugin: " + ex.getMessage());
|
|
}
|
|
}
|
|
else if (use_spatial_index_)
|
|
{
|
|
#ifdef MAPNIK_STATS
|
|
mapnik::progress_timer __stats__(std::clog, "occi_datasource::envelope(use_spatial_index)");
|
|
#endif
|
|
|
|
std::ostringstream s;
|
|
s << "SELECT dim.sdo_lb, dim.sdo_ub FROM ";
|
|
s << METADATA_TABLE << " m, TABLE(m.diminfo) dim ";
|
|
s << " WHERE LOWER(m.table_name) = LOWER('" << table_name_ << "') AND dim.sdo_dimname = 'X'";
|
|
s << " UNION ";
|
|
s << "SELECT dim.sdo_lb, dim.sdo_ub FROM ";
|
|
s << METADATA_TABLE << " m, TABLE(m.diminfo) dim ";
|
|
s << " WHERE LOWER(m.table_name) = LOWER('" << table_name_ << "') AND dim.sdo_dimname = 'Y'";
|
|
|
|
MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str();
|
|
|
|
try
|
|
{
|
|
occi_connection_ptr conn;
|
|
if (use_connection_pool_) conn.set_pool(pool_);
|
|
else conn.set_connection(conn_, false);
|
|
|
|
ResultSet* rs = conn.execute_query(s.str());
|
|
if (rs)
|
|
{
|
|
if (rs->next())
|
|
{
|
|
lox = rs->getDouble(1);
|
|
hix = rs->getDouble(2);
|
|
}
|
|
|
|
if (rs->next())
|
|
{
|
|
loy = rs->getDouble(1);
|
|
hiy = rs->getDouble(2);
|
|
}
|
|
extent_.init(lox, loy, hix, hiy);
|
|
extent_initialized_ = true;
|
|
}
|
|
}
|
|
catch (SQLException& ex)
|
|
{
|
|
throw datasource_exception("OCCI Plugin: " + ex.getMessage());
|
|
}
|
|
}
|
|
|
|
if (! extent_initialized_)
|
|
{
|
|
throw datasource_exception("OCCI Plugin: unable to determine the extent of a <occi> table");
|
|
}
|
|
|
|
return extent_;
|
|
}
|
|
|
|
|
|
boost::optional<mapnik::datasource_geometry_t> occi_datasource::get_geometry_type() const
|
|
{
|
|
return boost::optional<mapnik::datasource_geometry_t>();
|
|
}
|
|
|
|
layer_descriptor occi_datasource::get_descriptor() const
|
|
{
|
|
return desc_;
|
|
}
|
|
|
|
std::string occi_datasource::sql_bbox(box2d<double> const& env) const
|
|
{
|
|
std::ostringstream b;
|
|
b << std::setprecision(16);
|
|
b << "MDSYS.SDO_GEOMETRY(" << SDO_GTYPE_2DPOLYGON << "," << srid_ << ",NULL,";
|
|
b << " MDSYS.SDO_ELEM_INFO_ARRAY(1," << SDO_ETYPE_POLYGON << "," << SDO_INTERPRETATION_RECTANGLE << "),";
|
|
b << " MDSYS.SDO_ORDINATE_ARRAY(";
|
|
b << env.minx() << "," << env.miny() << ", ";
|
|
b << env.maxx() << "," << env.maxy() << "))";
|
|
return b.str();
|
|
}
|
|
|
|
std::string occi_datasource::populate_tokens(std::string const& sql, double scale_denom, box2d<double> const& env, double pixel_width, double pixel_height) const
|
|
{
|
|
std::string populated_sql = sql;
|
|
|
|
if (boost::algorithm::icontains(populated_sql, scale_denom_token_))
|
|
{
|
|
std::ostringstream ss;
|
|
ss << scale_denom;
|
|
boost::algorithm::replace_all(populated_sql, scale_denom_token_, ss.str());
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
if (boost::algorithm::icontains(sql, pixel_height_token_))
|
|
{
|
|
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_, sql_bbox(env));
|
|
}
|
|
|
|
return populated_sql;
|
|
}
|
|
|
|
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 occi_datasource::features_at_point(coord2d const& pt, double tol) const
|
|
{
|
|
#ifdef MAPNIK_STATS
|
|
mapnik::progress_timer __stats__(std::clog, "occi_datasource::features_at_point");
|
|
#endif
|
|
|
|
std::ostringstream s;
|
|
s << "SELECT ";
|
|
if (use_wkb_)
|
|
{
|
|
s << "SDO_UTIL.TO_WKBGEOMETRY(" << geometry_field_ << ")";
|
|
}
|
|
else
|
|
{
|
|
s << geometry_field_;
|
|
}
|
|
std::vector<attribute_descriptor>::const_iterator itr = desc_.get_descriptors().begin();
|
|
std::vector<attribute_descriptor>::const_iterator end = desc_.get_descriptors().end();
|
|
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
|
|
while (itr != end)
|
|
{
|
|
s << ", " << itr->get_name();
|
|
ctx->push(itr->get_name());
|
|
++itr;
|
|
}
|
|
|
|
box2d<double> box(pt.x - tol, pt.y - tol, pt.x + tol, pt.y + tol);
|
|
std::string query = populate_tokens(table_, FMAX, box, 0, 0);
|
|
|
|
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_);
|
|
}
|