static bool detect_types_from_subquery(std::string const& query, std::string & geometry_field, mapnik::layer_descriptor & desc, boost::shared_ptr<sqlite_connection> ds) { bool found = false; boost::shared_ptr<sqlite_resultset> rs(ds->execute_query(query)); if (rs->is_valid() && rs->step_next()) { for (int i = 0; i < rs->column_count(); ++i) { found = true; const int type_oid = rs->column_type(i); const char* fld_name = rs->column_name(i); switch (type_oid) { case SQLITE_INTEGER: desc.add_descriptor(mapnik::attribute_descriptor(fld_name, mapnik::Integer)); break; case SQLITE_FLOAT: desc.add_descriptor(mapnik::attribute_descriptor(fld_name, mapnik::Double)); break; case SQLITE_TEXT: desc.add_descriptor(mapnik::attribute_descriptor(fld_name, mapnik::String)); break; case SQLITE_NULL: // sqlite reports based on value, not actual column type unless // PRAGMA table_info is used so here we assume the column is a string // which is a lesser evil than altogether dropping the column desc.add_descriptor(mapnik::attribute_descriptor(fld_name, mapnik::String)); break; case SQLITE_BLOB: if (geometry_field.empty() && (boost::algorithm::icontains(fld_name, "geom") || boost::algorithm::icontains(fld_name, "point") || boost::algorithm::icontains(fld_name, "linestring") || boost::algorithm::icontains(fld_name, "polygon"))) { geometry_field = std::string(fld_name); } break; default: #ifdef MAPNIK_DEBUG std::clog << "Sqlite Plugin: unknown type_oid=" << type_oid << std::endl; #endif break; } } } return found; }
static bool table_info(std::string & key_field, bool detected_types, std::string & field, std::string & table, mapnik::layer_descriptor & desc, std::shared_ptr<sqlite_connection> ds) { // http://www.sqlite.org/pragma.html#pragma_table_info // use pragma table_info to detect primary key // and to detect types if no subquery is used or // if the subquery-based type detection failed std::ostringstream s; s << "PRAGMA table_info(" << table << ")"; std::shared_ptr<sqlite_resultset> rs(ds->execute_query(s.str())); bool found_table = false; bool found_pk = false; while (rs->is_valid() && rs->step_next()) { found_table = true; const char* fld_name = rs->column_text(1); std::string fld_type(rs->column_text(2)); sqlite_int64 fld_pk = rs->column_integer64(5); std::transform(fld_type.begin(), fld_type.end(), fld_type.begin(), ::tolower); // TODO - how to handle primary keys on multiple columns ? if (key_field.empty() && ! found_pk && fld_pk != 0) { key_field = fld_name; found_pk = true; } if (! detected_types) { // see 2.1 "Column Affinity" at http://www.sqlite.org/datatype3.html // TODO - refactor this somehow ? if (field.empty() && ((boost::algorithm::contains(fld_type, "geom") || boost::algorithm::contains(fld_type, "point") || boost::algorithm::contains(fld_type, "linestring") || boost::algorithm::contains(fld_type, "polygon")) || (boost::algorithm::icontains(fld_name, "geom") || boost::algorithm::icontains(fld_name, "point") || boost::algorithm::icontains(fld_name, "linestring") || boost::algorithm::icontains(fld_name, "polygon"))) ) { field = std::string(fld_name); } else if (boost::algorithm::contains(fld_type, "int")) { desc.add_descriptor(mapnik::attribute_descriptor(fld_name, mapnik::Integer)); } else if (boost::algorithm::contains(fld_type, "text") || boost::algorithm::contains(fld_type, "char") || boost::algorithm::contains(fld_type, "clob")) { desc.add_descriptor(mapnik::attribute_descriptor(fld_name, mapnik::String)); } else if (boost::algorithm::contains(fld_type, "real") || boost::algorithm::contains(fld_type, "floa") || boost::algorithm::contains(fld_type, "doub")) { desc.add_descriptor(mapnik::attribute_descriptor(fld_name, mapnik::Double)); } else if (boost::algorithm::contains(fld_type, "blob")) { if (! field.empty()) { desc.add_descriptor(mapnik::attribute_descriptor(fld_name, mapnik::String)); } } else { // "Column Affinity" says default to "Numeric" but for now we pass.. //desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); desc.add_descriptor(mapnik::attribute_descriptor(fld_name, mapnik::String)); #ifdef MAPNIK_LOG // Do not fail when we specify geometry_field in XML file if (field.empty()) { MAPNIK_LOG_DEBUG(sqlite) << "Column '" << std::string(fld_name) << "' unhandled due to unknown type: '" << fld_type << "', using String"; } #endif } } } return found_table; }