diff --git a/plugins/input/occi/occi_datasource.cpp b/plugins/input/occi/occi_datasource.cpp index 6111c7049..1c2240d62 100644 --- a/plugins/input/occi/occi_datasource.cpp +++ b/plugins/input/occi/occi_datasource.cpp @@ -42,6 +42,8 @@ #include #include +using boost::shared_ptr; + using mapnik::datasource; using mapnik::parameters; using mapnik::query; @@ -52,14 +54,7 @@ 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::max(); 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_height_token_("!pixel_height!"), desc_(*params.get("type"), *params.get("encoding", "utf-8")), + creator_(params.get("user"), + params.get("password"), + params.get("host")), use_wkb_(*params.get("use_wkb", false)), row_limit_(*params.get("row_limit", 0)), - row_prefetch_(*params.get("row_prefetch", 100)), - pool_(0), - conn_(0) + row_prefetch_(*params.get("row_prefetch", 100)) { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "occi_datasource::init"); @@ -103,7 +99,7 @@ occi_datasource::occi_datasource(parameters const& params) } estimate_extent_ = *params.get("estimate_extent",false); use_spatial_index_ = *params.get("use_spatial_index",true); - use_connection_pool_ = *params.get("use_connection_pool",true); + persist_connection_ = *params.get("persist_connection",true); boost::optional ext = params.get("extent"); if (ext) extent_initialized_ = extent_.from_string(*ext); @@ -116,222 +112,186 @@ occi_datasource::occi_datasource(parameters const& params) } // connect to environment - if (use_connection_pool_) - { - try - { - pool_ = occi_environment::instance().create_pool( - *params.get("user"), - *params.get("password"), - *params.get("host"), - *params.get("max_size", 5), - *params.get("initial_size", 1), - 1); - } - catch (SQLException& ex) - { - throw datasource_exception("OCCI Plugin: " + ex.getMessage()); - } - } - else - { - try - { - conn_ = occi_environment::instance().create_connection( - *params.get("user"), - *params.get("password"), - *params.get("host")); - } - catch (SQLException& ex) - { - throw datasource_exception("OCCI Plugin: " + ex.getMessage()); - } - } + boost::optional initial_size = params.get("initial_size", 1); + boost::optional max_size = params.get("max_size", 10); - // extract real table name - table_name_ = mapnik::sql_utils::table_from_sql(table_); + ConnectionManager::instance().registerPool(creator_, *initial_size, *max_size); + shared_ptr< Pool > pool = + ConnectionManager::instance().getPool(creator_.id()); - // get SRID and/or GEOMETRY_FIELD from metadata table only if we need to - if (! srid_initialized_ || geometry_field_ == "") + if (pool) { + shared_ptr 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 - 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 - std::ostringstream s; - s << "SELECT srid, column_name FROM " << METADATA_TABLE << " WHERE"; - s << " LOWER(table_name) = LOWER('" << table_name_ << "')"; + 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 (geometry_field_ != "") { - if (! srid_initialized_) - { - srid_ = rs->getInt(1); - srid_initialized_ = true; - } - - if (geometry_field_ == "") - { - geometry_field_ = rs->getString(2); - } + s << " AND LOWER(column_name) = LOWER('" << geometry_field_ << "')"; } - } - 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 + MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); - 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) + try { - std::vector listOfColumns = rs->getColumnListMetaData(); - - for (unsigned int i = 0; i < listOfColumns.size(); ++i) + shared_ptr rs = conn->execute_query(s.str()); + if (rs && rs->next()) { - 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) + if (! srid_initialized_) { - 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; + srid_ = rs->getInt(1); + srid_initialized_ = true; } + + 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 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() { - if (use_connection_pool_) + if (! persist_connection_) { - if (pool_ != 0) + shared_ptr< Pool > pool = + ConnectionManager::instance().getPool(creator_.id()); + if (pool) { - occi_environment::instance().destroy_pool(pool_); - } - } - else - { - if (conn_ != 0) - { - occi_environment::instance().destroy_connection(conn_); + shared_ptr conn = pool->borrowObject(); + if (conn) + { + conn->close(); + } } } } @@ -352,87 +312,91 @@ box2d occi_datasource::envelope() const double lox = 0.0, loy = 0.0, hix = 0.0, hiy = 0.0; - - if (estimate_extent_) + shared_ptr< Pool > pool = + ConnectionManager::instance().getPool(creator_.id()); + if (pool) { + shared_ptr conn = pool->borrowObject(); + if (conn) + { + if (estimate_extent_) + { #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 - 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"; + 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(); + 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); + try + { + shared_ptr 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; - 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; + rs->close(); + } + } + catch (SQLException& ex) + { + throw datasource_exception("OCCI Plugin: " + ex.getMessage()); + } } - } - catch (SQLException& ex) - { - throw datasource_exception("OCCI Plugin: " + ex.getMessage()); - } - } - else if (use_spatial_index_) - { + else if (use_spatial_index_) + { #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 - 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'"; + 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(); + 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()) + try { - lox = rs->getDouble(1); - hix = rs->getDouble(2); - } + shared_ptr 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); + if (rs->next()) + { + loy = rs->getDouble(1); + 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_) @@ -505,71 +469,78 @@ featureset_ptr occi_datasource::features(query const& q) const mapnik::progress_timer __stats__(std::clog, "occi_datasource::features"); #endif - box2d const& box = q.get_bbox(); - const double px_gw = 1.0 / boost::get<0>(q.resolution()); - const double px_gh = 1.0 / boost::get<1>(q.resolution()); - const double scale_denom = q.scale_denominator(); - - std::ostringstream s; - s << "SELECT "; - if (use_wkb_) + shared_ptr< Pool > pool = + ConnectionManager::instance().getPool(creator_.id()); + if (pool) { - s << "SDO_UTIL.TO_WKBGEOMETRY(" << geometry_field_ << ")"; - } - else - { - s << geometry_field_; - } - std::set const& props = q.property_names(); - std::set::const_iterator pos = props.begin(); - std::set::const_iterator end = props.end(); - mapnik::context_ptr ctx = boost::make_shared(); - 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")) + shared_ptr conn = pool->borrowObject(); + if (conn) { - 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"; + box2d const& box = q.get_bbox(); + const double px_gw = 1.0 / boost::get<0>(q.resolution()); + const double px_gh = 1.0 / boost::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 const& props = q.property_names(); + std::set::const_iterator pos = props.begin(); + std::set::const_iterator end = props.end(); + mapnik::context_ptr ctx = boost::make_shared(); + 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(conn->execute_query(s.str(), row_prefetch_), + ctx, + desc_.get_encoding(), + use_wkb_); } } - s << " FROM " << query; - - if (row_limit_ > 0) - { - s << " WHERE ROWNUM < " << row_limit_; - } - - MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); - - return boost::make_shared(pool_, - conn_, - ctx, - s.str(), - desc_.get_encoding(), - use_connection_pool_, - use_wkb_, - row_prefetch_); + return featureset_ptr(); } 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"); #endif - std::ostringstream s; - s << "SELECT "; - if (use_wkb_) + shared_ptr< Pool > pool = + ConnectionManager::instance().getPool(creator_.id()); + if (pool) { - s << "SDO_UTIL.TO_WKBGEOMETRY(" << geometry_field_ << ")"; - } - else - { - s << geometry_field_; - } - std::vector::const_iterator itr = desc_.get_descriptors().begin(); - std::vector::const_iterator end = desc_.get_descriptors().end(); - mapnik::context_ptr ctx = boost::make_shared(); - while (itr != end) - { - s << ", " << itr->get_name(); - ctx->push(itr->get_name()); - ++itr; - } - - box2d 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")) + shared_ptr conn = pool->borrowObject(); + if (conn) { - 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"; + std::ostringstream s; + s << "SELECT "; + if (use_wkb_) + { + s << "SDO_UTIL.TO_WKBGEOMETRY(" << geometry_field_ << ")"; + } + else + { + s << geometry_field_; + } + std::vector::const_iterator itr = desc_.get_descriptors().begin(); + std::vector::const_iterator end = desc_.get_descriptors().end(); + mapnik::context_ptr ctx = boost::make_shared(); + while (itr != end) + { + s << ", " << itr->get_name(); + ctx->push(itr->get_name()); + ++itr; + } + + box2d 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(conn->execute_query(s.str(), row_prefetch_), + ctx, + desc_.get_encoding(), + use_wkb_); } } - s << " FROM " << query; - - if (row_limit_ > 0) - { - s << " WHERE ROWNUM < " << row_limit_; - } - - MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); - - return boost::make_shared(pool_, - conn_, - ctx, - s.str(), - desc_.get_encoding(), - use_connection_pool_, - use_wkb_, - row_prefetch_); + return featureset_ptr(); } diff --git a/plugins/input/occi/occi_datasource.hpp b/plugins/input/occi/occi_datasource.hpp index 10261f19a..5b277714b 100644 --- a/plugins/input/occi/occi_datasource.hpp +++ b/plugins/input/occi/occi_datasource.hpp @@ -82,12 +82,11 @@ private: const std::string pixel_width_token_; const std::string pixel_height_token_; mapnik::layer_descriptor desc_; + ConnectionCreator creator_; bool use_wkb_; mapnik::value_integer row_limit_; int row_prefetch_; - oracle::occi::StatelessConnectionPool* pool_; - oracle::occi::Connection* conn_; - bool use_connection_pool_; + bool persist_connection_; bool use_spatial_index_; bool estimate_extent_; }; diff --git a/plugins/input/occi/occi_featureset.cpp b/plugins/input/occi/occi_featureset.cpp index 9a2eb67b1..db285c924 100644 --- a/plugins/input/occi/occi_featureset.cpp +++ b/plugins/input/occi/occi_featureset.cpp @@ -43,49 +43,22 @@ using mapnik::transcoder; using mapnik::datasource_exception; 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::SQLException; using oracle::occi::Type; using oracle::occi::Number; using oracle::occi::Blob; -occi_featureset::occi_featureset(StatelessConnectionPool* pool, - Connection* conn, +occi_featureset::occi_featureset(boost::shared_ptr rs, mapnik::context_ptr const& ctx, - std::string const& sqlstring, std::string const& encoding, - bool use_connection_pool, - bool use_wkb, - unsigned prefetch_rows) - : rs_(NULL), + bool use_wkb) + : rs_(rs), tr_(new transcoder(encoding)), feature_id_(1), ctx_(ctx), 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() @@ -94,25 +67,13 @@ occi_featureset::~occi_featureset() 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_)); if (use_wkb_) { - 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(); + unsigned int size = rs_->getBlob(1, buffer_); if (! geometry_utils::from_wkb(feature->paths(), buffer_.data(), size)) { @@ -132,22 +93,11 @@ feature_ptr occi_featureset::next() } } - std::vector listOfColumns = rs_->getColumnListMetaData(); - - for (unsigned int i = 1; i < listOfColumns.size(); ++i) + unsigned int numFields = rs_->getNumFields(); + for (unsigned int i = 0; i < numFields; ++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) - { - continue; - } - */ + std::string fld_name = rs_->getFieldName(i); + int type_oid = rs_->getTypeOID(i); switch (type_oid) { @@ -192,7 +142,7 @@ feature_ptr occi_featureset::next() case oracle::occi::OCCI_SQLT_TIMESTAMP: case oracle::occi::OCCI_SQLT_TIMESTAMP_LTZ: 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; case oracle::occi::OCCIINTERVALDS: case oracle::occi::OCCIINTERVALYM: @@ -218,7 +168,7 @@ feature_ptr occi_featureset::next() case oracle::occi::OCCI_SQLT_RSET: { MAPNIK_LOG_WARN(occi) << "occi_featureset: Unsupported datatype " - << occi_enums::resolve_datatype(type_oid) + << Environment::instance().resolve_datatype(type_oid) << " (type_oid=" << type_oid << ")"; break; } @@ -368,7 +318,7 @@ void occi_featureset::convert_geometry(SDOGeometry* geom, feature_ptr feature) default: { MAPNIK_LOG_WARN(occi) << "occi_featureset: Unknown oracle enum " - << occi_enums::resolve_gtype(geomtype) + << Environment::instance().resolve_gtype(geomtype) << "(gtype=" << gtype << ")"; } break; diff --git a/plugins/input/occi/occi_featureset.hpp b/plugins/input/occi/occi_featureset.hpp index cb4e7cb9e..798d2f9ee 100644 --- a/plugins/input/occi/occi_featureset.hpp +++ b/plugins/input/occi/occi_featureset.hpp @@ -41,14 +41,10 @@ class occi_featureset : public mapnik::Featureset { public: - occi_featureset(oracle::occi::StatelessConnectionPool* pool, - oracle::occi::Connection* conn, + occi_featureset(boost::shared_ptr rs, mapnik::context_ptr const& ctx, - std::string const& sqlstring, std::string const& encoding, - bool use_connection_pool, - bool use_wkb, - unsigned prefetch_rows); + bool use_wkb); virtual ~occi_featureset(); mapnik::feature_ptr next(); @@ -68,8 +64,7 @@ private: const int dimensions, const bool is_point_geom); - occi_connection_ptr conn_; - oracle::occi::ResultSet* rs_; + boost::shared_ptr rs_; boost::scoped_ptr tr_; mapnik::value_integer feature_id_; mapnik::context_ptr ctx_; diff --git a/plugins/input/occi/occi_types.cpp b/plugins/input/occi/occi_types.cpp index 0545b80fa..ad54aece2 100644 --- a/plugins/input/occi/occi_types.cpp +++ b/plugins/input/occi/occi_types.cpp @@ -21,71 +21,3 @@ *****************************************************************************/ #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 ""; - } -} - -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 ""; - } -} - -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 ""; - } -} diff --git a/plugins/input/occi/occi_types.hpp b/plugins/input/occi/occi_types.hpp index 896219a62..f2ec3930a 100644 --- a/plugins/input/occi/occi_types.hpp +++ b/plugins/input/occi/occi_types.hpp @@ -25,13 +25,22 @@ // mapnik #include +#include #include // boost +#include +#include +#include + #ifdef MAPNIK_THREADSAFE #include #endif +// stl +#include +#include + // occi #include @@ -46,6 +55,10 @@ #error Only ORACLE 10g >= 10.2.0.X is supported ! #endif +using mapnik::Pool; +using mapnik::singleton; +using mapnik::CreateStatic; + // geometry types definitions enum { @@ -83,9 +96,9 @@ enum SDO_INTERPRETATION_CIRCULAR = 2 }; -class occi_environment : public mapnik::singleton +class Environment : public mapnik::singleton { - friend class mapnik::CreateStatic; + friend class mapnik::CreateStatic; public: @@ -94,51 +107,77 @@ public: return env_; } - oracle::occi::Connection* create_connection( - const std::string& user, - const std::string& password, - const std::string& host) + std::string resolve_gtype(int gtype) { - MAPNIK_LOG_DEBUG(occi) << "occi_environment: create_connection"; - - return env_->createConnection(user, password, host); + 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 ""; + } } - 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 ""; + } } - oracle::occi::StatelessConnectionPool* create_pool( - const std::string& user, - const std::string& password, - const std::string& host, - int max_size, - int initial_size, - int incr_size) + std::string resolve_datatype(int type_id) { - MAPNIK_LOG_DEBUG(occi) << "occi_environment: create_pool"; - - return env_->createStatelessConnectionPool( - user, - password, - host, - max_size, - initial_size, - incr_size, - oracle::occi::StatelessConnectionPool::HOMOGENEOUS); - } - - void destroy_pool(oracle::occi::StatelessConnectionPool* pool) - { - env_->terminateStatelessConnectionPool( - pool, - oracle::occi::StatelessConnectionPool::SPD_FORCE); + 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 ""; + } } private: - occi_environment() + Environment() : env_(0) { MAPNIK_LOG_DEBUG(occi) << "occi_environment: constructor"; @@ -149,7 +188,7 @@ private: RegisterClasses(env_); } - ~occi_environment() + ~Environment() { MAPNIK_LOG_DEBUG(occi) << "occi_environment: destructor"; @@ -160,48 +199,17 @@ private: oracle::occi::Environment* env_; }; - -class occi_connection_ptr +class ResultSet { public: - explicit occi_connection_ptr() - : pool_(0), - conn_(0), - stmt_(0), - rs_(0), - owns_connection_(false) + ResultSet(oracle::occi::Connection* conn, + std::string const& s, + const unsigned prefetch = 0) + : conn_(conn), + stmt_(NULL), + 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); if (prefetch > 0) @@ -211,60 +219,282 @@ public: } rs_ = stmt_->executeQuery(); - - return rs_; } -private: - void close_query(const bool release_connection) + virtual ~ResultSet() { - if (conn_) + close(); + } + + inline void close() + { + if (stmt_) { - if (stmt_) + if (rs_) { - if (rs_) - { - stmt_->closeResultSet(rs_); - rs_ = 0; - } - - conn_->terminateStatement(stmt_); - stmt_ = 0; + stmt_->closeResultSet(rs_); + rs_ = NULL; } - if (release_connection) - { - if (pool_) - { - pool_->releaseConnection(conn_); - } - else - { - if (owns_connection_) - { - occi_environment::instance().destroy_connection(conn_); - } - } - - conn_ = 0; - } + conn_->terminateStatement(stmt_); + stmt_ = NULL; + } + } + + inline bool next() + { + return rs_ && rs_->next() == oracle::occi::ResultSet::DATA_AVAILABLE; + } + + inline int getNumFields() + { + query_metadata(); + + 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& 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::Statement* stmt_; oracle::occi::ResultSet* rs_; - bool owns_connection_; + + std::vector metadata_; + bool metadata_queried_; + + ResultSet(const ResultSet&); + ResultSet& operator=(const ResultSet); }; -class occi_enums +class Connection { 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); - static std::string resolve_etype(int etype); - static std::string resolve_datatype(int type_id); + conn_ = Environment::instance().get_environment()->createConnection(user, pass, host); + } + + ~Connection() + { + close(); + } + + boost::shared_ptr execute_query(std::string const& s, const unsigned prefetch = 0) + { + MAPNIK_LOG_DEBUG(occi) << "occi_connection_ptr: " << s; + + return boost::make_shared(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 +class ConnectionCreator +{ + +public: + ConnectionCreator(boost::optional const& user, + boost::optional const& pass, + boost::optional 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 user_; + boost::optional pass_; + boost::optional host_; +}; + +class ConnectionManager : public singleton +{ + + friend class CreateStatic; + typedef Pool PoolType; + typedef std::map > ContType; + typedef boost::shared_ptr HolderType; + ContType pools_; + +public: + + bool registerPool(const ConnectionCreator& 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(creator,initialSize,maxSize))).second; + } + return false; + + } + + boost::shared_ptr getPool(std::string const& key) + { + ContType::const_iterator itr=pools_.find(key); + if (itr!=pools_.end()) + { + return itr->second; + } + static const boost::shared_ptr emptyPool; + return emptyPool; + } + + ConnectionManager() {} +private: + ConnectionManager(const ConnectionManager&); + ConnectionManager& operator=(const ConnectionManager); +}; + + #endif // OCCI_TYPES_HPP