Opened 18 years ago
Closed 15 years ago
#7126 closed (worksforme)
select_related(field) doesn't correctly SELECT GIS fields on MySQL/Oracle
| Reported by: | Owned by: | jbronn | |
|---|---|---|---|
| Component: | GIS | Version: | gis |
| Severity: | Keywords: | select_related gis oracle mysql | |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | yes | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
I'm not quite sure how to write a test, but I produced a simple script of what goes wrong.
I have a simple Item object which can optionally have a Location
from django.contrib.gis.db import models
class Location(models.Model):
location = models.PointField()
objects = models.GeoManager()
class Item(models.Model):
name = models.CharField(max_length=10)
location = models.ForeignKey(Location, null=True)
objects = models.GeoManager()
Setup some data
from django.contrib.gis.geos import Point from test.models import Location, Item item = Item(name="Place 1") item.save() item = Item(name="Place 2") location = Location(location=Point(1,1)) location.save() item.location = location item.save()
When I query the Items with select_related() everything works fine
>>> for i in Item.objects.select_related(): ... if i.location: ... i.location.location ... <Point object at 0x21ad784> >>> print connection.queries[-1]['sql'] SELECT `test_location`.`id`, AsText(`test_location`.`location`) FROM `test_location` WHERE `test_location`.`id` = 1
When I specify select_related('location') to do a LEFT JOIN onto location, the query isn't formed properly
>>> for i in Item.objects.select_related('location'):
... if i.location:
... i.location.location
...
Traceback (most recent call last):
File "<console>", line 3, in <module>
File "/opt/local/lib/python2.5/site-packages/django/contrib/gis/db/models/proxy.py", line 36, in __get__
geom = self._klass(geom_value)
File "/opt/local/lib/python2.5/site-packages/django/contrib/gis/geos/base.py", line 72, in __init__
raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.')
ValueError: String or unicode input unrecognized as WKT EWKT, and HEXEWKB.
>>> print connection.queries[-1]['sql']
SELECT `test_item`.`id`, `test_item`.`name`, `test_item`.`location_id`, `test_location`.`id`, `test_location`.`location` FROM `test_item` LEFT OUTER JOIN `test_location` ON (`test_item`.`location_id` = `test_location`.`id`)
I understand that this is a new feature rather than an old one that is broken.
Attachments (1)
Change History (11)
comment:1 by , 18 years ago
| Resolution: | → invalid |
|---|---|
| Status: | new → closed |
comment:2 by , 18 years ago
| Resolution: | invalid |
|---|---|
| Status: | closed → reopened |
| Triage Stage: | Unreviewed → Accepted |
Yes this is a bug when specifying a geometry field for select_related on MySQL and/or Oracle backends. This is also a new feature added by the queryset-refactor changes, and thus this functionality was not present in trunk.
The problem stems from the fact that Oracle and MySQL need to add a wrapper (AsText) around SELECT SQL. This isn't happening for the fields specified by select_related. In order to achieve this functionality GeoQuery will need to override at least get_columns and possibly fill_related_selections. This one may take a while.
comment:3 by , 18 years ago
| Owner: | changed from to |
|---|---|
| Status: | reopened → new |
comment:4 by , 18 years ago
I think it existed before... I've checked out revision 7476 and used a related field, and not passed any arguments to select_related()
class Location(models.Model):
location = models.PointField()
objects = models.GeoManager()
class Item(models.Model):
name = models.CharField(max_length=10)
location = models.ForeignKey(Location)
objects = models.GeoManager()
data
item = Item(name="Place 1") location = Location(location=Point(1,1)) location.save() item.location = location item.save() item = Item(name="Place 2") location = Location(location=Point(2,2)) location.save() item.location = location item.save()
queries
>>> for i in Item.objects.select_related():
... if i.location:
... i.location.location
...
Traceback (most recent call last):
File "<console>", line 3, in <module>
File "/opt/local/lib/python2.5/site-packages/django/contrib/gis/db/models/proxy.py", line 36, in __get__
geom = self._klass(geom_value)
File "/opt/local/lib/python2.5/site-packages/django/contrib/gis/geos/base.py", line 72, in __init__
raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.')
ValueError: String or unicode input unrecognized as WKT EWKT, and HEXEWKB.
>>> print connection.queries[-1]['sql']
SELECT `test_item`.`id`,`test_item`.`name`,`test_item`.`location_id`,`test_location`.`id`,`test_location`.`location` FROM `test_item` , `test_location` WHERE `test_item`.`location_id` = `test_location`.`id`
This is why I thought it wasn't a bug as it was there before the merge, I just never noticed it before!
comment:5 by , 18 years ago
| Has patch: | set |
|---|---|
| Keywords: | oracle mysql added |
| Needs tests: | set |
| Summary: | select_related(field) doesn't correctly SELECT GIS fields → select_related(field) doesn't correctly SELECT GIS fields on MySQL/Oracle |
It's a bug regardless; fortunately its limited in scope in only affecting MySQL/Oracle when using select_related on Geographic fields.
Attached is a patch which fixes the problem -- only get_columns needed to be overridden. I don't know when I'll get around to committing it because I want to have unit tests.
by , 18 years ago
| Attachment: | gis_select_related.diff added |
|---|
Fix for selection of geometry columns when using select_related on MySQL/Oracle.
follow-up: 7 comment:6 by , 18 years ago
I'll be more than happy to write some tests for this. I'll just need a bit of pointing in the right direction as to what things to test for etc.
comment:7 by , 18 years ago
Replying to benwalton@gmail.com:
I'll be more than happy to write some tests for this. I'll just need a bit of pointing in the right direction as to what things to test for etc.
The GeoDjango [browser:django/branches/gis/django/contrib/gis/tests tests folder] contains all tests. Since we want to test geographic model functionality a test application directory should be created (e.g., the existing ones are geoapp, layermap, and distapp) which can have the Item and Location models in a models.py. Create a file in the new application directory (say srapp) called tests_mysql.py (see the geoapp [browser:django/branches/gis/django/contrib/gis/tests/geoapp/tests_mysql.py tests] for an example) and add the tests there. Finally add add the test application name ('srapp') to the test_models variable for GeoDjango's test runner (read that code to see how to run the GeoDjango test suite).
comment:8 by , 17 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
follow-up: 10 comment:9 by , 15 years ago
| Resolution: | fixed |
|---|---|
| Status: | closed → reopened |
I'm getting the same error using Python2.6, Django 1.2.4 and MySQL 5.1.49
Traceback (most recent call last):
File "<console>", line 2, in <module>
File "/usr/local/lib/python2.6/dist-packages/django/contrib/gis/db/models/proxy.py", line 38, in __get__
geom = self._klass(geom_value)
File "/usr/local/lib/python2.6/dist-packages/django/contrib/gis/geos/geometry.py", line 73, in __init__
raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.')
ValueError: String or unicode input unrecognized as WKT EWKT, and HEXEWKB.
comment:10 by , 15 years ago
| Resolution: | → worksforme |
|---|---|
| Status: | reopened → closed |
Replying to sdonk:
I'm getting the same error using Python2.6, Django 1.2.4 and MySQL 5.1.49
I'm unable to reproduce. Ensure your models have objects = models.GeoManager() and that there's no corrupt data in your MySQL geometry columns.
A similar error message does not imply that this bug has regressed -- the current test suite checks for (and passes on) the conditions described in this ticket. If think your problem is still a bug, open up a new ticket with clear instructions and code describing how to reproduce.
Sorry, I think this might be something else as it doesn't work with a related-select_related on a pre qsrf chechout.