diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index dd24878..c89dcd9 100644
|
a
|
b
|
class BaseDatabaseFeatures(object):
|
| 340 | 340 | # Do time/datetime fields have microsecond precision? |
| 341 | 341 | supports_microsecond_precision = True |
| 342 | 342 | |
| | 343 | # Is there support for __regex lookups? |
| | 344 | supports_regex = True |
| | 345 | |
| 343 | 346 | # Does the __regex lookup support backreferencing and grouping? |
| 344 | 347 | supports_regex_backreferencing = True |
| 345 | 348 | |
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
index c197422..6cfd608 100644
|
a
|
b
|
class DatabaseFeatures(BaseDatabaseFeatures):
|
| 83 | 83 | has_bulk_insert = True |
| 84 | 84 | supports_tablespaces = True |
| 85 | 85 | |
| | 86 | def _supports_regex(self): |
| | 87 | if self.connection.oracle_version > 9: |
| | 88 | return True |
| | 89 | else: |
| | 90 | return False |
| | 91 | supports_regex = property(_supports_regex) |
| | 92 | supports_regex_backreferencing = supports_regex |
| | 93 | |
| 86 | 94 | class DatabaseOperations(BaseDatabaseOperations): |
| 87 | 95 | compiler_module = "django.db.backends.oracle.compiler" |
| 88 | 96 | |
| … |
… |
WHEN (new.%(col_name)s IS NULL)
|
| 249 | 257 | def random_function_sql(self): |
| 250 | 258 | return "DBMS_RANDOM.RANDOM" |
| 251 | 259 | |
| 252 | | def regex_lookup_9(self, lookup_type): |
| 253 | | raise NotImplementedError("Regexes are not supported in Oracle before version 10g.") |
| 254 | | |
| 255 | | def regex_lookup_10(self, lookup_type): |
| 256 | | if lookup_type == 'regex': |
| 257 | | match_option = "'c'" |
| 258 | | else: |
| 259 | | match_option = "'i'" |
| 260 | | return 'REGEXP_LIKE(%%s, %%s, %s)' % match_option |
| 261 | | |
| 262 | 260 | def regex_lookup(self, lookup_type): |
| 263 | | # If regex_lookup is called before it's been initialized, then create |
| 264 | | # a cursor to initialize it and recur. |
| 265 | | self.connection.cursor() |
| 266 | | return self.connection.ops.regex_lookup(lookup_type) |
| | 261 | if self.connection.oracle_version > 9: |
| | 262 | if lookup_type == 'regex': |
| | 263 | match_option = "'c'" |
| | 264 | else: |
| | 265 | match_option = "'i'" |
| | 266 | return 'REGEXP_LIKE(%%s, %%s, %s)' % match_option |
| | 267 | else: |
| | 268 | raise NotImplementedError("Regexes are not supported in Oracle before version 10g.") |
| 267 | 269 | |
| 268 | 270 | def return_insert_id(self): |
| 269 | 271 | return "RETURNING %s INTO %%s", (InsertIdVar(),) |
| … |
… |
class DatabaseWrapper(BaseDatabaseWrapper):
|
| 434 | 436 | def __init__(self, *args, **kwargs): |
| 435 | 437 | super(DatabaseWrapper, self).__init__(*args, **kwargs) |
| 436 | 438 | |
| 437 | | self.oracle_version = None |
| | 439 | self._oracle_version = None |
| 438 | 440 | self.features = DatabaseFeatures(self) |
| 439 | 441 | use_returning_into = self.settings_dict["OPTIONS"].get('use_returning_into', True) |
| 440 | 442 | self.features.can_return_id_from_insert = use_returning_into |
| … |
… |
class DatabaseWrapper(BaseDatabaseWrapper):
|
| 444 | 446 | self.introspection = DatabaseIntrospection(self) |
| 445 | 447 | self.validation = BaseDatabaseValidation(self) |
| 446 | 448 | |
| | 449 | def _get_ora_version(self): |
| | 450 | if self._oracle_version is None: |
| | 451 | # To check the server version, we need a connection |
| | 452 | if self.connection is None: |
| | 453 | self._cursor().close() |
| | 454 | self._oracle_version = int(self.connection.version.split('.')[0]) |
| | 455 | return self._oracle_version |
| | 456 | oracle_version = property(_get_ora_version) |
| | 457 | |
| 447 | 458 | def check_constraints(self, table_names=None): |
| 448 | 459 | """ |
| 449 | 460 | To check constraints, we set constraints to immediate. Then, when, we're done we must ensure they |
| … |
… |
class DatabaseWrapper(BaseDatabaseWrapper):
|
| 517 | 528 | self.operators = self._likec_operators |
| 518 | 529 | else: |
| 519 | 530 | self.operators = self._standard_operators |
| 520 | | |
| 521 | | try: |
| 522 | | self.oracle_version = int(self.connection.version.split('.')[0]) |
| 523 | | # There's no way for the DatabaseOperations class to know the |
| 524 | | # currently active Oracle version, so we do some setups here. |
| 525 | | # TODO: Multi-db support will need a better solution (a way to |
| 526 | | # communicate the current version). |
| 527 | | if self.oracle_version <= 9: |
| 528 | | self.ops.regex_lookup = self.ops.regex_lookup_9 |
| 529 | | else: |
| 530 | | self.ops.regex_lookup = self.ops.regex_lookup_10 |
| 531 | | except ValueError: |
| 532 | | pass |
| 533 | 531 | try: |
| 534 | 532 | self.connection.stmtcachesize = 20 |
| 535 | 533 | except: |
| … |
… |
class FormatStylePlaceholderCursor(object):
|
| 650 | 648 | self.cursor.arraysize = 100 |
| 651 | 649 | |
| 652 | 650 | def _format_params(self, params): |
| 653 | | return tuple([OracleParam(p, self, True) for p in params]) |
| | 651 | return tuple(OracleParam(p, self, True) for p in params) |
| 654 | 652 | |
| 655 | 653 | def _guess_input_sizes(self, params_list): |
| 656 | 654 | sizes = [None] * len(params_list[0]) |
| … |
… |
class FormatStylePlaceholderCursor(object):
|
| 722 | 720 | def fetchmany(self, size=None): |
| 723 | 721 | if size is None: |
| 724 | 722 | size = self.arraysize |
| 725 | | return tuple([_rowfactory(r, self.cursor) |
| 726 | | for r in self.cursor.fetchmany(size)]) |
| | 723 | return tuple(_rowfactory(r, self.cursor) |
| | 724 | for r in self.cursor.fetchmany(size)) |
| 727 | 725 | |
| 728 | 726 | def fetchall(self): |
| 729 | | return tuple([_rowfactory(r, self.cursor) |
| 730 | | for r in self.cursor.fetchall()]) |
| | 727 | return tuple(_rowfactory(r, self.cursor) |
| | 728 | for r in self.cursor.fetchall()) |
| 731 | 729 | |
| 732 | 730 | def var(self, *args): |
| 733 | 731 | return VariableWrapper(self.cursor.var(*args)) |
diff --git a/tests/modeltests/lookup/tests.py b/tests/modeltests/lookup/tests.py
index 9c2b0c6..068b5f7 100644
|
a
|
b
|
class LookupTests(TestCase):
|
| 479 | 479 | self.assertEqual(str(ex), "Join on field 'headline' not permitted. " |
| 480 | 480 | "Did you misspell 'starts' for the lookup type?") |
| 481 | 481 | |
| | 482 | @skipUnlessDBFeature('supports_regex') |
| 482 | 483 | def test_regex(self): |
| 483 | 484 | # Create some articles with a bit more interesting headlines for testing field lookups: |
| 484 | 485 | for a in Article.objects.all(): |