Ejemplo n.º 1
0
size_t middle_ram_t::ways_get_list(const idlist_t &ids, idlist_t &way_ids,
                                multitaglist_t &tags, multinodelist_t &nodes) const
{
    if (ids.empty())
    {
        return 0;
    }

    assert(way_ids.empty());
    tags.assign(ids.size(), taglist_t());
    nodes.assign(ids.size(), nodelist_t());

    size_t count = 0;
    for (idlist_t::const_iterator it = ids.begin(); it != ids.end(); ++it) {
        if (ways_get(*it, tags[count], nodes[count])) {
            way_ids.push_back(*it);
            count++;
        } else {
            tags[count].clear();
            nodes[count].clear();
        }
    }

    if (count < ids.size()) {
        tags.resize(count);
        nodes.resize(count);
    }

    return int(count);
}
Ejemplo n.º 2
0
size_t middle_pgsql_t::ways_get_list(const idlist_t &ids, osmium::memory::Buffer &buffer) const
{
    if (ids.empty())
        return 0;

    char tmp[16];
    std::unique_ptr<char[]> tmp2(new (std::nothrow) char[ids.size() * 16]);
    char const *paramValues[1];

    if (tmp2 == nullptr) return 0; //failed to allocate memory, return */

    // create a list of ids in tmp2 to query the database  */
    sprintf(tmp2.get(), "{");
    for (auto id : ids) {
        snprintf(tmp, sizeof(tmp), "%" PRIdOSMID ",", id);
        strncat(tmp2.get(), tmp, sizeof(char)*(ids.size()*16 - 2));
    }
    tmp2[strlen(tmp2.get()) - 1] = '}'; // replace last , with } to complete list of ids*/

    pgsql_endCopy(way_table);

    PGconn *sql_conn = way_table->sql_conn;

    paramValues[0] = tmp2.get();
    PGresult *res = pgsql_execPrepared(sql_conn, "get_way_list", 1, paramValues, PGRES_TUPLES_OK);
    int countPG = PQntuples(res);

    idlist_t wayidspg;

    for (int i = 0; i < countPG; i++) {
        wayidspg.push_back(strtoosmid(PQgetvalue(res, i, 0), nullptr, 10));
    }


    // Match the list of ways coming from postgres in a different order
    //   back to the list of ways given by the caller */
    int outres = 0;
    for (auto id : ids) {
        for (int j = 0; j < countPG; j++) {
            if (id == wayidspg[j]) {
                {
                    osmium::builder::WayBuilder builder(buffer);
                    builder.set_id(id);

                    pgsql_parse_nodes(PQgetvalue(res, j, 1), buffer, builder);
                    pgsql_parse_tags(PQgetvalue(res, j, 2), buffer, builder);
                }

                buffer.commit();
                outres++;
                break;
            }
        }
    }

    PQclear(res);

    return outres;
}
Ejemplo n.º 3
0
 int way_add(osmid_t id, const idlist_t &nds, const taglist_t &tags) {
     assert(id > 0);
     sum_ids += id;
     num_ways += 1;
     assert(nds.size() >= 0);
     num_nds += uint64_t(nds.size());
     return 0;
 }
Ejemplo n.º 4
0
void middle_pgsql_t::ways_set(osmid_t way_id, const idlist_t &nds, const taglist_t &tags)
{
    copy_buffer.reserve(nds.size() * 10 + tags.size() * 24 + 64);
    bool copy = way_table->copyMode;
    char delim = copy ? '\t' : '\0';
    // Three params: id, nodes, tags */
    const char *paramValues[4] = { copy_buffer.c_str(), };

    copy_buffer = std::to_string(way_id);
    copy_buffer += delim;

    paramValues[1] = paramValues[0] + copy_buffer.size();
    buffer_store_nodes(nds);
    copy_buffer += delim;

    if (tags.size() == 0) {
        paramValues[2] = nullptr;
        copy_buffer += "\\N";
    } else {
        paramValues[2] = paramValues[0] + copy_buffer.size();
        buffer_store_tags(tags, copy);
    }

    if (copy) {
        copy_buffer += '\n';
        pgsql_CopyData(__FUNCTION__, way_table->sql_conn, copy_buffer);
    } else {
        buffer_correct_params(paramValues, 3);
        pgsql_execPrepared(way_table->sql_conn, "insert_way", 3,
                           (const char * const *)paramValues, PGRES_COMMAND_OK);
    }
}
Ejemplo n.º 5
0
void middle_pgsql_t::buffer_store_nodes(idlist_t const &nds)
{
    if (nds.size() == 0) {
        copy_buffer += "{}";
        return;
    }

    copy_buffer += "{";

    for (auto const &it : nds) {
        copy_buffer += std::to_string(it);
        copy_buffer += ',';
    }

    copy_buffer[copy_buffer.size() - 1] = '}';
}
int output_multi_t::way_add(osmid_t id, const idlist_t &nodes, const taglist_t &tags) {
    if (m_processor->interests(geometry_processor::interest_way) && nodes.size() > 1) {
        return process_way(id, nodes, tags);
    }
    return 0;
}
Ejemplo n.º 7
0
size_t middle_pgsql_t::ways_get_list(const idlist_t &ids, idlist_t &way_ids,
                                  multitaglist_t &tags, multinodelist_t &nodes) const {
    if (ids.empty())
        return 0;

    char tmp[16];
    std::unique_ptr<char[]> tmp2(new (std::nothrow) char[ids.size() * 16]);
    char const *paramValues[1];

    if (tmp2 == nullptr) return 0; //failed to allocate memory, return */

    // create a list of ids in tmp2 to query the database  */
    sprintf(tmp2.get(), "{");
    for(idlist_t::const_iterator it = ids.begin(); it != ids.end(); ++it) {
        snprintf(tmp, sizeof(tmp), "%" PRIdOSMID ",", *it);
        strncat(tmp2.get(), tmp, sizeof(char)*(ids.size()*16 - 2));
    }
    tmp2[strlen(tmp2.get()) - 1] = '}'; // replace last , with } to complete list of ids*/

    pgsql_endCopy(way_table);

    PGconn *sql_conn = way_table->sql_conn;

    paramValues[0] = tmp2.get();
    PGresult *res = pgsql_execPrepared(sql_conn, "get_way_list", 1, paramValues, PGRES_TUPLES_OK);
    int countPG = PQntuples(res);

    idlist_t wayidspg;

    for (int i = 0; i < countPG; i++) {
        wayidspg.push_back(strtoosmid(PQgetvalue(res, i, 0), nullptr, 10));
    }


    // Match the list of ways coming from postgres in a different order
    //   back to the list of ways given by the caller */
    for(idlist_t::const_iterator it = ids.begin(); it != ids.end(); ++it) {
        for (int j = 0; j < countPG; j++) {
            if (*it == wayidspg[j]) {
                way_ids.push_back(*it);
                tags.push_back(taglist_t());
                pgsql_parse_tags(PQgetvalue(res, j, 2), tags.back());

                size_t num_nodes = strtoul(PQgetvalue(res, j, 3), nullptr, 10);
                idlist_t list;
                pgsql_parse_nodes( PQgetvalue(res, j, 1), list);
                if (num_nodes != list.size()) {
                    fprintf(stderr, "parse_nodes problem for way %s: expected nodes %zu got %zu\n",
                            tmp, num_nodes, list.size());
                    util::exit_nicely();
                }

                nodes.push_back(nodelist_t());
                nodes_get_list(nodes.back(), list);

                break;
            }
        }
    }

    assert(way_ids.size() <= ids.size());

    PQclear(res);

    return way_ids.size();
}
Ejemplo n.º 8
0
/* Implements the mid-layer processing for osm2pgsql
 * using several PostgreSQL tables
 *
 * This layer stores data read in from the planet.osm file
 * and is then read by the backend processing code to
 * emit the final geometry-enabled output formats
*/

#include "config.h"

#ifdef _WIN32
using namespace std;
#endif

#ifdef _MSC_VER
#define alloca _alloca
#endif

#include <stdexcept>
#include <unordered_map>

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <future>

#include <boost/format.hpp>

#include <libpq-fe.h>

#include "middle-pgsql.hpp"
#include "node-persistent-cache.hpp"
#include "node-ram-cache.hpp"
#include "options.hpp"
#include "osmtypes.hpp"
#include "output-pgsql.hpp"
#include "pgsql.hpp"
#include "util.hpp"

enum table_id {
    t_node, t_way, t_rel
} ;

middle_pgsql_t::table_desc::table_desc(const char *name_,
                                       const char *start_,
                                       const char *create_,
                                       const char *create_index_,
                                       const char *prepare_,
                                       const char *prepare_intarray_,
                                       const char *copy_,
                                       const char *analyze_,
                                       const char *stop_,
                                       const char *array_indexes_)
    : name(name_),
      start(start_),
      create(create_),
      create_index(create_index_),
      prepare(prepare_),
      prepare_intarray(prepare_intarray_),
      copy(copy_),
      analyze(analyze_),
      stop(stop_),
      array_indexes(array_indexes_),
      copyMode(0),
      transactionMode(0),
      sql_conn(nullptr)
{}

namespace {
// Decodes a portion of an array literal from postgres */
// Argument should point to beginning of literal, on return points to delimiter */
inline const char *decode_upto( const char *src, char *dst )
{
  int quoted = (*src == '"');
  if( quoted ) src++;

  while( quoted ? (*src != '"') : (*src != ',' && *src != '}') )
  {
    if( *src == '\\' )
    {
      switch( src[1] )
      {
        case 'n': *dst++ = '\n'; break;
        case 't': *dst++ = '\t'; break;
        default: *dst++ = src[1]; break;
      }
      src+=2;
    }
    else
      *dst++ = *src++;
  }
  if( quoted ) src++;
  *dst = 0;
  return src;
}

void pgsql_parse_tags(const char *string, taglist_t &tags)
{
  char key[1024];
  char val[1024];

  if( *string == '\0' )
    return;

  if( *string++ != '{' )
    return;
  while( *string != '}' )
  {
    string = decode_upto( string, key );
    // String points to the comma */
    string++;
    string = decode_upto( string, val );
    // String points to the comma or closing '}' */
    tags.push_back(tag_t(key, val));
    if( *string == ',' )
      string++;
  }
}

// Parses an array of integers */
void pgsql_parse_nodes(const char *string, idlist_t &nds)
{
  if( *string++ != '{' )
    return;

  while( *string != '}' )
  {
    char *ptr;
    nds.push_back(strtoosmid( string, &ptr, 10 ));
    string = ptr;
    if( *string == ',' )
      string++;
  }
}

int pgsql_endCopy(middle_pgsql_t::table_desc *table)
{
    // Terminate any pending COPY */
    if (table->copyMode) {
        PGconn *sql_conn = table->sql_conn;
        int stop = PQputCopyEnd(sql_conn, nullptr);
        if (stop != 1) {
            fprintf(stderr, "COPY_END for %s failed: %s\n", table->copy, PQerrorMessage(sql_conn));
            util::exit_nicely();
        }

        PGresult *res = PQgetResult(sql_conn);
        if (PQresultStatus(res) != PGRES_COMMAND_OK) {
            fprintf(stderr, "COPY_END for %s failed: %s\n", table->copy, PQerrorMessage(sql_conn));
            PQclear(res);
            util::exit_nicely();
        }
        PQclear(res);
        table->copyMode = 0;
    }
    return 0;
}
} // anonymous namespace


void middle_pgsql_t::buffer_store_nodes(idlist_t const &nds)
{
    if (nds.size() == 0) {
        copy_buffer += "{}";
        return;
    }

    copy_buffer += "{";

    for (auto const &it : nds) {
        copy_buffer += std::to_string(it);
        copy_buffer += ',';
    }

    copy_buffer[copy_buffer.size() - 1] = '}';
}

void middle_pgsql_t::buffer_store_string(std::string const &in, bool escape)
{
    for (char const c: in) {
        switch (c) {
            case '"':
                if (escape) copy_buffer += "\\";
                copy_buffer += "\\\"";
                break;
            case '\\':
                if (escape) copy_buffer += "\\\\";
                copy_buffer += "\\\\";
                break;
            case '\n':
                if (escape) copy_buffer += "\\";
                copy_buffer += "\\n";
                break;
            case '\r':
                if (escape) copy_buffer += "\\";
                copy_buffer += "\\r";
                break;
            case '\t':
                if (escape) copy_buffer += "\\";
                copy_buffer += "\\t";
                break;
            default:
                copy_buffer += c;
                break;
        }
    }
}

// escape means we return '\N' for copy mode, otherwise we return just nullptr
void middle_pgsql_t::buffer_store_tags(taglist_t const &tags, bool escape)
{
    copy_buffer += "{";

    bool first = true;
    for (auto const &it : tags) {
        if (!first) {
            copy_buffer += ',';
        }
        copy_buffer += "\"";
        buffer_store_string(it.key, escape);
        copy_buffer += "\",\"";
        buffer_store_string(it.value, escape);
        copy_buffer += '"';

        first = false;
    }

    copy_buffer += "}";
}

void middle_pgsql_t::buffer_correct_params(char const **param, size_t size)
{
    if (copy_buffer.c_str() != param[0]) {
        auto diff = copy_buffer.c_str() - param[0];
        for (size_t i = 0; i < size; ++i) {
            if (param[i]) {
                param[i] += diff;
            }
        }
    }
}

void middle_pgsql_t::local_nodes_set(osmid_t id, double lat, double lon,
                                     const taglist_t &tags)
{
    copy_buffer.reserve(tags.size() * 24 + 64);

    bool copy = node_table->copyMode;
    char delim = copy ? '\t' : '\0';
    const char *paramValues[4] = { copy_buffer.c_str(), };

    copy_buffer = std::to_string(id);
    copy_buffer += delim;

#ifdef FIXED_POINT
    ramNode n(lon, lat);
    paramValues[1] = paramValues[0] + copy_buffer.size();
    copy_buffer += std::to_string(n.int_lat());
    copy_buffer += delim;

    paramValues[2] = paramValues[0] + copy_buffer.size();
    copy_buffer += std::to_string(n.int_lon());
    copy_buffer += delim;
#else
    paramValues[1] = paramValues[0] + copy_buffer.size();
    copy_buffer += std::to_string(lat);
    copy_buffer += delim;

    paramValues[2] = paramValues[0] + copy_buffer.size();
    copy_buffer += std::to_string(lon);
    copy_buffer += delim;
#endif

    if (tags.size() == 0) {
        paramValues[3] = nullptr;
        copy_buffer += "\\N";
    } else {
        paramValues[3] = paramValues[0] + copy_buffer.size();
        buffer_store_tags(tags, copy);
    }

    if (copy) {
        copy_buffer += '\n';
        pgsql_CopyData(__FUNCTION__, node_table->sql_conn, copy_buffer);
    } else {
        buffer_correct_params(paramValues, 4);
        pgsql_execPrepared(node_table->sql_conn, "insert_node", 4,
                           (const char * const *)paramValues, PGRES_COMMAND_OK);
    }
}

// This should be made more efficient by using an IN(ARRAY[]) construct */
size_t middle_pgsql_t::local_nodes_get_list(nodelist_t &out, const idlist_t nds) const
{
    assert(out.empty());

    char tmp[16];

    char *tmp2 = static_cast<char *>(malloc(sizeof(char) * nds.size() * 16));
    if (tmp2 == nullptr) return 0; //failed to allocate memory, return */


    // create a list of ids in tmp2 to query the database  */
    sprintf(tmp2, "{");
    int countDB = 0;
    for(idlist_t::const_iterator it = nds.begin(); it != nds.end(); ++it) {
        // Check cache first */
        osmNode loc;
        if (cache->get(&loc, *it) == 0) {
            out.push_back(loc);
            continue;
        }

        countDB++;
        // Mark nodes as needing to be fetched from the DB */
        out.push_back(osmNode());

        snprintf(tmp, sizeof(tmp), "%" PRIdOSMID ",", *it);
        strncat(tmp2, tmp, sizeof(char)*(nds.size()*16 - 2));
    }
    tmp2[strlen(tmp2) - 1] = '}'; // replace last , with } to complete list of ids*/

    if (countDB == 0) {
        free(tmp2);
        return nds.size(); // All ids where in cache, so nothing more to do */
    }

    pgsql_endCopy(node_table);

    PGconn *sql_conn = node_table->sql_conn;

    char const *paramValues[1];
    paramValues[0] = tmp2;
    PGresult *res = pgsql_execPrepared(sql_conn, "get_node_list", 1, paramValues, PGRES_TUPLES_OK);
    int countPG = PQntuples(res);

    //store the pg results in a hashmap and telling it how many we expect
    std::unordered_map<osmid_t, osmNode> pg_nodes(countPG);

    for (int i = 0; i < countPG; i++) {
        osmid_t id = strtoosmid(PQgetvalue(res, i, 0), nullptr, 10);
        osmNode node;
#ifdef FIXED_POINT
        ramNode n((int) strtol(PQgetvalue(res, i, 2), nullptr, 10),
                  (int) strtol(PQgetvalue(res, i, 1), nullptr, 10));

        node.lat = n.lat();
        node.lon = n.lon();
#else
        node.lat = strtod(PQgetvalue(res, i, 1), nullptr);
        node.lon = strtod(PQgetvalue(res, i, 2), nullptr);
#endif
        pg_nodes.emplace(id, node);
    }

    PQclear(res);
    free(tmp2);

    // If some of the nodes in the way don't exist, the returning list has holes.
    // Merge the two lists removing any holes.
    size_t wrtidx = 0;
    for (size_t i = 0; i < nds.size(); ++i) {
        if (std::isnan(out[i].lat)) {
            std::unordered_map<osmid_t, osmNode>::iterator found = pg_nodes.find(nds[i]);
            if(found != pg_nodes.end()) {
                out[wrtidx] = found->second;
                ++wrtidx;
            }
        } else {
            if (wrtidx < i)
                out[wrtidx] = out[i];
            ++wrtidx;
        }
    }
    out.resize(wrtidx);

    return wrtidx;
}
Ejemplo n.º 9
0
int output_pgsql_t::pgsql_out_relation(osmid_t id, const taglist_t &rel_tags,
                                       const multinodelist_t &xnodes, const multitaglist_t & xtags,
                                       const idlist_t &xid, const rolelist_t &xrole,
                                       bool pending)
{
    if (xnodes.empty())
        return 0;

    int roads = 0;
    int make_polygon = 0;
    int make_boundary = 0;
    double split_at;

    std::vector<int> members_superseeded(xnodes.size(), 0);
    taglist_t outtags;

    //if its a route relation make_boundary and make_polygon will be false otherwise one or the other will be true
    if (m_tagtransform->filter_rel_member_tags(rel_tags, xtags, xrole,
            &(members_superseeded[0]), &make_boundary, &make_polygon, &roads,
            *m_export_list.get(), outtags)) {
        return 0;
    }

    /* Split long linear ways after around 1 degree or 100km (polygons not effected) */
    if (m_options.projection->get_proj_id() == PROJ_LATLONG)
        split_at = 1;
    else
        split_at = 100 * 1000;

    //this will either make lines or polygons (unless the lines arent a ring or are less than 3 pts) depending on the tag transform above
    //TODO: pick one or the other based on which we expect to care about
    auto wkbs  = builder.build_both(xnodes, make_polygon, m_options.enable_multi, split_at, id);

    if (wkbs.empty()) {
        return 0;
    }

    tag_t *areatag = 0;
    char tmp[32];
    for (const auto& wkb: wkbs) {
        expire->from_wkb(wkb.geom.c_str(), -id);
        /* FIXME: there should be a better way to detect polygons */
        if (wkb.is_polygon()) {
            if ((wkb.area > 0.0) && m_enable_way_area) {
                snprintf(tmp, sizeof(tmp), "%g", wkb.area);
                if (!areatag) {
                    outtags.push_dedupe(tag_t("way_area", tmp));
                    areatag = outtags.find("way_area");
                }
            }
            m_tables[t_poly]->write_row(-id, outtags, wkb.geom);
        } else {
            m_tables[t_line]->write_row(-id, outtags, wkb.geom);
            if (roads)
                m_tables[t_roads]->write_row(-id, outtags, wkb.geom);
        }
    }

    /* Tagtransform will have marked those member ways of the relation that
     * have fully been dealt with as part of the multi-polygon entry.
     * Set them in the database as done and delete their entry to not
     * have duplicates */
    //dont do this when working with pending relations as its not needed
    if (make_polygon) {
        for (size_t i=0; i < xid.size(); i++) {
            if (members_superseeded[i]) {
                pgsql_delete_way_from_output(xid[i]);
                if(!pending)
                    ways_done_tracker->mark(xid[i]);
            }
        }
    }

    // If the tag transform said the polygon looked like a boundary we want to make that as well
    // If we are making a boundary then also try adding any relations which form complete rings
    // The linear variants will have already been processed above
    if (make_boundary) {
        wkbs = builder.build_polygons(xnodes, m_options.enable_multi, id);
        for (const auto& wkb: wkbs) {
            expire->from_wkb(wkb.geom.c_str(), -id);
            if ((wkb.area > 0.0) && m_enable_way_area) {
                snprintf(tmp, sizeof(tmp), "%g", wkb.area);
                if (!areatag) {
                    outtags.push_dedupe(tag_t("way_area", tmp));
                    areatag = outtags.find("way_area");
                }
            }
            m_tables[t_poly]->write_row(-id, outtags, wkb.geom);
        }
    }

    return 0;
}