#30489: Django RasterField deserialization bug with pixeltype flags
-------------------------------+--------------------------------------
     Reporter:  Ivor Bosloper  |                    Owner:  nobody
         Type:  Bug            |                   Status:  new
    Component:  GIS            |                  Version:  2.2
     Severity:  Normal         |               Resolution:
     Keywords:  RasterField    |             Triage Stage:  Unreviewed
    Has patch:  1              |      Needs documentation:  0
  Needs tests:  0              |  Patch needs improvement:  0
Easy pickings:  0              |                    UI/UX:  0
-------------------------------+--------------------------------------
Description changed by Ivor Bosloper:

Old description:

> After inserting some raster data with raster2pgsql into a Django model
> table with a RasterField column, I get a `list index out of range` when
> querying the table with a Django Queryset.
>
> {{{
> ...
> File "django/contrib/gis/db/models/fields.py" in from_db_value
>   360.         return connection.ops.parse_raster(value)
> File "django/contrib/gis/db/backends/postgis/operations.py" in
> parse_raster
>   369.         return from_pgraster(value)
> File "django/contrib/gis/db/backends/postgis/pgraster.py" in
> from_pgraster
>   57.         pixeltype = POSTGIS_TO_GDAL[pixeltype]
> }}}
>
> It turns out the `pixeltype` value used is 39 while the `POSTGIS_TO_GDAL`
> list is only 16 elements long. The database field contains valid data but
> can not be deserialized with Django.
>
> **Steps for reproduction:**
>
> {{{
> # Django model
> class RasterModel(models.Model):
>     rast = models.RasterField(srid=4326)
>
> # raw sql, single pixel raster with nodata bit set
> insert into app_rastermodel values(1, REPLACE('01 0000 0100
> 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> 0000000000000000 0000000000000000 E6100000 0100 0100 6 2 03 03', ' ',
> '')::raster);
>
> # query generating Exception
> RasterModel.objects.get(pk=1)
> }}}
>

> **Analysis**: if we look at the
> [https://trac.osgeo.org/postgis/wiki/WKTRaster/RFC/RFC1_V0SerialFormat
> Raster specification], the pixeltype is a byte of which the 4 highest
> bits are flags and the lowest 4 bits are the real pixeltype, but the
> Django deserialization code only considers one bit-flag:
>
> {{{
> # django/contrib/gis/db/backends/postgis/pgraster.py
> def from_pgraster(data):
>         ...
>         # Subtract nodata byte from band nodata value if it exists
>         has_nodata = pixeltype >= 64
>         if has_nodata:
>             pixeltype -= 64
>        ...
> }}}
>
> I have created (my first django) patch and hope somebody can assist me in
> getting it correct and merged.

New description:

 After inserting some raster data with raster2pgsql into a Django model
 table with a RasterField column, I get a `list index out of range` when
 querying the table with a Django Queryset.

 {{{
 ...
 File "django/contrib/gis/db/models/fields.py" in from_db_value
   360.         return connection.ops.parse_raster(value)
 File "django/contrib/gis/db/backends/postgis/operations.py" in
 parse_raster
   369.         return from_pgraster(value)
 File "django/contrib/gis/db/backends/postgis/pgraster.py" in from_pgraster
   57.         pixeltype = POSTGIS_TO_GDAL[pixeltype]
 }}}

 It turns out the `pixeltype` value used is 39 while the `POSTGIS_TO_GDAL`
 list is only 16 elements long. The database field contains valid data but
 can not be deserialized with Django.

 **Steps for reproduction:**

 {{{
 # Django model
 class RasterModel(models.Model):
     rast = models.RasterField(srid=4326)

 # raw sql, single pixel raster with nodata bit set
 insert into app_rastermodel values(1, REPLACE('01 0000 0100
 0000000000000000 0000000000000000 0000000000000000 0000000000000000
 0000000000000000 0000000000000000 E6100000 0100 0100 6 2 03 03', ' ',
 '')::raster);

 # query generating Exception
 RasterModel.objects.get(pk=1)
 }}}


 **Analysis**: if we look at the
 [https://trac.osgeo.org/postgis/wiki/WKTRaster/RFC/RFC1_V0SerialFormat
 Raster specification], the pixeltype is a byte of which the 4 highest bits
 are flags and the lowest 4 bits are the real pixeltype, but the Django
 deserialization code only considers one bit-flag:

 {{{
 # django/contrib/gis/db/backends/postgis/pgraster.py
 def from_pgraster(data):
         ...
         # Subtract nodata byte from band nodata value if it exists
         has_nodata = pixeltype >= 64
         if has_nodata:
             pixeltype -= 64
        ...
 }}}

 The erroneous pixeltype 39 in my example actually had the
 `BANDTYPE_FLAG_ISNODATA` (32) bit set which indicates all rastervalues are
 nodata.

 I have created (my first django) patch and hope somebody can assist me in
 getting it correct and merged.

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/30489#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/070.31947f125575455d264fc49ae875a0ba%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to