#12529: manage.py syncdb doesn't check tables by using mangled names with Oracle
backend
-------------------------------------+-------------------------------------
     Reporter:  jtiai                |                    Owner:  nobody
         Type:  Bug                  |                   Status:  closed
    Component:  Database layer       |                  Version:  master
  (models, ORM)                      |               Resolution:  fixed
     Severity:  Normal               |             Triage Stage:  Accepted
     Keywords:  syncdb oracle        |      Needs documentation:  0
  inspectdb                          |  Patch needs improvement:  0
    Has patch:  0                    |                    UI/UX:  0
  Needs tests:  0                    |
Easy pickings:  0                    |
-------------------------------------+-------------------------------------

Comment (by manelclos):

 Hi, I can still reproduce this using Django 1.7 and 1.7.1.

 As an example, let's use django-cas' table
 "django_cas_session_service_ticket". This also happens with
 easy_thumbails' table "easy_thumbnails_thumbnaildimensions".

 The flow is like this:
 - migrate command is called, eventually migrate.py:model_installed() is
 called:

 {{{
             def model_installed(model):
                 opts = model._meta
                 converter = connection.introspection.table_name_converter
                 # Note that if a model is unmanaged we short-circuit and
 never try to install it
                 return not ((converter(opts.db_table) in tables) or
                     (opts.auto_created and
 converter(opts.auto_created._meta.db_table) in tables))
 }}}

 - here, the table name converter will just return name.lower(), which is
 clearly NOT the name that was used to create the table.
 - at creation time, the Oracle DatabaseOperations (oracle/base.py) class
 will truncate the name:

 {{{
     def quote_name(self, name):
         # SQL92 requires delimited (quoted) names to be case-sensitive.
 When
         # not quoted, Oracle has case-insensitive behavior for
 identifiers, but
         # always defaults to uppercase.
         # We simplify things by making Oracle identifiers always
 uppercase.
         if not name.startswith('"') and not name.endswith('"'):
             name = '"%s"' % backend_utils.truncate_name(name.upper(),
                                                self.max_name_length())
         # Oracle puts the query text into a (query % args) construct, so %
 signs
         # in names need to be escaped. The '%%' will be collapsed back to
 '%' at
         # that stage so we aren't really making the name longer here.
         name = name.replace('%', '%%')
         return name.upper()
 }}}

 - the check for table existance "(converter(opts.db_table) in tables)"
 will fail, as tables array contains "django_cas_session_service1144" and
 not "django_cas_session_service_ticket"

 - with these changes in oracle/introspection.py everything works as
 expected. imports included in function for easier testing:

 {{{
     def table_name_converter(self, name):
         "Table name comparison is case insensitive under Oracle"
         from django.db.backends import utils as backend_utils
         from django.db.backends.oracle.base import DatabaseOperations
         self.ops = DatabaseOperations(self)
         name = backend_utils.truncate_name(name.upper(),
 self.ops.max_name_length())
         return name.lower()
 }}}

--
Ticket URL: <https://code.djangoproject.com/ticket/12529#comment:9>
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/063.67130252acf547b9af39b6faaebbd29d%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to