- improved pool handling in oracle occi

This commit is contained in:
kunitoki 2013-05-14 11:27:34 +02:00
parent 2ec04ab9e3
commit 04a7c7b36f
6 changed files with 716 additions and 632 deletions

View file

@ -42,6 +42,8 @@
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
using boost::shared_ptr;
using mapnik::datasource; using mapnik::datasource;
using mapnik::parameters; using mapnik::parameters;
using mapnik::query; using mapnik::query;
@ -52,14 +54,7 @@ using mapnik::datasource_exception;
using mapnik::box2d; using mapnik::box2d;
using mapnik::coord2d; 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::SQLException;
using oracle::occi::Type;
using oracle::occi::StatelessConnectionPool;
const double occi_datasource::FMAX = std::numeric_limits<double>::max(); const double occi_datasource::FMAX = std::numeric_limits<double>::max();
const std::string occi_datasource::METADATA_TABLE = "USER_SDO_GEOM_METADATA"; const std::string occi_datasource::METADATA_TABLE = "USER_SDO_GEOM_METADATA";
@ -78,11 +73,12 @@ occi_datasource::occi_datasource(parameters const& params)
pixel_width_token_("!pixel_width!"), pixel_width_token_("!pixel_width!"),
pixel_height_token_("!pixel_height!"), pixel_height_token_("!pixel_height!"),
desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding", "utf-8")), desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding", "utf-8")),
creator_(params.get<std::string>("user"),
params.get<std::string>("password"),
params.get<std::string>("host")),
use_wkb_(*params.get<mapnik::boolean>("use_wkb", false)), use_wkb_(*params.get<mapnik::boolean>("use_wkb", false)),
row_limit_(*params.get<mapnik::value_integer>("row_limit", 0)), row_limit_(*params.get<mapnik::value_integer>("row_limit", 0)),
row_prefetch_(*params.get<int>("row_prefetch", 100)), row_prefetch_(*params.get<int>("row_prefetch", 100))
pool_(0),
conn_(0)
{ {
#ifdef MAPNIK_STATS #ifdef MAPNIK_STATS
mapnik::progress_timer __stats__(std::clog, "occi_datasource::init"); mapnik::progress_timer __stats__(std::clog, "occi_datasource::init");
@ -103,7 +99,7 @@ occi_datasource::occi_datasource(parameters const& params)
} }
estimate_extent_ = *params.get<mapnik::boolean>("estimate_extent",false); estimate_extent_ = *params.get<mapnik::boolean>("estimate_extent",false);
use_spatial_index_ = *params.get<mapnik::boolean>("use_spatial_index",true); use_spatial_index_ = *params.get<mapnik::boolean>("use_spatial_index",true);
use_connection_pool_ = *params.get<mapnik::boolean>("use_connection_pool",true); persist_connection_ = *params.get<mapnik::boolean>("persist_connection",true);
boost::optional<std::string> ext = params.get<std::string>("extent"); boost::optional<std::string> ext = params.get<std::string>("extent");
if (ext) extent_initialized_ = extent_.from_string(*ext); if (ext) extent_initialized_ = extent_.from_string(*ext);
@ -116,222 +112,186 @@ occi_datasource::occi_datasource(parameters const& params)
} }
// connect to environment // connect to environment
if (use_connection_pool_) boost::optional<int> initial_size = params.get<int>("initial_size", 1);
{ boost::optional<int> max_size = params.get<int>("max_size", 10);
try
{
pool_ = occi_environment::instance().create_pool(
*params.get<std::string>("user"),
*params.get<std::string>("password"),
*params.get<std::string>("host"),
*params.get<int>("max_size", 5),
*params.get<int>("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 ConnectionManager::instance().registerPool(creator_, *initial_size, *max_size);
table_name_ = mapnik::sql_utils::table_from_sql(table_); shared_ptr< Pool<Connection,ConnectionCreator> > pool =
ConnectionManager::instance().getPool(creator_.id());
// get SRID and/or GEOMETRY_FIELD from metadata table only if we need to if (pool)
if (! srid_initialized_ || geometry_field_ == "")
{ {
shared_ptr<Connection> conn = pool->borrowObject();
if (! conn) return;
// 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 #ifdef MAPNIK_STATS
mapnik::progress_timer __stats__(std::clog, "occi_datasource::get_srid_and_geometry_field"); mapnik::progress_timer __stats__(std::clog, "occi_datasource::get_srid_and_geometry_field");
#endif #endif
std::ostringstream s; std::ostringstream s;
s << "SELECT srid, column_name FROM " << METADATA_TABLE << " WHERE"; s << "SELECT srid, column_name FROM " << METADATA_TABLE << " WHERE";
s << " LOWER(table_name) = LOWER('" << table_name_ << "')"; s << " LOWER(table_name) = LOWER('" << table_name_ << "')";
if (geometry_field_ != "") 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_) s << " AND LOWER(column_name) = LOWER('" << geometry_field_ << "')";
{
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 MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str();
{
#ifdef MAPNIK_STATS
mapnik::progress_timer __stats__(std::clog, "occi_datasource::get_column_description");
#endif
std::ostringstream s; try
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(); shared_ptr<ResultSet> rs = conn->execute_query(s.str());
if (rs && rs->next())
for (unsigned int i = 0; i < listOfColumns.size(); ++i)
{ {
MetaData columnObj = listOfColumns[i]; if (! srid_initialized_)
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: srid_ = rs->getInt(1);
desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Boolean)); srid_initialized_ = true;
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;
} }
if (geometry_field_ == "")
{
geometry_field_ = rs->getString(2);
}
rs->close();
} }
} }
catch (SQLException& ex)
{
throw datasource_exception("OCCI Plugin: " + ex.getMessage());
}
} }
catch (SQLException& ex)
// get columns description
{ {
throw datasource_exception(ex.getMessage()); #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
{
shared_ptr<ResultSet> rs = conn->execute_query(s.str());
if (rs)
{
unsigned int numFields = rs->getNumFields();
for (unsigned int i = 0; i < numFields; ++i)
{
std::string fld_name = rs->getFieldName(i);
int type_oid = rs->getTypeOID(i);
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 "
<< Environment::instance().resolve_datatype(type_oid)
<< " (type_oid=" << type_oid << ")";
break;
default:
MAPNIK_LOG_WARN(occi) << "occi_datasource: Unknown datatype "
<< "(type_oid=" << type_oid << ")";
break;
}
}
rs->close();
}
}
catch (SQLException& ex)
{
throw datasource_exception(ex.getMessage());
}
} }
} }
} }
occi_datasource::~occi_datasource() occi_datasource::~occi_datasource()
{ {
if (use_connection_pool_) if (! persist_connection_)
{ {
if (pool_ != 0) shared_ptr< Pool<Connection,ConnectionCreator> > pool =
ConnectionManager::instance().getPool(creator_.id());
if (pool)
{ {
occi_environment::instance().destroy_pool(pool_); shared_ptr<Connection> conn = pool->borrowObject();
} if (conn)
} {
else conn->close();
{ }
if (conn_ != 0)
{
occi_environment::instance().destroy_connection(conn_);
} }
} }
} }
@ -352,87 +312,91 @@ box2d<double> occi_datasource::envelope() const
double lox = 0.0, loy = 0.0, hix = 0.0, hiy = 0.0; double lox = 0.0, loy = 0.0, hix = 0.0, hiy = 0.0;
shared_ptr< Pool<Connection,ConnectionCreator> > pool =
if (estimate_extent_) ConnectionManager::instance().getPool(creator_.id());
if (pool)
{ {
shared_ptr<Connection> conn = pool->borrowObject();
if (conn)
{
if (estimate_extent_)
{
#ifdef MAPNIK_STATS #ifdef MAPNIK_STATS
mapnik::progress_timer __stats__(std::clog, "occi_datasource::envelope(estimate_extent)"); mapnik::progress_timer __stats__(std::clog, "occi_datasource::envelope(estimate_extent)");
#endif #endif
std::ostringstream s; std::ostringstream s;
s << "SELECT MIN(c.x), MIN(c.y), MAX(c.x), MAX(c.y) FROM "; 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 << " (SELECT SDO_AGGR_MBR(" << geometry_field_ << ") shape FROM " << table_ << ") a, ";
s << " TABLE(SDO_UTIL.GETVERTICES(a.shape)) c"; s << " TABLE(SDO_UTIL.GETVERTICES(a.shape)) c";
MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str();
try try
{ {
occi_connection_ptr conn; shared_ptr<ResultSet> rs = conn->execute_query(s.str());
if (use_connection_pool_) conn.set_pool(pool_); if (rs && rs->next())
else conn.set_connection(conn_, false); {
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;
ResultSet* rs = conn.execute_query(s.str()); rs->close();
if (rs && rs->next()) }
{ }
lox = rs->getDouble(1); catch (SQLException& ex)
loy = rs->getDouble(2); {
hix = rs->getDouble(3); throw datasource_exception("OCCI Plugin: " + ex.getMessage());
hiy = rs->getDouble(4); }
extent_.init(lox, loy, hix, hiy);
extent_initialized_ = true;
} }
} else if (use_spatial_index_)
catch (SQLException& ex) {
{
throw datasource_exception("OCCI Plugin: " + ex.getMessage());
}
}
else if (use_spatial_index_)
{
#ifdef MAPNIK_STATS #ifdef MAPNIK_STATS
mapnik::progress_timer __stats__(std::clog, "occi_datasource::envelope(use_spatial_index)"); mapnik::progress_timer __stats__(std::clog, "occi_datasource::envelope(use_spatial_index)");
#endif #endif
std::ostringstream s; std::ostringstream s;
s << "SELECT dim.sdo_lb, dim.sdo_ub FROM "; s << "SELECT dim.sdo_lb, dim.sdo_ub FROM ";
s << METADATA_TABLE << " m, TABLE(m.diminfo) dim "; s << METADATA_TABLE << " m, TABLE(m.diminfo) dim ";
s << " WHERE LOWER(m.table_name) = LOWER('" << table_name_ << "') AND dim.sdo_dimname = 'X'"; s << " WHERE LOWER(m.table_name) = LOWER('" << table_name_ << "') AND dim.sdo_dimname = 'X'";
s << " UNION "; s << " UNION ";
s << "SELECT dim.sdo_lb, dim.sdo_ub FROM "; s << "SELECT dim.sdo_lb, dim.sdo_ub FROM ";
s << METADATA_TABLE << " m, TABLE(m.diminfo) dim "; s << METADATA_TABLE << " m, TABLE(m.diminfo) dim ";
s << " WHERE LOWER(m.table_name) = LOWER('" << table_name_ << "') AND dim.sdo_dimname = 'Y'"; s << " WHERE LOWER(m.table_name) = LOWER('" << table_name_ << "') AND dim.sdo_dimname = 'Y'";
MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str();
try 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); shared_ptr<ResultSet> rs = conn->execute_query(s.str());
hix = rs->getDouble(2); if (rs)
} {
if (rs->next())
{
lox = rs->getDouble(1);
hix = rs->getDouble(2);
}
if (rs->next()) if (rs->next())
{ {
loy = rs->getDouble(1); loy = rs->getDouble(1);
hiy = rs->getDouble(2); hiy = rs->getDouble(2);
}
extent_.init(lox, loy, hix, hiy);
extent_initialized_ = true;
rs->close();
}
}
catch (SQLException& ex)
{
throw datasource_exception("OCCI Plugin: " + ex.getMessage());
} }
extent_.init(lox, loy, hix, hiy);
extent_initialized_ = true;
} }
} }
catch (SQLException& ex)
{
throw datasource_exception("OCCI Plugin: " + ex.getMessage());
}
} }
if (! extent_initialized_) if (! extent_initialized_)
@ -505,71 +469,78 @@ featureset_ptr occi_datasource::features(query const& q) const
mapnik::progress_timer __stats__(std::clog, "occi_datasource::features"); mapnik::progress_timer __stats__(std::clog, "occi_datasource::features");
#endif #endif
box2d<double> const& box = q.get_bbox(); shared_ptr< Pool<Connection,ConnectionCreator> > pool =
const double px_gw = 1.0 / boost::get<0>(q.resolution()); ConnectionManager::instance().getPool(creator_.id());
const double px_gh = 1.0 / boost::get<1>(q.resolution()); if (pool)
const double scale_denom = q.scale_denominator();
std::ostringstream s;
s << "SELECT ";
if (use_wkb_)
{ {
s << "SDO_UTIL.TO_WKBGEOMETRY(" << geometry_field_ << ")"; shared_ptr<Connection> conn = pool->borrowObject();
} if (conn)
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 = boost::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 "); box2d<double> const& box = q.get_bbox();
} const double px_gw = 1.0 / boost::get<0>(q.resolution());
else if (boost::algorithm::ifind_first(query, table_name_)) const double px_gh = 1.0 / boost::get<1>(q.resolution());
{ const double scale_denom = q.scale_denominator();
boost::algorithm::ireplace_first(query, table_name_, table_name_ + " " + spatial_sql.str());
} std::ostringstream s;
else s << "SELECT ";
{ if (use_wkb_)
MAPNIK_LOG_WARN(occi) << "occi_datasource: cannot determine where to add the spatial filter declaration"; {
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 = boost::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 boost::make_shared<occi_featureset>(conn->execute_query(s.str(), row_prefetch_),
ctx,
desc_.get_encoding(),
use_wkb_);
} }
} }
s << " FROM " << query; return featureset_ptr();
if (row_limit_ > 0)
{
s << " WHERE ROWNUM < " << row_limit_;
}
MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str();
return boost::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 featureset_ptr occi_datasource::features_at_point(coord2d const& pt, double tol) const
@ -578,65 +549,72 @@ featureset_ptr occi_datasource::features_at_point(coord2d const& pt, double tol)
mapnik::progress_timer __stats__(std::clog, "occi_datasource::features_at_point"); mapnik::progress_timer __stats__(std::clog, "occi_datasource::features_at_point");
#endif #endif
std::ostringstream s; shared_ptr< Pool<Connection,ConnectionCreator> > pool =
s << "SELECT "; ConnectionManager::instance().getPool(creator_.id());
if (use_wkb_) if (pool)
{ {
s << "SDO_UTIL.TO_WKBGEOMETRY(" << geometry_field_ << ")"; shared_ptr<Connection> conn = pool->borrowObject();
} if (conn)
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 = boost::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 "); std::ostringstream s;
} s << "SELECT ";
else if (boost::algorithm::ifind_first(query, table_name_)) if (use_wkb_)
{ {
boost::algorithm::ireplace_first(query, table_name_, table_name_ + " " + spatial_sql.str()); s << "SDO_UTIL.TO_WKBGEOMETRY(" << geometry_field_ << ")";
} }
else else
{ {
MAPNIK_LOG_WARN(occi) << "occi_datasource: Cannot determine where to add the spatial filter declaration"; 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 = boost::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 boost::make_shared<occi_featureset>(conn->execute_query(s.str(), row_prefetch_),
ctx,
desc_.get_encoding(),
use_wkb_);
} }
} }
s << " FROM " << query; return featureset_ptr();
if (row_limit_ > 0)
{
s << " WHERE ROWNUM < " << row_limit_;
}
MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str();
return boost::make_shared<occi_featureset>(pool_,
conn_,
ctx,
s.str(),
desc_.get_encoding(),
use_connection_pool_,
use_wkb_,
row_prefetch_);
} }

View file

@ -82,12 +82,11 @@ private:
const std::string pixel_width_token_; const std::string pixel_width_token_;
const std::string pixel_height_token_; const std::string pixel_height_token_;
mapnik::layer_descriptor desc_; mapnik::layer_descriptor desc_;
ConnectionCreator<Connection> creator_;
bool use_wkb_; bool use_wkb_;
mapnik::value_integer row_limit_; mapnik::value_integer row_limit_;
int row_prefetch_; int row_prefetch_;
oracle::occi::StatelessConnectionPool* pool_; bool persist_connection_;
oracle::occi::Connection* conn_;
bool use_connection_pool_;
bool use_spatial_index_; bool use_spatial_index_;
bool estimate_extent_; bool estimate_extent_;
}; };

View file

@ -43,49 +43,22 @@ using mapnik::transcoder;
using mapnik::datasource_exception; using mapnik::datasource_exception;
using mapnik::feature_factory; using mapnik::feature_factory;
using oracle::occi::Connection;
using oracle::occi::Statement;
using oracle::occi::ResultSet;
using oracle::occi::StatelessConnectionPool;
using oracle::occi::MetaData; using oracle::occi::MetaData;
using oracle::occi::SQLException; using oracle::occi::SQLException;
using oracle::occi::Type; using oracle::occi::Type;
using oracle::occi::Number; using oracle::occi::Number;
using oracle::occi::Blob; using oracle::occi::Blob;
occi_featureset::occi_featureset(StatelessConnectionPool* pool, occi_featureset::occi_featureset(boost::shared_ptr<ResultSet> rs,
Connection* conn,
mapnik::context_ptr const& ctx, mapnik::context_ptr const& ctx,
std::string const& sqlstring,
std::string const& encoding, std::string const& encoding,
bool use_connection_pool, bool use_wkb)
bool use_wkb, : rs_(rs),
unsigned prefetch_rows)
: rs_(NULL),
tr_(new transcoder(encoding)), tr_(new transcoder(encoding)),
feature_id_(1), feature_id_(1),
ctx_(ctx), ctx_(ctx),
use_wkb_(use_wkb) use_wkb_(use_wkb)
{ {
if (use_connection_pool)
{
conn_.set_pool(pool);
}
else
{
conn_.set_connection(conn, false);
}
try
{
rs_ = conn_.execute_query(sqlstring, prefetch_rows);
}
catch (SQLException &ex)
{
MAPNIK_LOG_ERROR(occi) << "OCCI Plugin: error processing " << sqlstring << " : " << ex.getMessage();
rs_ = NULL;
}
} }
occi_featureset::~occi_featureset() occi_featureset::~occi_featureset()
@ -94,25 +67,13 @@ occi_featureset::~occi_featureset()
feature_ptr occi_featureset::next() feature_ptr occi_featureset::next()
{ {
while (rs_ != NULL && rs_->next() == oracle::occi::ResultSet::DATA_AVAILABLE) while (rs_ != NULL && rs_->next())
{ {
feature_ptr feature(feature_factory::create(ctx_, feature_id_)); feature_ptr feature(feature_factory::create(ctx_, feature_id_));
if (use_wkb_) if (use_wkb_)
{ {
Blob blob = rs_->getBlob(1); unsigned int size = rs_->getBlob(1, buffer_);
blob.open(oracle::occi::OCCI_LOB_READONLY);
unsigned int size = blob.length();
if (buffer_.size() < size)
{
buffer_.resize(size);
}
oracle::occi::Stream* instream = blob.getStream(1, 0);
instream->readBuffer(buffer_.data(), size);
blob.closeStream(instream);
blob.close();
if (! geometry_utils::from_wkb(feature->paths(), buffer_.data(), size)) if (! geometry_utils::from_wkb(feature->paths(), buffer_.data(), size))
{ {
@ -132,22 +93,11 @@ feature_ptr occi_featureset::next()
} }
} }
std::vector<MetaData> listOfColumns = rs_->getColumnListMetaData(); unsigned int numFields = rs_->getNumFields();
for (unsigned int i = 0; i < numFields; ++i)
for (unsigned int i = 1; i < listOfColumns.size(); ++i)
{ {
MetaData columnObj = listOfColumns[i]; std::string fld_name = rs_->getFieldName(i);
int type_oid = rs_->getTypeOID(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)
{
continue;
}
*/
switch (type_oid) switch (type_oid)
{ {
@ -192,7 +142,7 @@ feature_ptr occi_featureset::next()
case oracle::occi::OCCI_SQLT_TIMESTAMP: case oracle::occi::OCCI_SQLT_TIMESTAMP:
case oracle::occi::OCCI_SQLT_TIMESTAMP_LTZ: case oracle::occi::OCCI_SQLT_TIMESTAMP_LTZ:
case oracle::occi::OCCI_SQLT_TIMESTAMP_TZ: case oracle::occi::OCCI_SQLT_TIMESTAMP_TZ:
feature->put(fld_name, (UnicodeString)tr_->transcode(rs_->getString(i + 1).c_str())); feature->put(fld_name, (UnicodeString)tr_->transcode(rs_->getString(i + 1)));
break; break;
case oracle::occi::OCCIINTERVALDS: case oracle::occi::OCCIINTERVALDS:
case oracle::occi::OCCIINTERVALYM: case oracle::occi::OCCIINTERVALYM:
@ -218,7 +168,7 @@ feature_ptr occi_featureset::next()
case oracle::occi::OCCI_SQLT_RSET: case oracle::occi::OCCI_SQLT_RSET:
{ {
MAPNIK_LOG_WARN(occi) << "occi_featureset: Unsupported datatype " MAPNIK_LOG_WARN(occi) << "occi_featureset: Unsupported datatype "
<< occi_enums::resolve_datatype(type_oid) << Environment::instance().resolve_datatype(type_oid)
<< " (type_oid=" << type_oid << ")"; << " (type_oid=" << type_oid << ")";
break; break;
} }
@ -368,7 +318,7 @@ void occi_featureset::convert_geometry(SDOGeometry* geom, feature_ptr feature)
default: default:
{ {
MAPNIK_LOG_WARN(occi) << "occi_featureset: Unknown oracle enum " MAPNIK_LOG_WARN(occi) << "occi_featureset: Unknown oracle enum "
<< occi_enums::resolve_gtype(geomtype) << Environment::instance().resolve_gtype(geomtype)
<< "(gtype=" << gtype << ")"; << "(gtype=" << gtype << ")";
} }
break; break;

View file

@ -41,14 +41,10 @@
class occi_featureset : public mapnik::Featureset class occi_featureset : public mapnik::Featureset
{ {
public: public:
occi_featureset(oracle::occi::StatelessConnectionPool* pool, occi_featureset(boost::shared_ptr<ResultSet> rs,
oracle::occi::Connection* conn,
mapnik::context_ptr const& ctx, mapnik::context_ptr const& ctx,
std::string const& sqlstring,
std::string const& encoding, std::string const& encoding,
bool use_connection_pool, bool use_wkb);
bool use_wkb,
unsigned prefetch_rows);
virtual ~occi_featureset(); virtual ~occi_featureset();
mapnik::feature_ptr next(); mapnik::feature_ptr next();
@ -68,8 +64,7 @@ private:
const int dimensions, const int dimensions,
const bool is_point_geom); const bool is_point_geom);
occi_connection_ptr conn_; boost::shared_ptr<ResultSet> rs_;
oracle::occi::ResultSet* rs_;
boost::scoped_ptr<mapnik::transcoder> tr_; boost::scoped_ptr<mapnik::transcoder> tr_;
mapnik::value_integer feature_id_; mapnik::value_integer feature_id_;
mapnik::context_ptr ctx_; mapnik::context_ptr ctx_;

View file

@ -21,71 +21,3 @@
*****************************************************************************/ *****************************************************************************/
#include "occi_types.hpp" #include "occi_types.hpp"
std::string occi_enums::resolve_gtype(int gtype)
{
switch (gtype)
{
case SDO_GTYPE_UNKNOWN: return "SDO_GTYPE_UNKNOWN";
case SDO_GTYPE_POINT: return "SDO_GTYPE_POINT";
case SDO_GTYPE_LINE: return "SDO_GTYPE_LINE";
case SDO_GTYPE_POLYGON: return "SDO_GTYPE_POLYGON";
case SDO_GTYPE_MULTIPOINT: return "SDO_GTYPE_MULTIPOINT";
case SDO_GTYPE_MULTILINE: return "SDO_GTYPE_MULTILINE";
case SDO_GTYPE_MULTIPOLYGON: return "SDO_GTYPE_MULTIPOLYGON";
case SDO_GTYPE_COLLECTION: return "SDO_GTYPE_COLLECTION";
default: return "<unknown SDO_GTYPE>";
}
}
std::string occi_enums::resolve_etype(int etype)
{
switch (etype)
{
case SDO_ETYPE_UNKNOWN: return "SDO_ETYPE_UNKNOWN";
case SDO_ETYPE_POINT: return "SDO_ETYPE_POINT";
case SDO_ETYPE_LINESTRING: return "SDO_ETYPE_LINESTRING";
case SDO_ETYPE_POLYGON: return "SDO_ETYPE_POLYGON";
case SDO_ETYPE_POLYGON_INTERIOR: return "SDO_ETYPE_POLYGON_INTERIOR";
case SDO_ETYPE_COMPOUND_LINESTRING: return "SDO_ETYPE_COMPOUND_LINESTRING";
case SDO_ETYPE_COMPOUND_POLYGON: return "SDO_ETYPE_COMPOUND_POLYGON";
case SDO_ETYPE_COMPOUND_POLYGON_INTERIOR: return "SDO_ETYPE_COMPOUND_POLYGON_INTERIOR";
default: return "<unknown SDO_ETYPE>";
}
}
std::string occi_enums::resolve_datatype(int type_id)
{
switch (type_id)
{
case oracle::occi::OCCIINT: return "OCCIINT";
case oracle::occi::OCCIUNSIGNED_INT: return "OCCIUNSIGNED_INT";
case oracle::occi::OCCIFLOAT: return "OCCIFLOAT";
case oracle::occi::OCCIBFLOAT: return "OCCIBFLOAT";
case oracle::occi::OCCIDOUBLE: return "OCCIDOUBLE";
case oracle::occi::OCCIBDOUBLE: return "OCCIBDOUBLE";
case oracle::occi::OCCINUMBER: return "OCCINUMBER";
case oracle::occi::OCCI_SQLT_NUM: return "OCCI_SQLT_NUM";
case oracle::occi::OCCICHAR: return "OCCICHAR";
case oracle::occi::OCCISTRING: return "OCCISTRING";
case oracle::occi::OCCI_SQLT_AFC: return "OCCI_SQLT_AFC";
case oracle::occi::OCCI_SQLT_AVC: return "OCCI_SQLT_AVC";
case oracle::occi::OCCI_SQLT_CHR: return "OCCI_SQLT_CHR";
case oracle::occi::OCCI_SQLT_LVC: return "OCCI_SQLT_LVC";
case oracle::occi::OCCI_SQLT_LNG: return "OCCI_SQLT_LNG";
case oracle::occi::OCCI_SQLT_STR: return "OCCI_SQLT_STR";
case oracle::occi::OCCI_SQLT_VCS: return "OCCI_SQLT_VCS";
case oracle::occi::OCCI_SQLT_VNU: return "OCCI_SQLT_VNU";
case oracle::occi::OCCI_SQLT_VBI: return "OCCI_SQLT_VBI";
case oracle::occi::OCCI_SQLT_VST: return "OCCI_SQLT_VST";
case oracle::occi::OCCI_SQLT_RDD: return "OCCI_SQLT_RDD";
case oracle::occi::OCCIDATE: return "OCCIDATE";
case oracle::occi::OCCITIMESTAMP: return "OCCITIMESTAMP";
case oracle::occi::OCCI_SQLT_DAT: return "OCCI_SQLT_DAT";
case oracle::occi::OCCI_SQLT_TIMESTAMP: return "OCCI_SQLT_TIMESTAMP";
case oracle::occi::OCCI_SQLT_TIMESTAMP_LTZ: return "OCCI_SQLT_TIMESTAMP_LTZ";
case oracle::occi::OCCI_SQLT_TIMESTAMP_TZ: return "OCCI_SQLT_TIMESTAMP_TZ";
case oracle::occi::OCCIPOBJECT: return "OCCIPOBJECT";
default: return "<unknown ATTR_DATA_TYPE>";
}
}

View file

@ -25,13 +25,22 @@
// mapnik // mapnik
#include <mapnik/debug.hpp> #include <mapnik/debug.hpp>
#include <mapnik/pool.hpp>
#include <mapnik/utils.hpp> #include <mapnik/utils.hpp>
// boost // boost
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/optional.hpp>
#ifdef MAPNIK_THREADSAFE #ifdef MAPNIK_THREADSAFE
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#endif #endif
// stl
#include <string>
#include <sstream>
// occi // occi
#include <occi.h> #include <occi.h>
@ -46,6 +55,10 @@
#error Only ORACLE 10g >= 10.2.0.X is supported ! #error Only ORACLE 10g >= 10.2.0.X is supported !
#endif #endif
using mapnik::Pool;
using mapnik::singleton;
using mapnik::CreateStatic;
// geometry types definitions // geometry types definitions
enum enum
{ {
@ -83,9 +96,9 @@ enum
SDO_INTERPRETATION_CIRCULAR = 2 SDO_INTERPRETATION_CIRCULAR = 2
}; };
class occi_environment : public mapnik::singleton<occi_environment, mapnik::CreateStatic> class Environment : public mapnik::singleton<Environment, mapnik::CreateStatic>
{ {
friend class mapnik::CreateStatic<occi_environment>; friend class mapnik::CreateStatic<Environment>;
public: public:
@ -94,51 +107,77 @@ public:
return env_; return env_;
} }
oracle::occi::Connection* create_connection( std::string resolve_gtype(int gtype)
const std::string& user,
const std::string& password,
const std::string& host)
{ {
MAPNIK_LOG_DEBUG(occi) << "occi_environment: create_connection"; switch (gtype)
{
return env_->createConnection(user, password, host); case SDO_GTYPE_UNKNOWN: return "SDO_GTYPE_UNKNOWN";
case SDO_GTYPE_POINT: return "SDO_GTYPE_POINT";
case SDO_GTYPE_LINE: return "SDO_GTYPE_LINE";
case SDO_GTYPE_POLYGON: return "SDO_GTYPE_POLYGON";
case SDO_GTYPE_MULTIPOINT: return "SDO_GTYPE_MULTIPOINT";
case SDO_GTYPE_MULTILINE: return "SDO_GTYPE_MULTILINE";
case SDO_GTYPE_MULTIPOLYGON: return "SDO_GTYPE_MULTIPOLYGON";
case SDO_GTYPE_COLLECTION: return "SDO_GTYPE_COLLECTION";
default: return "<unknown SDO_GTYPE>";
}
} }
void destroy_connection(oracle::occi::Connection* conn) std::string resolve_etype(int etype)
{ {
env_->terminateConnection(conn); switch (etype)
{
case SDO_ETYPE_UNKNOWN: return "SDO_ETYPE_UNKNOWN";
case SDO_ETYPE_POINT: return "SDO_ETYPE_POINT";
case SDO_ETYPE_LINESTRING: return "SDO_ETYPE_LINESTRING";
case SDO_ETYPE_POLYGON: return "SDO_ETYPE_POLYGON";
case SDO_ETYPE_POLYGON_INTERIOR: return "SDO_ETYPE_POLYGON_INTERIOR";
case SDO_ETYPE_COMPOUND_LINESTRING: return "SDO_ETYPE_COMPOUND_LINESTRING";
case SDO_ETYPE_COMPOUND_POLYGON: return "SDO_ETYPE_COMPOUND_POLYGON";
case SDO_ETYPE_COMPOUND_POLYGON_INTERIOR: return "SDO_ETYPE_COMPOUND_POLYGON_INTERIOR";
default: return "<unknown SDO_ETYPE>";
}
} }
oracle::occi::StatelessConnectionPool* create_pool( std::string resolve_datatype(int type_id)
const std::string& user,
const std::string& password,
const std::string& host,
int max_size,
int initial_size,
int incr_size)
{ {
MAPNIK_LOG_DEBUG(occi) << "occi_environment: create_pool"; switch (type_id)
{
return env_->createStatelessConnectionPool( case oracle::occi::OCCIINT: return "OCCIINT";
user, case oracle::occi::OCCIUNSIGNED_INT: return "OCCIUNSIGNED_INT";
password, case oracle::occi::OCCIFLOAT: return "OCCIFLOAT";
host, case oracle::occi::OCCIBFLOAT: return "OCCIBFLOAT";
max_size, case oracle::occi::OCCIDOUBLE: return "OCCIDOUBLE";
initial_size, case oracle::occi::OCCIBDOUBLE: return "OCCIBDOUBLE";
incr_size, case oracle::occi::OCCINUMBER: return "OCCINUMBER";
oracle::occi::StatelessConnectionPool::HOMOGENEOUS); case oracle::occi::OCCI_SQLT_NUM: return "OCCI_SQLT_NUM";
} case oracle::occi::OCCICHAR: return "OCCICHAR";
case oracle::occi::OCCISTRING: return "OCCISTRING";
void destroy_pool(oracle::occi::StatelessConnectionPool* pool) case oracle::occi::OCCI_SQLT_AFC: return "OCCI_SQLT_AFC";
{ case oracle::occi::OCCI_SQLT_AVC: return "OCCI_SQLT_AVC";
env_->terminateStatelessConnectionPool( case oracle::occi::OCCI_SQLT_CHR: return "OCCI_SQLT_CHR";
pool, case oracle::occi::OCCI_SQLT_LVC: return "OCCI_SQLT_LVC";
oracle::occi::StatelessConnectionPool::SPD_FORCE); case oracle::occi::OCCI_SQLT_LNG: return "OCCI_SQLT_LNG";
case oracle::occi::OCCI_SQLT_STR: return "OCCI_SQLT_STR";
case oracle::occi::OCCI_SQLT_VCS: return "OCCI_SQLT_VCS";
case oracle::occi::OCCI_SQLT_VNU: return "OCCI_SQLT_VNU";
case oracle::occi::OCCI_SQLT_VBI: return "OCCI_SQLT_VBI";
case oracle::occi::OCCI_SQLT_VST: return "OCCI_SQLT_VST";
case oracle::occi::OCCI_SQLT_RDD: return "OCCI_SQLT_RDD";
case oracle::occi::OCCIDATE: return "OCCIDATE";
case oracle::occi::OCCITIMESTAMP: return "OCCITIMESTAMP";
case oracle::occi::OCCI_SQLT_DAT: return "OCCI_SQLT_DAT";
case oracle::occi::OCCI_SQLT_TIMESTAMP: return "OCCI_SQLT_TIMESTAMP";
case oracle::occi::OCCI_SQLT_TIMESTAMP_LTZ: return "OCCI_SQLT_TIMESTAMP_LTZ";
case oracle::occi::OCCI_SQLT_TIMESTAMP_TZ: return "OCCI_SQLT_TIMESTAMP_TZ";
case oracle::occi::OCCIPOBJECT: return "OCCIPOBJECT";
default: return "<unknown ATTR_DATA_TYPE>";
}
} }
private: private:
occi_environment() Environment()
: env_(0) : env_(0)
{ {
MAPNIK_LOG_DEBUG(occi) << "occi_environment: constructor"; MAPNIK_LOG_DEBUG(occi) << "occi_environment: constructor";
@ -149,7 +188,7 @@ private:
RegisterClasses(env_); RegisterClasses(env_);
} }
~occi_environment() ~Environment()
{ {
MAPNIK_LOG_DEBUG(occi) << "occi_environment: destructor"; MAPNIK_LOG_DEBUG(occi) << "occi_environment: destructor";
@ -160,48 +199,17 @@ private:
oracle::occi::Environment* env_; oracle::occi::Environment* env_;
}; };
class ResultSet
class occi_connection_ptr
{ {
public: public:
explicit occi_connection_ptr() ResultSet(oracle::occi::Connection* conn,
: pool_(0), std::string const& s,
conn_(0), const unsigned prefetch = 0)
stmt_(0), : conn_(conn),
rs_(0), stmt_(NULL),
owns_connection_(false) rs_(NULL),
metadata_queried_(false)
{ {
}
~occi_connection_ptr()
{
close_query(true);
}
void set_pool(oracle::occi::StatelessConnectionPool* pool)
{
close_query(true);
pool_ = pool;
conn_ = pool_->getConnection();
owns_connection_ = true;
}
void set_connection(oracle::occi::Connection* conn, bool owns_connection)
{
close_query(true);
pool_ = 0;
conn_ = conn;
owns_connection_ = owns_connection;
}
oracle::occi::ResultSet* execute_query(std::string const& s, const unsigned prefetch = 0)
{
close_query(false);
MAPNIK_LOG_DEBUG(occi) << "occi_connection_ptr: " << s;
stmt_ = conn_->createStatement(s); stmt_ = conn_->createStatement(s);
if (prefetch > 0) if (prefetch > 0)
@ -211,60 +219,282 @@ public:
} }
rs_ = stmt_->executeQuery(); rs_ = stmt_->executeQuery();
return rs_;
} }
private: virtual ~ResultSet()
void close_query(const bool release_connection)
{ {
if (conn_) close();
}
inline void close()
{
if (stmt_)
{ {
if (stmt_) if (rs_)
{ {
if (rs_) stmt_->closeResultSet(rs_);
{ rs_ = NULL;
stmt_->closeResultSet(rs_);
rs_ = 0;
}
conn_->terminateStatement(stmt_);
stmt_ = 0;
} }
if (release_connection) conn_->terminateStatement(stmt_);
{ stmt_ = NULL;
if (pool_) }
{ }
pool_->releaseConnection(conn_);
} inline bool next()
else {
{ return rs_ && rs_->next() == oracle::occi::ResultSet::DATA_AVAILABLE;
if (owns_connection_) }
{
occi_environment::instance().destroy_connection(conn_); inline int getNumFields()
} {
} query_metadata();
conn_ = 0; return metadata_.size();
} }
inline const char* getFieldName(int index)
{
query_metadata();
if (index >= 0 && (size_t)index < metadata_.size())
{
return metadata_[index].getString(oracle::occi::MetaData::ATTR_NAME).c_str();
}
return NULL;
}
inline int getTypeOID(int index)
{
query_metadata();
if (index >= 0 && (size_t)index < metadata_.size())
{
return metadata_[index].getInt(oracle::occi::MetaData::ATTR_DATA_TYPE);
}
return 0;
}
inline bool isNull(int index) const
{
return rs_->isNull(index);
}
inline int getInt(int index)
{
return rs_->getInt(index);
}
inline float getFloat(int index)
{
return rs_->getFloat(index);
}
inline double getDouble(int index)
{
return rs_->getDouble(index);
}
inline oracle::occi::PObject* getObject(int index)
{
return rs_->getObject(index);
}
inline const char* getString(int index)
{
return rs_->getString(index).c_str();
}
inline unsigned int getBlob(int index, std::vector<char>& buffer)
{
if (! rs_->isNull(index))
{
oracle::occi::Blob blob = rs_->getBlob(1);
blob.open(oracle::occi::OCCI_LOB_READONLY);
unsigned int size = blob.length();
if (buffer.size() < size)
{
buffer.resize(size);
}
oracle::occi::Stream* instream = blob.getStream(1, 0);
instream->readBuffer(buffer.data(), size);
blob.closeStream(instream);
blob.close();
return size;
}
return 0;
}
private:
inline void query_metadata()
{
if (! metadata_queried_ && rs_)
{
metadata_ = rs_->getColumnListMetaData();
metadata_queried_ = true;
} }
} }
oracle::occi::StatelessConnectionPool* pool_;
oracle::occi::Connection* conn_; oracle::occi::Connection* conn_;
oracle::occi::Statement* stmt_; oracle::occi::Statement* stmt_;
oracle::occi::ResultSet* rs_; oracle::occi::ResultSet* rs_;
bool owns_connection_;
std::vector<oracle::occi::MetaData> metadata_;
bool metadata_queried_;
ResultSet(const ResultSet&);
ResultSet& operator=(const ResultSet);
}; };
class occi_enums class Connection
{ {
public: public:
explicit Connection(std::string const& user,
std::string const& pass,
std::string const& host)
: conn_(NULL)
{
MAPNIK_LOG_DEBUG(occi) << "occi_environment: create_connection";
static std::string resolve_gtype(int gtype); conn_ = Environment::instance().get_environment()->createConnection(user, pass, host);
static std::string resolve_etype(int etype); }
static std::string resolve_datatype(int type_id);
~Connection()
{
close();
}
boost::shared_ptr<ResultSet> execute_query(std::string const& s, const unsigned prefetch = 0)
{
MAPNIK_LOG_DEBUG(occi) << "occi_connection_ptr: " << s;
return boost::make_shared<ResultSet>(conn_, s, prefetch);
}
bool isOK()
{
return (conn_ != NULL);
}
void close()
{
if (conn_)
{
MAPNIK_LOG_DEBUG(occi) << "occi_environment: destroy_connection";
Environment::instance().get_environment()->terminateConnection(conn_);
conn_ = NULL;
}
}
private:
oracle::occi::Connection* conn_;
oracle::occi::Statement* stmt_;
oracle::occi::ResultSet* rs_;
Connection(const Connection&);
Connection& operator=(const Connection);
}; };
template <typename T>
class ConnectionCreator
{
public:
ConnectionCreator(boost::optional<std::string> const& user,
boost::optional<std::string> const& pass,
boost::optional<std::string> const& host)
: user_(user),
pass_(pass),
host_(host)
{}
T* operator()() const
{
return new T(*user_, *pass_, *host_);
}
inline std::string id() const
{
return connection_string();
}
inline std::string connection_string() const
{
std::string connect_str = connection_string_safe();
if (pass_ && !pass_->empty()) connect_str += " password=" + *pass_;
return connect_str;
}
inline std::string connection_string_safe() const
{
std::string connect_str;
if (host_ && !host_->empty()) connect_str += "host=" + *host_;
if (user_ && !user_->empty()) connect_str += " user=" + *user_;
return connect_str;
}
private:
boost::optional<std::string> user_;
boost::optional<std::string> pass_;
boost::optional<std::string> host_;
};
class ConnectionManager : public singleton <ConnectionManager,CreateStatic>
{
friend class CreateStatic<ConnectionManager>;
typedef Pool<Connection,ConnectionCreator> PoolType;
typedef std::map<std::string,boost::shared_ptr<PoolType> > ContType;
typedef boost::shared_ptr<Connection> HolderType;
ContType pools_;
public:
bool registerPool(const ConnectionCreator<Connection>& creator,unsigned initialSize,unsigned maxSize)
{
ContType::const_iterator itr = pools_.find(creator.id());
if (itr != pools_.end())
{
itr->second->set_initial_size(initialSize);
itr->second->set_max_size(maxSize);
}
else
{
return pools_.insert(
std::make_pair(creator.id(),
boost::make_shared<PoolType>(creator,initialSize,maxSize))).second;
}
return false;
}
boost::shared_ptr<PoolType> getPool(std::string const& key)
{
ContType::const_iterator itr=pools_.find(key);
if (itr!=pools_.end())
{
return itr->second;
}
static const boost::shared_ptr<PoolType> emptyPool;
return emptyPool;
}
ConnectionManager() {}
private:
ConnectionManager(const ConnectionManager&);
ConnectionManager& operator=(const ConnectionManager);
};
#endif // OCCI_TYPES_HPP #endif // OCCI_TYPES_HPP