Version 2 (modified by ian.g.kelly@…, 8 years ago) (diff)


The boulder-oracle-sprint branch

This branch began November 4, 2006 at a code sprint in Boulder, Colorado, whence it takes its name. It aims to implement full support for the Oracle RDBMS.

How to get the branch

svn co

See our branch policy for full information on how to use a branch.


The main goals of this branch are:

  • Improve the oracle backend to the point where it can be used interchangeably with the existing supported backends.


Tablespace options

A common paradigm for optimizing performance in Oracle-based systems is the use of tablespaces to organize disk layout. The Oracle branch supports this use case by adding tablespace options to Meta and Field classes. When using a backend that lacks support for tablespaces, these options are ignored.

A tablespace can be specified for the table(s) generated by a model by supplying the "tablespace" option inside the model's Meta class. Additionally, the "tablespace" option can be passed to a Field constructor to specify an alternate tablespace for the Field's column index. If no index would be created for the column, the "tablespace" option is ignored.

class TablespaceExample(models.Model):
    name = models.CharField(maxlength=30, db_index=True, tablespace="indexes")
    data = models.CharField(maxlength=255, db_index=True)
    edges = models.ManyToManyField(to="self", tablespace="indexes")

    class Meta:
        tablespace = "tables"

In this example, the tables generated by the TablespaceExample model (i.e., the model table and the many-to-many table) would be stored in the "tables" tablespace. The index for the name field and the indexes on the many-to-many table would be stored in the "indexes" tablespace. The "data" field would also generate an index, but no tablespace for it is specified, so it would be stored in the model tablespace "tables" by default.

Naming issues

Oracle imposes a name length limit of 30 characters. To accommodate this, the django.db.backends.util.truncate_name function has been added to truncate names to backend.get_max_name_length(). To prevent name collisions, the final 4 characters of the truncated name are generated from an MD5 hash.

Backend QuerySet classes

A new mechanism is supplied by which backends can supply their own QuerySet subclasses that will be used in place of QuerySet, and that core QuerySet subclasses (such as DateQuerySet) will subclass. The oracle backend uses this to override the iterator and _get_sql_clause methods in order to construct proper SQL for Oracle. It is also used to provide a new resolve_columns method that the iterator method is expected to call in order to fetch corrected values.

Empty strings

Django generally prefers to use the empty string ('') rather than NULL, but Oracle treats the empty string as NULL. To get around this, the oracle backend silently changes '' to ' ' when saving data. The inverse operation is automatically performed by OracleQuerySet.resolve_columns when fetching from the database.

Datetime conversion

All communication of date and time-related fields with cx_Oracle requires the use of datetime.datetime objects rather than strings. Code has been introduced to the Field classes to properly cast values for cx_Oracle, and the OracleQuerySet.resolve_columns method is used to cast values from the database to the proper type for the Field.

LOB manipulation

The oracle backend stores TextFields as NCLOB columns, for which cx_Oracle requires some extra manipulation to fetch. This is automatically handled by OracleQuerySet.resolve_columns.

To-do list

(Updated April 19, 2007)

  • The branch could use additional testing.
  • Rename the "tablespace" options to "db_tablespace" to match "db_table" and "db_index"?
  • Additional code refactoring for the QuerySet.iterator and QuerySet._get_sql_clause methods.

Attachments (4)

Download all attachments as: .zip

Back to Top