Add Django-1.2.1
[frozenviper.git] / Django-1.2.1 / build / lib.linux-i686-2.6 / django / db / backends / oracle / base.py
blob369e65baf744359980e7cb248fc77e3be877e368
1 """
2 Oracle database backend for Django.
4 Requires cx_Oracle: http://cx-oracle.sourceforge.net/
5 """
8 import datetime
9 import os
10 import sys
11 import time
12 from decimal import Decimal
14 # Oracle takes client-side character set encoding from the environment.
15 os.environ['NLS_LANG'] = '.UTF8'
16 # This prevents unicode from getting mangled by getting encoded into the
17 # potentially non-unicode database character set.
18 os.environ['ORA_NCHAR_LITERAL_REPLACE'] = 'TRUE'
20 try:
21 import cx_Oracle as Database
22 except ImportError, e:
23 from django.core.exceptions import ImproperlyConfigured
24 raise ImproperlyConfigured("Error loading cx_Oracle module: %s" % e)
26 from django.db import utils
27 from django.db.backends import *
28 from django.db.backends.signals import connection_created
29 from django.db.backends.oracle.client import DatabaseClient
30 from django.db.backends.oracle.creation import DatabaseCreation
31 from django.db.backends.oracle.introspection import DatabaseIntrospection
32 from django.utils.encoding import smart_str, force_unicode
34 DatabaseError = Database.DatabaseError
35 IntegrityError = Database.IntegrityError
38 # Check whether cx_Oracle was compiled with the WITH_UNICODE option. This will
39 # also be True in Python 3.0.
40 if int(Database.version.split('.', 1)[0]) >= 5 and not hasattr(Database, 'UNICODE'):
41 convert_unicode = force_unicode
42 else:
43 convert_unicode = smart_str
46 class DatabaseFeatures(BaseDatabaseFeatures):
47 empty_fetchmany_value = ()
48 needs_datetime_string_cast = False
49 interprets_empty_strings_as_nulls = True
50 uses_savepoints = True
51 can_return_id_from_insert = True
52 allow_sliced_subqueries = False
55 class DatabaseOperations(BaseDatabaseOperations):
56 compiler_module = "django.db.backends.oracle.compiler"
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
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)
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
105 def convert_values(self, value, field):
106 if isinstance(value, Database.LOB):
107 value = value.read()
108 if field and field.get_internal_type() == 'TextField':
109 value = force_unicode(value)
111 # Oracle stores empty strings as null. We need to undo this in
112 # order to adhere to the Django convention of using the empty
113 # string instead of null, but only if the field accepts the
114 # empty string.
115 if value is None and field and field.empty_strings_allowed:
116 value = u''
117 # Convert 1 or 0 to True or False
118 elif value in (1, 0) and field and field.get_internal_type() in ('BooleanField', 'NullBooleanField'):
119 value = bool(value)
120 # Force floats to the correct type
121 elif value is not None and field and field.get_internal_type() == 'FloatField':
122 value = float(value)
123 # Convert floats to decimals
124 elif value is not None and field and field.get_internal_type() == 'DecimalField':
125 value = util.typecast_decimal(field.format_number(value))
126 # cx_Oracle always returns datetime.datetime objects for
127 # DATE and TIMESTAMP columns, but Django wants to see a
128 # python datetime.date, .time, or .datetime. We use the type
129 # of the Field to determine which to cast to, but it's not
130 # always available.
131 # As a workaround, we cast to date if all the time-related
132 # values are 0, or to time if the date is 1/1/1900.
133 # This could be cleaned a bit by adding a method to the Field
134 # classes to normalize values from the database (the to_python
135 # method is used for validation and isn't what we want here).
136 elif isinstance(value, Database.Timestamp):
137 # In Python 2.3, the cx_Oracle driver returns its own
138 # Timestamp object that we must convert to a datetime class.
139 if not isinstance(value, datetime.datetime):
140 value = datetime.datetime(value.year, value.month,
141 value.day, value.hour, value.minute, value.second,
142 value.fsecond)
143 if field and field.get_internal_type() == 'DateTimeField':
144 pass
145 elif field and field.get_internal_type() == 'DateField':
146 value = value.date()
147 elif field and field.get_internal_type() == 'TimeField' or (value.year == 1900 and value.month == value.day == 1):
148 value = value.time()
149 elif value.hour == value.minute == value.second == value.microsecond == 0:
150 value = value.date()
151 return value
153 def datetime_cast_sql(self):
154 return "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')"
156 def deferrable_sql(self):
157 return " DEFERRABLE INITIALLY DEFERRED"
159 def drop_sequence_sql(self, table):
160 return "DROP SEQUENCE %s;" % self.quote_name(get_sequence_name(table))
162 def fetch_returned_insert_id(self, cursor):
163 return long(cursor._insert_id_var.getvalue())
165 def field_cast_sql(self, db_type):
166 if db_type and db_type.endswith('LOB'):
167 return "DBMS_LOB.SUBSTR(%s)"
168 else:
169 return "%s"
171 def last_insert_id(self, cursor, table_name, pk_name):
172 sq_name = get_sequence_name(table_name)
173 cursor.execute('SELECT "%s".currval FROM dual' % sq_name)
174 return cursor.fetchone()[0]
176 def lookup_cast(self, lookup_type):
177 if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'):
178 return "UPPER(%s)"
179 return "%s"
181 def max_name_length(self):
182 return 30
184 def prep_for_iexact_query(self, x):
185 return x
187 def process_clob(self, value):
188 if value is None:
189 return u''
190 return force_unicode(value.read())
192 def quote_name(self, name):
193 # SQL92 requires delimited (quoted) names to be case-sensitive. When
194 # not quoted, Oracle has case-insensitive behavior for identifiers, but
195 # always defaults to uppercase.
196 # We simplify things by making Oracle identifiers always uppercase.
197 if not name.startswith('"') and not name.endswith('"'):
198 name = '"%s"' % util.truncate_name(name.upper(),
199 self.max_name_length())
200 return name.upper()
202 def random_function_sql(self):
203 return "DBMS_RANDOM.RANDOM"
205 def regex_lookup_9(self, lookup_type):
206 raise NotImplementedError("Regexes are not supported in Oracle before version 10g.")
208 def regex_lookup_10(self, lookup_type):
209 if lookup_type == 'regex':
210 match_option = "'c'"
211 else:
212 match_option = "'i'"
213 return 'REGEXP_LIKE(%%s, %%s, %s)' % match_option
215 def regex_lookup(self, lookup_type):
216 # If regex_lookup is called before it's been initialized, then create
217 # a cursor to initialize it and recur.
218 from django.db import connection
219 connection.cursor()
220 return connection.ops.regex_lookup(lookup_type)
222 def return_insert_id(self):
223 return "RETURNING %s INTO %%s", (InsertIdVar(),)
225 def savepoint_create_sql(self, sid):
226 return convert_unicode("SAVEPOINT " + self.quote_name(sid))
228 def savepoint_rollback_sql(self, sid):
229 return convert_unicode("ROLLBACK TO SAVEPOINT " + self.quote_name(sid))
231 def sql_flush(self, style, tables, sequences):
232 # Return a list of 'TRUNCATE x;', 'TRUNCATE y;',
233 # 'TRUNCATE z;'... style SQL statements
234 if tables:
235 # Oracle does support TRUNCATE, but it seems to get us into
236 # FK referential trouble, whereas DELETE FROM table works.
237 sql = ['%s %s %s;' % \
238 (style.SQL_KEYWORD('DELETE'),
239 style.SQL_KEYWORD('FROM'),
240 style.SQL_FIELD(self.quote_name(table)))
241 for table in tables]
242 # Since we've just deleted all the rows, running our sequence
243 # ALTER code will reset the sequence to 0.
244 for sequence_info in sequences:
245 sequence_name = get_sequence_name(sequence_info['table'])
246 table_name = self.quote_name(sequence_info['table'])
247 column_name = self.quote_name(sequence_info['column'] or 'id')
248 query = _get_sequence_reset_sql() % {'sequence': sequence_name,
249 'table': table_name,
250 'column': column_name}
251 sql.append(query)
252 return sql
253 else:
254 return []
256 def sequence_reset_sql(self, style, model_list):
257 from django.db import models
258 output = []
259 query = _get_sequence_reset_sql()
260 for model in model_list:
261 for f in model._meta.local_fields:
262 if isinstance(f, models.AutoField):
263 table_name = self.quote_name(model._meta.db_table)
264 sequence_name = get_sequence_name(model._meta.db_table)
265 column_name = self.quote_name(f.column)
266 output.append(query % {'sequence': sequence_name,
267 'table': table_name,
268 'column': column_name})
269 # Only one AutoField is allowed per model, so don't
270 # continue to loop
271 break
272 for f in model._meta.many_to_many:
273 if not f.rel.through:
274 table_name = self.quote_name(f.m2m_db_table())
275 sequence_name = get_sequence_name(f.m2m_db_table())
276 column_name = self.quote_name('id')
277 output.append(query % {'sequence': sequence_name,
278 'table': table_name,
279 'column': column_name})
280 return output
282 def start_transaction_sql(self):
283 return ''
285 def tablespace_sql(self, tablespace, inline=False):
286 return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""),
287 self.quote_name(tablespace))
289 def value_to_db_time(self, value):
290 if value is None:
291 return None
292 if isinstance(value, basestring):
293 return datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6]))
294 return datetime.datetime(1900, 1, 1, value.hour, value.minute,
295 value.second, value.microsecond)
297 def year_lookup_bounds_for_date_field(self, value):
298 first = '%s-01-01'
299 second = '%s-12-31'
300 return [first % value, second % value]
302 def combine_expression(self, connector, sub_expressions):
303 "Oracle requires special cases for %% and & operators in query expressions"
304 if connector == '%%':
305 return 'MOD(%s)' % ','.join(sub_expressions)
306 elif connector == '&':
307 return 'BITAND(%s)' % ','.join(sub_expressions)
308 elif connector == '|':
309 raise NotImplementedError("Bit-wise or is not supported in Oracle.")
310 return super(DatabaseOperations, self).combine_expression(connector, sub_expressions)
313 class DatabaseWrapper(BaseDatabaseWrapper):
315 operators = {
316 'exact': '= %s',
317 'iexact': '= UPPER(%s)',
318 'contains': "LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
319 'icontains': "LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
320 'gt': '> %s',
321 'gte': '>= %s',
322 'lt': '< %s',
323 'lte': '<= %s',
324 'startswith': "LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
325 'endswith': "LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
326 'istartswith': "LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
327 'iendswith': "LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
329 oracle_version = None
331 def __init__(self, *args, **kwargs):
332 super(DatabaseWrapper, self).__init__(*args, **kwargs)
334 self.features = DatabaseFeatures()
335 self.ops = DatabaseOperations()
336 self.client = DatabaseClient(self)
337 self.creation = DatabaseCreation(self)
338 self.introspection = DatabaseIntrospection(self)
339 self.validation = BaseDatabaseValidation(self)
341 def _valid_connection(self):
342 return self.connection is not None
344 def _connect_string(self):
345 settings_dict = self.settings_dict
346 if len(settings_dict['HOST'].strip()) == 0:
347 settings_dict['HOST'] = 'localhost'
348 if len(settings_dict['PORT'].strip()) != 0:
349 dsn = Database.makedsn(settings_dict['HOST'],
350 int(settings_dict['PORT']),
351 settings_dict['NAME'])
352 else:
353 dsn = settings_dict['NAME']
354 return "%s/%s@%s" % (settings_dict['USER'],
355 settings_dict['PASSWORD'], dsn)
357 def _cursor(self):
358 cursor = None
359 if not self._valid_connection():
360 conn_string = convert_unicode(self._connect_string())
361 self.connection = Database.connect(conn_string, **self.settings_dict['OPTIONS'])
362 cursor = FormatStylePlaceholderCursor(self.connection)
363 # Set oracle date to ansi date format. This only needs to execute
364 # once when we create a new connection. We also set the Territory
365 # to 'AMERICA' which forces Sunday to evaluate to a '1' in TO_CHAR().
366 cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' "
367 "NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF' "
368 "NLS_TERRITORY = 'AMERICA'")
369 try:
370 self.oracle_version = int(self.connection.version.split('.')[0])
371 # There's no way for the DatabaseOperations class to know the
372 # currently active Oracle version, so we do some setups here.
373 # TODO: Multi-db support will need a better solution (a way to
374 # communicate the current version).
375 if self.oracle_version <= 9:
376 self.ops.regex_lookup = self.ops.regex_lookup_9
377 else:
378 self.ops.regex_lookup = self.ops.regex_lookup_10
379 except ValueError:
380 pass
381 try:
382 self.connection.stmtcachesize = 20
383 except:
384 # Django docs specify cx_Oracle version 4.3.1 or higher, but
385 # stmtcachesize is available only in 4.3.2 and up.
386 pass
387 connection_created.send(sender=self.__class__)
388 if not cursor:
389 cursor = FormatStylePlaceholderCursor(self.connection)
390 return cursor
392 # Oracle doesn't support savepoint commits. Ignore them.
393 def _savepoint_commit(self, sid):
394 pass
397 class OracleParam(object):
399 Wrapper object for formatting parameters for Oracle. If the string
400 representation of the value is large enough (greater than 4000 characters)
401 the input size needs to be set as CLOB. Alternatively, if the parameter
402 has an `input_size` attribute, then the value of the `input_size` attribute
403 will be used instead. Otherwise, no input size will be set for the
404 parameter when executing the query.
407 def __init__(self, param, cursor, strings_only=False):
408 if hasattr(param, 'bind_parameter'):
409 self.smart_str = param.bind_parameter(cursor)
410 else:
411 self.smart_str = convert_unicode(param, cursor.charset,
412 strings_only)
413 if hasattr(param, 'input_size'):
414 # If parameter has `input_size` attribute, use that.
415 self.input_size = param.input_size
416 elif isinstance(param, basestring) and len(param) > 4000:
417 # Mark any string param greater than 4000 characters as a CLOB.
418 self.input_size = Database.CLOB
419 else:
420 self.input_size = None
423 class VariableWrapper(object):
425 An adapter class for cursor variables that prevents the wrapped object
426 from being converted into a string when used to instanciate an OracleParam.
427 This can be used generally for any other object that should be passed into
428 Cursor.execute as-is.
431 def __init__(self, var):
432 self.var = var
434 def bind_parameter(self, cursor):
435 return self.var
437 def __getattr__(self, key):
438 return getattr(self.var, key)
440 def __setattr__(self, key, value):
441 if key == 'var':
442 self.__dict__[key] = value
443 else:
444 setattr(self.var, key, value)
447 class InsertIdVar(object):
449 A late-binding cursor variable that can be passed to Cursor.execute
450 as a parameter, in order to receive the id of the row created by an
451 insert statement.
454 def bind_parameter(self, cursor):
455 param = cursor.cursor.var(Database.NUMBER)
456 cursor._insert_id_var = param
457 return param
460 class FormatStylePlaceholderCursor(object):
462 Django uses "format" (e.g. '%s') style placeholders, but Oracle uses ":var"
463 style. This fixes it -- but note that if you want to use a literal "%s" in
464 a query, you'll need to use "%%s".
466 We also do automatic conversion between Unicode on the Python side and
467 UTF-8 -- for talking to Oracle -- in here.
469 charset = 'utf-8'
471 def __init__(self, connection):
472 self.cursor = connection.cursor()
473 # Necessary to retrieve decimal values without rounding error.
474 self.cursor.numbersAsStrings = True
475 # Default arraysize of 1 is highly sub-optimal.
476 self.cursor.arraysize = 100
478 def _format_params(self, params):
479 return tuple([OracleParam(p, self, True) for p in params])
481 def _guess_input_sizes(self, params_list):
482 sizes = [None] * len(params_list[0])
483 for params in params_list:
484 for i, value in enumerate(params):
485 if value.input_size:
486 sizes[i] = value.input_size
487 self.setinputsizes(*sizes)
489 def _param_generator(self, params):
490 return [p.smart_str for p in params]
492 def execute(self, query, params=None):
493 if params is None:
494 params = []
495 else:
496 params = self._format_params(params)
497 args = [(':arg%d' % i) for i in range(len(params))]
498 # cx_Oracle wants no trailing ';' for SQL statements. For PL/SQL, it
499 # it does want a trailing ';' but not a trailing '/'. However, these
500 # characters must be included in the original query in case the query
501 # is being passed to SQL*Plus.
502 if query.endswith(';') or query.endswith('/'):
503 query = query[:-1]
504 query = convert_unicode(query % tuple(args), self.charset)
505 self._guess_input_sizes([params])
506 try:
507 return self.cursor.execute(query, self._param_generator(params))
508 except Database.IntegrityError, e:
509 raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
510 except Database.DatabaseError, e:
511 # cx_Oracle <= 4.4.0 wrongly raises a DatabaseError for ORA-01400.
512 if hasattr(e.args[0], 'code') and e.args[0].code == 1400 and not isinstance(e, IntegrityError):
513 raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
514 raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
516 def executemany(self, query, params=None):
517 try:
518 args = [(':arg%d' % i) for i in range(len(params[0]))]
519 except (IndexError, TypeError):
520 # No params given, nothing to do
521 return None
522 # cx_Oracle wants no trailing ';' for SQL statements. For PL/SQL, it
523 # it does want a trailing ';' but not a trailing '/'. However, these
524 # characters must be included in the original query in case the query
525 # is being passed to SQL*Plus.
526 if query.endswith(';') or query.endswith('/'):
527 query = query[:-1]
528 query = convert_unicode(query % tuple(args), self.charset)
529 formatted = [self._format_params(i) for i in params]
530 self._guess_input_sizes(formatted)
531 try:
532 return self.cursor.executemany(query,
533 [self._param_generator(p) for p in formatted])
534 except Database.IntegrityError, e:
535 raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
536 except Database.DatabaseError, e:
537 # cx_Oracle <= 4.4.0 wrongly raises a DatabaseError for ORA-01400.
538 if hasattr(e.args[0], 'code') and e.args[0].code == 1400 and not isinstance(e, IntegrityError):
539 raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
540 raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
542 def fetchone(self):
543 row = self.cursor.fetchone()
544 if row is None:
545 return row
546 return _rowfactory(row, self.cursor)
548 def fetchmany(self, size=None):
549 if size is None:
550 size = self.arraysize
551 return tuple([_rowfactory(r, self.cursor)
552 for r in self.cursor.fetchmany(size)])
554 def fetchall(self):
555 return tuple([_rowfactory(r, self.cursor)
556 for r in self.cursor.fetchall()])
558 def var(self, *args):
559 return VariableWrapper(self.cursor.var(*args))
561 def arrayvar(self, *args):
562 return VariableWrapper(self.cursor.arrayvar(*args))
564 def __getattr__(self, attr):
565 if attr in self.__dict__:
566 return self.__dict__[attr]
567 else:
568 return getattr(self.cursor, attr)
570 def __iter__(self):
571 return CursorIterator(self.cursor)
574 class CursorIterator(object):
576 """Cursor iterator wrapper that invokes our custom row factory."""
578 def __init__(self, cursor):
579 self.cursor = cursor
580 self.iter = iter(cursor)
582 def __iter__(self):
583 return self
585 def next(self):
586 return _rowfactory(self.iter.next(), self.cursor)
589 def _rowfactory(row, cursor):
590 # Cast numeric values as the appropriate Python type based upon the
591 # cursor description, and convert strings to unicode.
592 casted = []
593 for value, desc in zip(row, cursor.description):
594 if value is not None and desc[1] is Database.NUMBER:
595 precision, scale = desc[4:6]
596 if scale == -127:
597 if precision == 0:
598 # NUMBER column: decimal-precision floating point
599 # This will normally be an integer from a sequence,
600 # but it could be a decimal value.
601 if '.' in value:
602 value = Decimal(value)
603 else:
604 value = int(value)
605 else:
606 # FLOAT column: binary-precision floating point.
607 # This comes from FloatField columns.
608 value = float(value)
609 elif precision > 0:
610 # NUMBER(p,s) column: decimal-precision fixed point.
611 # This comes from IntField and DecimalField columns.
612 if scale == 0:
613 value = int(value)
614 else:
615 value = Decimal(value)
616 elif '.' in value:
617 # No type information. This normally comes from a
618 # mathematical expression in the SELECT list. Guess int
619 # or Decimal based on whether it has a decimal point.
620 value = Decimal(value)
621 else:
622 value = int(value)
623 elif desc[1] in (Database.STRING, Database.FIXED_CHAR,
624 Database.LONG_STRING):
625 value = to_unicode(value)
626 casted.append(value)
627 return tuple(casted)
630 def to_unicode(s):
632 Convert strings to Unicode objects (and return all other data types
633 unchanged).
635 if isinstance(s, basestring):
636 return force_unicode(s)
637 return s
640 def _get_sequence_reset_sql():
641 # TODO: colorize this SQL code with style.SQL_KEYWORD(), etc.
642 return """
643 DECLARE
644 startvalue integer;
645 cval integer;
646 BEGIN
647 LOCK TABLE %(table)s IN SHARE MODE;
648 SELECT NVL(MAX(%(column)s), 0) INTO startvalue FROM %(table)s;
649 SELECT "%(sequence)s".nextval INTO cval FROM dual;
650 cval := startvalue - cval;
651 IF cval != 0 THEN
652 EXECUTE IMMEDIATE 'ALTER SEQUENCE "%(sequence)s" MINVALUE 0 INCREMENT BY '||cval;
653 SELECT "%(sequence)s".nextval INTO cval FROM dual;
654 EXECUTE IMMEDIATE 'ALTER SEQUENCE "%(sequence)s" INCREMENT BY 1';
655 END IF;
656 COMMIT;
657 END;
658 /"""
661 def get_sequence_name(table):
662 name_length = DatabaseOperations().max_name_length() - 3
663 return '%s_SQ' % util.truncate_name(table, name_length).upper()
666 def get_trigger_name(table):
667 name_length = DatabaseOperations().max_name_length() - 3
668 return '%s_TR' % util.truncate_name(table, name_length).upper()