web/lib/django/db/backends/oracle/base.py
changeset 0 0d40e90630ef
child 29 cc9b7e14412b
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     1 """
       
     2 Oracle database backend for Django.
       
     3 
       
     4 Requires cx_Oracle: http://cx-oracle.sourceforge.net/
       
     5 """
       
     6 
       
     7 import os
       
     8 import datetime
       
     9 import time
       
    10 try:
       
    11     from decimal import Decimal
       
    12 except ImportError:
       
    13     from django.utils._decimal import Decimal
       
    14 
       
    15 # Oracle takes client-side character set encoding from the environment.
       
    16 os.environ['NLS_LANG'] = '.UTF8'
       
    17 # This prevents unicode from getting mangled by getting encoded into the
       
    18 # potentially non-unicode database character set.
       
    19 os.environ['ORA_NCHAR_LITERAL_REPLACE'] = 'TRUE'
       
    20 
       
    21 try:
       
    22     import cx_Oracle as Database
       
    23 except ImportError, e:
       
    24     from django.core.exceptions import ImproperlyConfigured
       
    25     raise ImproperlyConfigured("Error loading cx_Oracle module: %s" % e)
       
    26 
       
    27 from django.db.backends import *
       
    28 from django.db.backends.signals import connection_created
       
    29 from django.db.backends.oracle import query
       
    30 from django.db.backends.oracle.client import DatabaseClient
       
    31 from django.db.backends.oracle.creation import DatabaseCreation
       
    32 from django.db.backends.oracle.introspection import DatabaseIntrospection
       
    33 from django.utils.encoding import smart_str, force_unicode
       
    34 
       
    35 DatabaseError = Database.DatabaseError
       
    36 IntegrityError = Database.IntegrityError
       
    37 
       
    38 
       
    39 # Check whether cx_Oracle was compiled with the WITH_UNICODE option.  This will
       
    40 # also be True in Python 3.0.
       
    41 if int(Database.version.split('.', 1)[0]) >= 5 and not hasattr(Database, 'UNICODE'):
       
    42     convert_unicode = force_unicode
       
    43 else:
       
    44     convert_unicode = smart_str
       
    45 
       
    46 
       
    47 class DatabaseFeatures(BaseDatabaseFeatures):
       
    48     empty_fetchmany_value = ()
       
    49     needs_datetime_string_cast = False
       
    50     uses_custom_query_class = True
       
    51     interprets_empty_strings_as_nulls = True
       
    52     uses_savepoints = True
       
    53     can_return_id_from_insert = True
       
    54 
       
    55 
       
    56 class DatabaseOperations(BaseDatabaseOperations):
       
    57 
       
    58     def autoinc_sql(self, table, column):
       
    59         # To simulate auto-incrementing primary keys in Oracle, we have to
       
    60         # create a sequence and a trigger.
       
    61         sq_name = get_sequence_name(table)
       
    62         tr_name = get_trigger_name(table)
       
    63         tbl_name = self.quote_name(table)
       
    64         col_name = self.quote_name(column)
       
    65         sequence_sql = """
       
    66 DECLARE
       
    67     i INTEGER;
       
    68 BEGIN
       
    69     SELECT COUNT(*) INTO i FROM USER_CATALOG
       
    70         WHERE TABLE_NAME = '%(sq_name)s' AND TABLE_TYPE = 'SEQUENCE';
       
    71     IF i = 0 THEN
       
    72         EXECUTE IMMEDIATE 'CREATE SEQUENCE "%(sq_name)s"';
       
    73     END IF;
       
    74 END;
       
    75 /""" % locals()
       
    76         trigger_sql = """
       
    77 CREATE OR REPLACE TRIGGER "%(tr_name)s"
       
    78 BEFORE INSERT ON %(tbl_name)s
       
    79 FOR EACH ROW
       
    80 WHEN (new.%(col_name)s IS NULL)
       
    81     BEGIN
       
    82         SELECT "%(sq_name)s".nextval
       
    83         INTO :new.%(col_name)s FROM dual;
       
    84     END;
       
    85 /""" % locals()
       
    86         return sequence_sql, trigger_sql
       
    87 
       
    88     def date_extract_sql(self, lookup_type, field_name):
       
    89         # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions42a.htm#1017163
       
    90         if lookup_type == 'week_day':
       
    91             # TO_CHAR(field, 'D') returns an integer from 1-7, where 1=Sunday.
       
    92             return "TO_CHAR(%s, 'D')" % field_name
       
    93         else:
       
    94             return "EXTRACT(%s FROM %s)" % (lookup_type, field_name)
       
    95 
       
    96     def date_trunc_sql(self, lookup_type, field_name):
       
    97         # Oracle uses TRUNC() for both dates and numbers.
       
    98         # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions155a.htm#SQLRF06151
       
    99         if lookup_type == 'day':
       
   100             sql = 'TRUNC(%s)' % field_name
       
   101         else:
       
   102             sql = "TRUNC(%s, '%s')" % (field_name, lookup_type)
       
   103         return sql
       
   104 
       
   105     def datetime_cast_sql(self):
       
   106         return "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')"
       
   107 
       
   108     def deferrable_sql(self):
       
   109         return " DEFERRABLE INITIALLY DEFERRED"
       
   110 
       
   111     def drop_sequence_sql(self, table):
       
   112         return "DROP SEQUENCE %s;" % self.quote_name(get_sequence_name(table))
       
   113 
       
   114     def fetch_returned_insert_id(self, cursor):
       
   115         return long(cursor._insert_id_var.getvalue())
       
   116 
       
   117     def field_cast_sql(self, db_type):
       
   118         if db_type and db_type.endswith('LOB'):
       
   119             return "DBMS_LOB.SUBSTR(%s)"
       
   120         else:
       
   121             return "%s"
       
   122 
       
   123     def last_insert_id(self, cursor, table_name, pk_name):
       
   124         sq_name = get_sequence_name(table_name)
       
   125         cursor.execute('SELECT "%s".currval FROM dual' % sq_name)
       
   126         return cursor.fetchone()[0]
       
   127 
       
   128     def lookup_cast(self, lookup_type):
       
   129         if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'):
       
   130             return "UPPER(%s)"
       
   131         return "%s"
       
   132 
       
   133     def max_name_length(self):
       
   134         return 30
       
   135 
       
   136     def prep_for_iexact_query(self, x):
       
   137         return x
       
   138 
       
   139     def process_clob(self, value):
       
   140         if value is None:
       
   141             return u''
       
   142         return force_unicode(value.read())
       
   143 
       
   144     def query_class(self, DefaultQueryClass):
       
   145         return query.query_class(DefaultQueryClass, Database)
       
   146 
       
   147     def quote_name(self, name):
       
   148         # SQL92 requires delimited (quoted) names to be case-sensitive.  When
       
   149         # not quoted, Oracle has case-insensitive behavior for identifiers, but
       
   150         # always defaults to uppercase.
       
   151         # We simplify things by making Oracle identifiers always uppercase.
       
   152         if not name.startswith('"') and not name.endswith('"'):
       
   153             name = '"%s"' % util.truncate_name(name.upper(),
       
   154                                                self.max_name_length())
       
   155         return name.upper()
       
   156 
       
   157     def random_function_sql(self):
       
   158         return "DBMS_RANDOM.RANDOM"
       
   159 
       
   160     def regex_lookup_9(self, lookup_type):
       
   161         raise NotImplementedError("Regexes are not supported in Oracle before version 10g.")
       
   162 
       
   163     def regex_lookup_10(self, lookup_type):
       
   164         if lookup_type == 'regex':
       
   165             match_option = "'c'"
       
   166         else:
       
   167             match_option = "'i'"
       
   168         return 'REGEXP_LIKE(%%s, %%s, %s)' % match_option
       
   169 
       
   170     def regex_lookup(self, lookup_type):
       
   171         # If regex_lookup is called before it's been initialized, then create
       
   172         # a cursor to initialize it and recur.
       
   173         from django.db import connection
       
   174         connection.cursor()
       
   175         return connection.ops.regex_lookup(lookup_type)
       
   176 
       
   177     def return_insert_id(self):
       
   178         return "RETURNING %s INTO %%s", (InsertIdVar(),)
       
   179 
       
   180     def savepoint_create_sql(self, sid):
       
   181         return convert_unicode("SAVEPOINT " + self.quote_name(sid))
       
   182 
       
   183     def savepoint_rollback_sql(self, sid):
       
   184         return convert_unicode("ROLLBACK TO SAVEPOINT " + self.quote_name(sid))
       
   185 
       
   186     def sql_flush(self, style, tables, sequences):
       
   187         # Return a list of 'TRUNCATE x;', 'TRUNCATE y;',
       
   188         # 'TRUNCATE z;'... style SQL statements
       
   189         if tables:
       
   190             # Oracle does support TRUNCATE, but it seems to get us into
       
   191             # FK referential trouble, whereas DELETE FROM table works.
       
   192             sql = ['%s %s %s;' % \
       
   193                     (style.SQL_KEYWORD('DELETE'),
       
   194                      style.SQL_KEYWORD('FROM'),
       
   195                      style.SQL_FIELD(self.quote_name(table)))
       
   196                     for table in tables]
       
   197             # Since we've just deleted all the rows, running our sequence
       
   198             # ALTER code will reset the sequence to 0.
       
   199             for sequence_info in sequences:
       
   200                 sequence_name = get_sequence_name(sequence_info['table'])
       
   201                 table_name = self.quote_name(sequence_info['table'])
       
   202                 column_name = self.quote_name(sequence_info['column'] or 'id')
       
   203                 query = _get_sequence_reset_sql() % {'sequence': sequence_name,
       
   204                                                      'table': table_name,
       
   205                                                      'column': column_name}
       
   206                 sql.append(query)
       
   207             return sql
       
   208         else:
       
   209             return []
       
   210 
       
   211     def sequence_reset_sql(self, style, model_list):
       
   212         from django.db import models
       
   213         output = []
       
   214         query = _get_sequence_reset_sql()
       
   215         for model in model_list:
       
   216             for f in model._meta.local_fields:
       
   217                 if isinstance(f, models.AutoField):
       
   218                     table_name = self.quote_name(model._meta.db_table)
       
   219                     sequence_name = get_sequence_name(model._meta.db_table)
       
   220                     column_name = self.quote_name(f.column)
       
   221                     output.append(query % {'sequence': sequence_name,
       
   222                                            'table': table_name,
       
   223                                            'column': column_name})
       
   224                     # Only one AutoField is allowed per model, so don't
       
   225                     # continue to loop
       
   226                     break
       
   227             for f in model._meta.many_to_many:
       
   228                 if not f.rel.through:
       
   229                     table_name = self.quote_name(f.m2m_db_table())
       
   230                     sequence_name = get_sequence_name(f.m2m_db_table())
       
   231                     column_name = self.quote_name('id')
       
   232                     output.append(query % {'sequence': sequence_name,
       
   233                                            'table': table_name,
       
   234                                            'column': column_name})
       
   235         return output
       
   236 
       
   237     def start_transaction_sql(self):
       
   238         return ''
       
   239 
       
   240     def tablespace_sql(self, tablespace, inline=False):
       
   241         return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""),
       
   242             self.quote_name(tablespace))
       
   243 
       
   244     def value_to_db_time(self, value):
       
   245         if value is None:
       
   246             return None
       
   247         if isinstance(value, basestring):
       
   248             return datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6]))
       
   249         return datetime.datetime(1900, 1, 1, value.hour, value.minute,
       
   250                                  value.second, value.microsecond)
       
   251 
       
   252     def year_lookup_bounds_for_date_field(self, value):
       
   253         first = '%s-01-01'
       
   254         second = '%s-12-31'
       
   255         return [first % value, second % value]
       
   256 
       
   257     def combine_expression(self, connector, sub_expressions):
       
   258         "Oracle requires special cases for %% and & operators in query expressions"
       
   259         if connector == '%%':
       
   260             return 'MOD(%s)' % ','.join(sub_expressions)
       
   261         elif connector == '&':
       
   262             return 'BITAND(%s)' % ','.join(sub_expressions)
       
   263         elif connector == '|':
       
   264             raise NotImplementedError("Bit-wise or is not supported in Oracle.")
       
   265         return super(DatabaseOperations, self).combine_expression(connector, sub_expressions)
       
   266 
       
   267 
       
   268 class DatabaseWrapper(BaseDatabaseWrapper):
       
   269 
       
   270     operators = {
       
   271         'exact': '= %s',
       
   272         'iexact': '= UPPER(%s)',
       
   273         'contains': "LIKEC %s ESCAPE '\\'",
       
   274         'icontains': "LIKEC UPPER(%s) ESCAPE '\\'",
       
   275         'gt': '> %s',
       
   276         'gte': '>= %s',
       
   277         'lt': '< %s',
       
   278         'lte': '<= %s',
       
   279         'startswith': "LIKEC %s ESCAPE '\\'",
       
   280         'endswith': "LIKEC %s ESCAPE '\\'",
       
   281         'istartswith': "LIKEC UPPER(%s) ESCAPE '\\'",
       
   282         'iendswith': "LIKEC UPPER(%s) ESCAPE '\\'",
       
   283     }
       
   284     oracle_version = None
       
   285 
       
   286     def __init__(self, *args, **kwargs):
       
   287         super(DatabaseWrapper, self).__init__(*args, **kwargs)
       
   288 
       
   289         self.features = DatabaseFeatures()
       
   290         self.ops = DatabaseOperations()
       
   291         self.client = DatabaseClient(self)
       
   292         self.creation = DatabaseCreation(self)
       
   293         self.introspection = DatabaseIntrospection(self)
       
   294         self.validation = BaseDatabaseValidation()
       
   295 
       
   296     def _valid_connection(self):
       
   297         return self.connection is not None
       
   298 
       
   299     def _connect_string(self):
       
   300         settings_dict = self.settings_dict
       
   301         if len(settings_dict['DATABASE_HOST'].strip()) == 0:
       
   302             settings_dict['DATABASE_HOST'] = 'localhost'
       
   303         if len(settings_dict['DATABASE_PORT'].strip()) != 0:
       
   304             dsn = Database.makedsn(settings_dict['DATABASE_HOST'],
       
   305                                    int(settings_dict['DATABASE_PORT']),
       
   306                                    settings_dict['DATABASE_NAME'])
       
   307         else:
       
   308             dsn = settings_dict['DATABASE_NAME']
       
   309         return "%s/%s@%s" % (settings_dict['DATABASE_USER'],
       
   310                              settings_dict['DATABASE_PASSWORD'], dsn)
       
   311 
       
   312     def _cursor(self):
       
   313         cursor = None
       
   314         if not self._valid_connection():
       
   315             conn_string = convert_unicode(self._connect_string())
       
   316             self.connection = Database.connect(conn_string, **self.settings_dict['DATABASE_OPTIONS'])
       
   317             cursor = FormatStylePlaceholderCursor(self.connection)
       
   318             # Set oracle date to ansi date format.  This only needs to execute
       
   319             # once when we create a new connection. We also set the Territory
       
   320             # to 'AMERICA' which forces Sunday to evaluate to a '1' in TO_CHAR().
       
   321             cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' "
       
   322                            "NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF' "
       
   323                            "NLS_TERRITORY = 'AMERICA'")
       
   324             try:
       
   325                 self.oracle_version = int(self.connection.version.split('.')[0])
       
   326                 # There's no way for the DatabaseOperations class to know the
       
   327                 # currently active Oracle version, so we do some setups here.
       
   328                 # TODO: Multi-db support will need a better solution (a way to
       
   329                 # communicate the current version).
       
   330                 if self.oracle_version <= 9:
       
   331                     self.ops.regex_lookup = self.ops.regex_lookup_9
       
   332                 else:
       
   333                     self.ops.regex_lookup = self.ops.regex_lookup_10
       
   334             except ValueError:
       
   335                 pass
       
   336             try:
       
   337                 self.connection.stmtcachesize = 20
       
   338             except:
       
   339                 # Django docs specify cx_Oracle version 4.3.1 or higher, but
       
   340                 # stmtcachesize is available only in 4.3.2 and up.
       
   341                 pass
       
   342             connection_created.send(sender=self.__class__)
       
   343         if not cursor:
       
   344             cursor = FormatStylePlaceholderCursor(self.connection)
       
   345         return cursor
       
   346 
       
   347     # Oracle doesn't support savepoint commits.  Ignore them.
       
   348     def _savepoint_commit(self, sid):
       
   349         pass
       
   350 
       
   351 
       
   352 class OracleParam(object):
       
   353     """
       
   354     Wrapper object for formatting parameters for Oracle. If the string
       
   355     representation of the value is large enough (greater than 4000 characters)
       
   356     the input size needs to be set as CLOB. Alternatively, if the parameter
       
   357     has an `input_size` attribute, then the value of the `input_size` attribute
       
   358     will be used instead. Otherwise, no input size will be set for the
       
   359     parameter when executing the query.
       
   360     """
       
   361 
       
   362     def __init__(self, param, cursor, strings_only=False):
       
   363         if hasattr(param, 'bind_parameter'):
       
   364             self.smart_str = param.bind_parameter(cursor)
       
   365         else:
       
   366             self.smart_str = convert_unicode(param, cursor.charset,
       
   367                                              strings_only)
       
   368         if hasattr(param, 'input_size'):
       
   369             # If parameter has `input_size` attribute, use that.
       
   370             self.input_size = param.input_size
       
   371         elif isinstance(param, basestring) and len(param) > 4000:
       
   372             # Mark any string param greater than 4000 characters as a CLOB.
       
   373             self.input_size = Database.CLOB
       
   374         else:
       
   375             self.input_size = None
       
   376 
       
   377 
       
   378 class InsertIdVar(object):
       
   379     """
       
   380     A late-binding cursor variable that can be passed to Cursor.execute
       
   381     as a parameter, in order to receive the id of the row created by an
       
   382     insert statement.
       
   383     """
       
   384 
       
   385     def bind_parameter(self, cursor):
       
   386         param = cursor.var(Database.NUMBER)
       
   387         cursor._insert_id_var = param
       
   388         return param
       
   389 
       
   390 
       
   391 class FormatStylePlaceholderCursor(object):
       
   392     """
       
   393     Django uses "format" (e.g. '%s') style placeholders, but Oracle uses ":var"
       
   394     style. This fixes it -- but note that if you want to use a literal "%s" in
       
   395     a query, you'll need to use "%%s".
       
   396 
       
   397     We also do automatic conversion between Unicode on the Python side and
       
   398     UTF-8 -- for talking to Oracle -- in here.
       
   399     """
       
   400     charset = 'utf-8'
       
   401 
       
   402     def __init__(self, connection):
       
   403         self.cursor = connection.cursor()
       
   404         # Necessary to retrieve decimal values without rounding error.
       
   405         self.cursor.numbersAsStrings = True
       
   406         # Default arraysize of 1 is highly sub-optimal.
       
   407         self.cursor.arraysize = 100
       
   408 
       
   409     def _format_params(self, params):
       
   410         return tuple([OracleParam(p, self, True) for p in params])
       
   411 
       
   412     def _guess_input_sizes(self, params_list):
       
   413         sizes = [None] * len(params_list[0])
       
   414         for params in params_list:
       
   415             for i, value in enumerate(params):
       
   416                 if value.input_size:
       
   417                     sizes[i] = value.input_size
       
   418         self.setinputsizes(*sizes)
       
   419 
       
   420     def _param_generator(self, params):
       
   421         return [p.smart_str for p in params]
       
   422 
       
   423     def execute(self, query, params=None):
       
   424         if params is None:
       
   425             params = []
       
   426         else:
       
   427             params = self._format_params(params)
       
   428         args = [(':arg%d' % i) for i in range(len(params))]
       
   429         # cx_Oracle wants no trailing ';' for SQL statements.  For PL/SQL, it
       
   430         # it does want a trailing ';' but not a trailing '/'.  However, these
       
   431         # characters must be included in the original query in case the query
       
   432         # is being passed to SQL*Plus.
       
   433         if query.endswith(';') or query.endswith('/'):
       
   434             query = query[:-1]
       
   435         query = convert_unicode(query % tuple(args), self.charset)
       
   436         self._guess_input_sizes([params])
       
   437         try:
       
   438             return self.cursor.execute(query, self._param_generator(params))
       
   439         except DatabaseError, e:
       
   440             # cx_Oracle <= 4.4.0 wrongly raises a DatabaseError for ORA-01400.
       
   441             if e.args[0].code == 1400 and not isinstance(e, IntegrityError):
       
   442                 e = IntegrityError(e.args[0])
       
   443             raise e
       
   444 
       
   445     def executemany(self, query, params=None):
       
   446         try:
       
   447             args = [(':arg%d' % i) for i in range(len(params[0]))]
       
   448         except (IndexError, TypeError):
       
   449             # No params given, nothing to do
       
   450             return None
       
   451         # cx_Oracle wants no trailing ';' for SQL statements.  For PL/SQL, it
       
   452         # it does want a trailing ';' but not a trailing '/'.  However, these
       
   453         # characters must be included in the original query in case the query
       
   454         # is being passed to SQL*Plus.
       
   455         if query.endswith(';') or query.endswith('/'):
       
   456             query = query[:-1]
       
   457         query = convert_unicode(query % tuple(args), self.charset)
       
   458         formatted = [self._format_params(i) for i in params]
       
   459         self._guess_input_sizes(formatted)
       
   460         try:
       
   461             return self.cursor.executemany(query,
       
   462                                 [self._param_generator(p) for p in formatted])
       
   463         except DatabaseError, e:
       
   464             # cx_Oracle <= 4.4.0 wrongly raises a DatabaseError for ORA-01400.
       
   465             if e.args[0].code == 1400 and not isinstance(e, IntegrityError):
       
   466                 e = IntegrityError(e.args[0])
       
   467             raise e
       
   468 
       
   469     def fetchone(self):
       
   470         row = self.cursor.fetchone()
       
   471         if row is None:
       
   472             return row
       
   473         return self._rowfactory(row)
       
   474 
       
   475     def fetchmany(self, size=None):
       
   476         if size is None:
       
   477             size = self.arraysize
       
   478         return tuple([self._rowfactory(r)
       
   479                       for r in self.cursor.fetchmany(size)])
       
   480 
       
   481     def fetchall(self):
       
   482         return tuple([self._rowfactory(r)
       
   483                       for r in self.cursor.fetchall()])
       
   484 
       
   485     def _rowfactory(self, row):
       
   486         # Cast numeric values as the appropriate Python type based upon the
       
   487         # cursor description, and convert strings to unicode.
       
   488         casted = []
       
   489         for value, desc in zip(row, self.cursor.description):
       
   490             if value is not None and desc[1] is Database.NUMBER:
       
   491                 precision, scale = desc[4:6]
       
   492                 if scale == -127:
       
   493                     if precision == 0:
       
   494                         # NUMBER column: decimal-precision floating point
       
   495                         # This will normally be an integer from a sequence,
       
   496                         # but it could be a decimal value.
       
   497                         if '.' in value:
       
   498                             value = Decimal(value)
       
   499                         else:
       
   500                             value = int(value)
       
   501                     else:
       
   502                         # FLOAT column: binary-precision floating point.
       
   503                         # This comes from FloatField columns.
       
   504                         value = float(value)
       
   505                 elif precision > 0:
       
   506                     # NUMBER(p,s) column: decimal-precision fixed point.
       
   507                     # This comes from IntField and DecimalField columns.
       
   508                     if scale == 0:
       
   509                         value = int(value)
       
   510                     else:
       
   511                         value = Decimal(value)
       
   512                 elif '.' in value:
       
   513                     # No type information. This normally comes from a
       
   514                     # mathematical expression in the SELECT list. Guess int
       
   515                     # or Decimal based on whether it has a decimal point.
       
   516                     value = Decimal(value)
       
   517                 else:
       
   518                     value = int(value)
       
   519             elif desc[1] in (Database.STRING, Database.FIXED_CHAR,
       
   520                              Database.LONG_STRING):
       
   521                 value = to_unicode(value)
       
   522             casted.append(value)
       
   523         return tuple(casted)
       
   524 
       
   525     def __getattr__(self, attr):
       
   526         if attr in self.__dict__:
       
   527             return self.__dict__[attr]
       
   528         else:
       
   529             return getattr(self.cursor, attr)
       
   530 
       
   531     def __iter__(self):
       
   532         return iter(self.cursor)
       
   533 
       
   534 
       
   535 def to_unicode(s):
       
   536     """
       
   537     Convert strings to Unicode objects (and return all other data types
       
   538     unchanged).
       
   539     """
       
   540     if isinstance(s, basestring):
       
   541         return force_unicode(s)
       
   542     return s
       
   543 
       
   544 
       
   545 def _get_sequence_reset_sql():
       
   546     # TODO: colorize this SQL code with style.SQL_KEYWORD(), etc.
       
   547     return """
       
   548 DECLARE
       
   549     startvalue integer;
       
   550     cval integer;
       
   551 BEGIN
       
   552     LOCK TABLE %(table)s IN SHARE MODE;
       
   553     SELECT NVL(MAX(%(column)s), 0) INTO startvalue FROM %(table)s;
       
   554     SELECT "%(sequence)s".nextval INTO cval FROM dual;
       
   555     cval := startvalue - cval;
       
   556     IF cval != 0 THEN
       
   557         EXECUTE IMMEDIATE 'ALTER SEQUENCE "%(sequence)s" MINVALUE 0 INCREMENT BY '||cval;
       
   558         SELECT "%(sequence)s".nextval INTO cval FROM dual;
       
   559         EXECUTE IMMEDIATE 'ALTER SEQUENCE "%(sequence)s" INCREMENT BY 1';
       
   560     END IF;
       
   561     COMMIT;
       
   562 END;
       
   563 /"""
       
   564 
       
   565 
       
   566 def get_sequence_name(table):
       
   567     name_length = DatabaseOperations().max_name_length() - 3
       
   568     return '%s_SQ' % util.truncate_name(table, name_length).upper()
       
   569 
       
   570 
       
   571 def get_trigger_name(table):
       
   572     name_length = DatabaseOperations().max_name_length() - 3
       
   573     return '%s_TR' % util.truncate_name(table, name_length).upper()