|
1 from django.db import connection |
|
2 from django.db.backends.util import truncate_name |
|
3 from django.db.models.fields import Field # Django base Field class |
|
4 from django.contrib.gis.db.backend.util import gqn |
|
5 from django.contrib.gis.db.backend.oracle.query import TRANSFORM |
|
6 |
|
7 # Quotename & geographic quotename, respectively. |
|
8 qn = connection.ops.quote_name |
|
9 |
|
10 class OracleSpatialField(Field): |
|
11 """ |
|
12 The backend-specific geographic field for Oracle Spatial. |
|
13 """ |
|
14 |
|
15 empty_strings_allowed = False |
|
16 |
|
17 def __init__(self, extent=(-180.0, -90.0, 180.0, 90.0), tolerance=0.05, **kwargs): |
|
18 """ |
|
19 Oracle Spatial backend needs to have the extent -- for projected coordinate |
|
20 systems _you must define the extent manually_, since the coordinates are |
|
21 for geodetic systems. The `tolerance` keyword specifies the tolerance |
|
22 for error (in meters), and defaults to 0.05 (5 centimeters). |
|
23 """ |
|
24 # Oracle Spatial specific keyword arguments. |
|
25 self._extent = extent |
|
26 self._tolerance = tolerance |
|
27 # Calling the Django field initialization. |
|
28 super(OracleSpatialField, self).__init__(**kwargs) |
|
29 |
|
30 def _add_geom(self, style, db_table): |
|
31 """ |
|
32 Adds this geometry column into the Oracle USER_SDO_GEOM_METADATA |
|
33 table. |
|
34 """ |
|
35 |
|
36 # Checking the dimensions. |
|
37 # TODO: Add support for 3D geometries. |
|
38 if self._dim != 2: |
|
39 raise Exception('3D geometries not yet supported on Oracle Spatial backend.') |
|
40 |
|
41 # Constructing the SQL that will be used to insert information about |
|
42 # the geometry column into the USER_GSDO_GEOM_METADATA table. |
|
43 meta_sql = style.SQL_KEYWORD('INSERT INTO ') + \ |
|
44 style.SQL_TABLE('USER_SDO_GEOM_METADATA') + \ |
|
45 ' (%s, %s, %s, %s)\n ' % tuple(map(qn, ['TABLE_NAME', 'COLUMN_NAME', 'DIMINFO', 'SRID'])) + \ |
|
46 style.SQL_KEYWORD(' VALUES ') + '(\n ' + \ |
|
47 style.SQL_TABLE(gqn(db_table)) + ',\n ' + \ |
|
48 style.SQL_FIELD(gqn(self.column)) + ',\n ' + \ |
|
49 style.SQL_KEYWORD("MDSYS.SDO_DIM_ARRAY") + '(\n ' + \ |
|
50 style.SQL_KEYWORD("MDSYS.SDO_DIM_ELEMENT") + \ |
|
51 ("('LONG', %s, %s, %s),\n " % (self._extent[0], self._extent[2], self._tolerance)) + \ |
|
52 style.SQL_KEYWORD("MDSYS.SDO_DIM_ELEMENT") + \ |
|
53 ("('LAT', %s, %s, %s)\n ),\n" % (self._extent[1], self._extent[3], self._tolerance)) + \ |
|
54 ' %s\n );' % self._srid |
|
55 return meta_sql |
|
56 |
|
57 def _geom_index(self, style, db_table): |
|
58 "Creates an Oracle Geometry index (R-tree) for this geometry field." |
|
59 |
|
60 # Getting the index name, Oracle doesn't allow object |
|
61 # names > 30 characters. |
|
62 idx_name = truncate_name('%s_%s_id' % (db_table, self.column), 30) |
|
63 |
|
64 sql = style.SQL_KEYWORD('CREATE INDEX ') + \ |
|
65 style.SQL_TABLE(qn(idx_name)) + \ |
|
66 style.SQL_KEYWORD(' ON ') + \ |
|
67 style.SQL_TABLE(qn(db_table)) + '(' + \ |
|
68 style.SQL_FIELD(qn(self.column)) + ') ' + \ |
|
69 style.SQL_KEYWORD('INDEXTYPE IS ') + \ |
|
70 style.SQL_TABLE('MDSYS.SPATIAL_INDEX') + ';' |
|
71 return sql |
|
72 |
|
73 def post_create_sql(self, style, db_table): |
|
74 """ |
|
75 Returns SQL that will be executed after the model has been |
|
76 created. |
|
77 """ |
|
78 # Getting the meta geometry information. |
|
79 post_sql = self._add_geom(style, db_table) |
|
80 |
|
81 # Getting the geometric index for this Geometry column. |
|
82 if self._index: |
|
83 return (post_sql, self._geom_index(style, db_table)) |
|
84 else: |
|
85 return (post_sql,) |
|
86 |
|
87 def db_type(self): |
|
88 "The Oracle geometric data type is MDSYS.SDO_GEOMETRY." |
|
89 return 'MDSYS.SDO_GEOMETRY' |
|
90 |
|
91 def get_placeholder(self, value): |
|
92 """ |
|
93 Provides a proper substitution value for Geometries that are not in the |
|
94 SRID of the field. Specifically, this routine will substitute in the |
|
95 SDO_CS.TRANSFORM() function call. |
|
96 """ |
|
97 if value is None: |
|
98 return '%s' |
|
99 elif value.srid != self._srid: |
|
100 # Adding Transform() to the SQL placeholder. |
|
101 return '%s(SDO_GEOMETRY(%%s, %s), %s)' % (TRANSFORM, value.srid, self._srid) |
|
102 else: |
|
103 return 'SDO_GEOMETRY(%%s, %s)' % self._srid |