Skip to content

Commit

Permalink
Fix geometry field creation missing configurations
Browse files Browse the repository at this point in the history
After changing the field in state `base` instead of `manual`.
Those fields were created without configuration.
srid would be 0 gemetry type in geometry_columns table would be
GEOMETRY instead of POINT, LINESTRING, ...

This fixes the creation of geometry to use AddGeometryColumn again.
  • Loading branch information
yvaucher committed Oct 1, 2019
1 parent 5aa9b18 commit 3460f58
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 86 deletions.
112 changes: 59 additions & 53 deletions base_geoengine/fields.py
Expand Up @@ -5,8 +5,10 @@
from operator import attrgetter

from odoo import fields, _
from odoo.tools import sql

from .geo_helper import geo_convertion_helper as convert
from .geo_db import create_geo_column

logger = logging.getLogger(__name__)
try:
Expand Down Expand Up @@ -94,26 +96,6 @@ def load_geo(cls, wkb):
"""Load geometry into browse record after read was done"""
return wkbloads(wkb, hex=True) if wkb else False

def create_geo_column(self, cr, col_name, table, model):
"""Create a columns of type the geom"""
try:
cr.execute("SELECT AddGeometryColumn( %s, %s, %s, %s, %s)",
(table,
col_name,
self.srid,
self.geo_type,
self.dim))
self._create_index(cr, table, col_name)
except Exception:
cr.rollback()
logger.exception('Cannot create column %s table %s:',
col_name, table)
raise
finally:
cr.commit()

return True

def entry_to_shape(self, value, same_type=False):
"""Transform input into an object"""
shape = convert.value_to_shape(value)
Expand All @@ -124,63 +106,87 @@ def entry_to_shape(self, value, same_type=False):
self.geo_type.lower()))
return shape

def _postgis_index_name(self, table, col_name):
return "%s_%s_gist_index" % (table, col_name)

def _create_index(self, cr, table, col_name):
if self.gist_index:
try:
cr.execute("CREATE INDEX %s ON %s USING GIST ( %s )" %
(self._postgis_index_name(table, col_name),
table,
col_name))
except Exception:
cr.rollback()
logger.exception(
'Cannot create gist index for col %s table %s:',
col_name, table)
raise
finally:
cr.commit()

def update_geo_column(self, cr, col_name, table, model):
def update_geo_db_column(self, model):
"""Update the column type in the database.
"""
cr = model._cr
query = ("""SELECT srid, type, coord_dimension
FROM geometry_columns
WHERE f_table_name = %s
AND f_geometry_column = %s""")
cr.execute(query, (table, col_name))
cr.execute(query, (model._table, self.name))
check_data = cr.fetchone()
if not check_data:
raise TypeError(
"geometry_columns table seems to be corrupted. "
"SRID check is not possible")
"geometry_columns table seems to be corrupted."
" SRID check is not possible")
if check_data[0] != self.srid:
raise TypeError(
"Reprojection of column is not implemented"
"We can not change srid %s to %s" % (
"Reprojection of column is not implemented."
" We can not change srid %s to %s" % (
self.srid, check_data[0]))
if check_data[1] != self.geo_type:
elif check_data[1] != self.geo_type:
raise TypeError(
"Geo type modification is not implemented"
"We can not change type %s to %s" % (
"Geo type modification is not implemented."
" We can not change type %s to %s" % (
check_data[1], self.geo_type))
if check_data[2] != self.dim:
elif check_data[2] != self.dim:
raise TypeError(
"Geo dimention modification is not implemented"
"We can not change dimention %s to %s" % (
"Geo dimention modification is not implemented."
" We can not change dimention %s to %s" % (
check_data[2], self.dim))
if self.gist_index:
cr.execute(
"SELECT indexname FROM pg_indexes WHERE indexname = %s",
(self._postgis_index_name(table, col_name),))
(self._postgis_index_name(model._table, self.name),))
index = cr.fetchone()
if index:
return True
self._create_index(cr, table, col_name)
self._create_index(cr, model._table, self.name)
return True

def update_db_column(self, model, column):
""" Create/update the column corresponding to ``self``.
For creation of geo column
:param model: an instance of the field's model
:param column: the column's configuration (dict)
if it exists, or ``None``
"""
# the column does not exist, create it

if not column:
create_geo_column(
model._cr,
model._table,
self.name,
self.geo_type,
self.srid,
self.dim,
self.string)
return

if column['udt_name'] == self.column_type[0]:
return

self.update_geo_db_column(model)

if column['udt_name'] in self.column_cast_from:
sql.convert_column(
model._cr, model._table, self.name, self.column_type[1])
else:
newname = (self.name + '_moved{}').format
i = 0
while sql.column_exists(
model._cr, model._table, newname(i)
):
i += 1
if column['is_nullable'] == 'NO':
sql.drop_not_null(model._cr, model._table, self.name)
sql.rename_column(model._cr, model._table, self.name, newname(i))
sql.create_column(model._cr, model._table, self.name, self.column_type[1], self.string)


class GeoLine(GeoField):
"""Field for POSTGIS geometry Line type"""
Expand Down
39 changes: 39 additions & 0 deletions base_geoengine/geo_db.py
Expand Up @@ -5,8 +5,10 @@

from odoo import _
from odoo.exceptions import MissingError
from odoo.tools import sql

logger = logging.getLogger('geoengine.sql')
_schema = logging.getLogger('odoo.schema')


def init_postgis(cr):
Expand Down Expand Up @@ -45,3 +47,40 @@ def init_postgis(cr):
"CREATE EXTENSION postgis_topology;\n"
)
)


def create_geo_column(
cr, tablename, columnname, geotype, srid, dim, comment=None):
""" Create a geometry column with the given type.
:params: srid: geometry's projection srid
:params: dim: geometry's dimension (2D or 3D)
"""
cr.execute("SELECT AddGeometryColumn( %s, %s, %s, %s, %s)",
(tablename,
columnname,
srid,
geotype,
dim))
if comment:
cr.execute('COMMENT ON COLUMN "{}"."{}" IS %s'.format(
tablename, columnname), (comment,))
_schema.debug(
"Table %r: added geometry column %r of type %s",
tablename, columnname, geotype)


def _postgis_index_name(table, col_name):
return "%s_%s_gist_index" % (table, col_name)


def create_geo_index(cr, columnname, tablename):
""" Create the given index unless it exists. """
indexname = _postgis_index_name(tablename, columnname)
if sql.index_exists(cr, indexname):
return
cr.execute("CREATE INDEX %s ON %s USING GIST ( %s )" %
(indexname,
tablename,
columnname))
_schema.debug("Table %r: created index %r (%s)", tablename, indexname, args)
33 changes: 0 additions & 33 deletions base_geoengine/geo_model.py
Expand Up @@ -19,37 +19,6 @@ class GeoModel(models.AbstractModel):
# Array of ash that define layer and data to use
_georepr = []

@api.model_cr_context
def _auto_init(self):
"""Initialize the columns in dB and Create the GIST index
only create and update supported
We override the base methid because creation of fields in DB is not
actually delegated to the field it self but to the ORM _auto_init
function
"""
cr = self._cr

geo_fields = {}
for f_name, field in self._fields.items():
if field.type.startswith('geo_'):
geo_fields[f_name] = field
res = super()._auto_init()
if self._abstract:
return res

# Create geo columns
column_data = tools.table_columns(cr, self._table)

for f_name, geo_field in geo_fields.items():
if geo_field.compute and not geo_field.store:
continue
fct = geo_field.create_geo_column
if f_name in column_data:
fct = geo_field.update_geo_column
fct(cr, f_name, self._table, self._name)
return res

@api.model
def fields_get(self, allfields=None, attributes=None):
"""Add geo_type definition for geo fields"""
Expand Down Expand Up @@ -110,8 +79,6 @@ def set_field_real_name(in_tuple):
'default_extent': view.default_extent or DEFAULT_EXTENT,
'default_zoom': view.default_zoom,
}
# XXX still the case ?
# TODO find why context in read does not work with webclient
for layer in view.raster_layer_ids:
layer_dict = layer.read()[0]
res['geoengine_layers']['backgrounds'].append(layer_dict)
Expand Down

0 comments on commit 3460f58

Please sign in to comment.