Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flex - Error with LineString and MultiLineString data #1386

Closed
rustprooflabs opened this issue Jan 1, 2021 · 4 comments
Closed

Flex - Error with LineString and MultiLineString data #1386

rustprooflabs opened this issue Jan 1, 2021 · 4 comments

Comments

@rustprooflabs
Copy link
Contributor

I am running into an error attempting to combine linestring and multilinestring data with the Flex output.
Additional links to the specific commits where I encountered this are tracked here.

The previous version of the Lua script below did not handle relations, it worked fine. I added the relation handling for the polygons without issue (apparently dealing with polygon/multipolygon w/out problem). The error happens when I attempt adding the line processing into the relations. The original table definition had the place_line table set as linestring. Updating the table definition to multilinestring to allow relations to be added causes the error:

ERROR: DB copy thread failed: Ending COPY mode for 'place_line' failed: ERROR:  Geometry type (LineString) does not match column type (MultiLineString)
CONTEXT:  COPY place_line, line 1, column geom: "0102000020110F00000A0000000DAF04630C5A60C11BD8F1715AFF5141233BA5E3125A60C1D8D2A9BA48FF514146B4A0C713..."

Based on the osm2pgsql docs and how the polygon data has worked I expect the LineString data to automatically be converted to MultiLineString.

Version

osm2pgsql version 1.4.0 (1.4.0-72-gc3eb0fb6)
Compiled using the following library versions:
Libosmium 2.15.6
Proj [API 4] Rel. 7.1.0, August 1st, 2020
Lua 5.3.3

place.lua

-- Change SRID if desired
local srid = 3857

local tables = {}


tables.place_point = osm2pgsql.define_table({
    name = 'place_point',
    schema = 'osm',
    ids = { type = 'node', id_column = 'osm_id' },
    columns = {
        { column = 'osm_type',     type = 'text', not_null = true },
        { column = 'name',     type = 'text' },
        { column = 'geom',     type = 'point' , projection = srid},
    }
})

tables.place_line = osm2pgsql.define_table({
    name = 'place_line',
    schema = 'osm',
    ids = { type = 'way', id_column = 'osm_id' },
    columns = {
        { column = 'osm_type',     type = 'text', not_null = true },
        { column = 'name',     type = 'text' },
        { column = 'geom',     type = 'multilinestring' , projection = srid},
    }
})


tables.place_polygon = osm2pgsql.define_table({
    name = 'place_polygon',
    schema = 'osm',
    ids = { type = 'area', id_column = 'osm_id' },
    columns = {
        { column = 'osm_type',     type = 'text', not_null = true },
        { column = 'name',     type = 'text' },
        { column = 'geom',     type = 'multipolygon' , projection = srid},
    }
})


function place_process_node(object)
    if not object.tags.place then
        return
    end

    -- Using grab_tag() removes from remaining key/value saved to Pg
    local osm_type = object:grab_tag('place')
    local name = object:grab_tag('name')

    tables.place_point:add_row({
        osm_type = osm_type,
        name = name,
        geom = { create = 'point' }
    })

end

-- Change function name here
function place_process_way(object)
    if not object.tags.place then
        return
    end

    local osm_type = object:grab_tag('place')
    local name = object:grab_tag('name')

    if object.is_closed then
        tables.place_polygon:add_row({
            osm_type = osm_type,
            name = name,
            geom = { create = 'area' }
        })
    else
        tables.place_line:add_row({
            osm_type = osm_type,
            name = name,
            geom = { create = 'line' }
        })
    end
    
end


function place_process_relation(object)
    if not object.tags.place then
        return
    end

    local osm_type = object:grab_tag('place')
    local name = object:grab_tag('name')

    if object.tags.type == 'multipolygon' or object.tags.type == 'boundary' then
        tables.place_polygon:add_row({
            osm_type = osm_type,
            name = name,
            geom = { create = 'area' }
        })
    else
        tables.place_line:add_row({
            osm_type = osm_type,
            name = name,
            geom = { create = 'line' }
         })
    end
end



-- deep_copy based on copy2: https://gist.github.com/tylerneylon/81333721109155b2d244
function deep_copy(obj)
    if type(obj) ~= 'table' then return obj end
    local res = setmetatable({}, getmetatable(obj))
    for k, v in pairs(obj) do res[deep_copy(k)] = deep_copy(v) end
    return res
end


if osm2pgsql.process_node == nil then
    -- Change function name here
    osm2pgsql.process_node = place_process_node
else
    local nested = osm2pgsql.process_node
    osm2pgsql.process_node = function(object)
        local object_copy = deep_copy(object)
        nested(object)
        -- Change function name here
        place_process_node(object_copy)
    end
end



if osm2pgsql.process_way == nil then
    -- Change function name here
    osm2pgsql.process_way = place_process_way
else
    local nested = osm2pgsql.process_way
    osm2pgsql.process_way = function(object)
        local object_copy = deep_copy(object)
        nested(object)
        -- Change function name here
        place_process_way(object_copy)
    end
end


if osm2pgsql.process_relation == nil then
    -- Change function name here
    osm2pgsql.process_relation = place_process_relation
else
    local nested = osm2pgsql.process_relation
    osm2pgsql.process_relation = function(object)
        local object_copy = deep_copy(object)
        nested(object)
        -- Change function name here
        place_process_relation(object_copy)
    end
end
@joto
Copy link
Collaborator

joto commented Jan 1, 2021

The "wrapping" of a non-multi geometry in a multi geometry currently only works for polygons. I don't remember off the top of my head whether this was just because I didn't think of adding this to the linestrings or whether there was some reason I couldn't add this. The geometry code in osm2pgsql is somewhat weird, so it might be easy to do or not, I have to take a look. But, yes, for consistency I believe it should behave the same way as for the polygons.

@nextstopsun
Copy link

Same problem here. I need to load relations with multiple ways and single ways to the same table without splitting relations. Automatic type conversion would solve this fine, but even better to have a function for controlling this conversion from lua script.

@joto
Copy link
Collaborator

joto commented Aug 10, 2022

I believe this is fixed in master. The Lua test file provided by @rustprooflabs runs through now in my tests without errors.

@rustprooflabs
Copy link
Contributor Author

It's working for me. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants