mirror of
https://github.com/django/django.git
synced 2025-10-21 04:39:17 +00:00
boulder-oracle-sprint: Changed Oracle CLOB to NCLOB for i18n.
Fixed Oracle backend's get_date_trunc_sql() function. git-svn-id: http://code.djangoproject.com/svn/django/branches/boulder-oracle-sprint@4064 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
b47c350b56
commit
2ef60b546b
@ -203,16 +203,15 @@ def _get_sql_model_create(model, known_models=set()):
|
|||||||
sequence_statement = 'CREATE SEQUENCE %s;' % sequence_name
|
sequence_statement = 'CREATE SEQUENCE %s;' % sequence_name
|
||||||
final_output.append(sequence_statement)
|
final_output.append(sequence_statement)
|
||||||
trigger_statement = '' + \
|
trigger_statement = '' + \
|
||||||
'CREATE OR REPLACE trigger %s\n' % truncate_name('%s_tr' % opts.db_table, backend.get_max_name_length()) + \
|
'CREATE OR REPLACE TRIGGER %s\n' % truncate_name('%s_tr' % opts.db_table, backend.get_max_name_length()) + \
|
||||||
' before insert on %s\n' % backend.quote_name(opts.db_table) + \
|
' BEFORE INSERT ON %s\n' % backend.quote_name(opts.db_table) + \
|
||||||
' for each row\n' + \
|
' FOR EACH ROW\n' + \
|
||||||
' when (new.id is NULL)\n' + \
|
' WHEN (new.id IS NULL)\n' + \
|
||||||
' begin\n' + \
|
' BEGIN\n' + \
|
||||||
' select %s.NEXTVAL into :new.id from DUAL;\n' % sequence_name + \
|
' SELECT %s.nextval INTO :new.id FROM dual;\n' % sequence_name + \
|
||||||
' end;\n'
|
' END;\n'
|
||||||
final_output.append(trigger_statement)
|
final_output.append(trigger_statement)
|
||||||
|
|
||||||
|
|
||||||
return final_output, pending_references
|
return final_output, pending_references
|
||||||
|
|
||||||
def _get_sql_for_pending_references(model, pending_references):
|
def _get_sql_for_pending_references(model, pending_references):
|
||||||
@ -283,13 +282,13 @@ def _get_many_to_many_sql_for_model(model):
|
|||||||
sequence_statement = 'CREATE SEQUENCE %s;' % sequence_name
|
sequence_statement = 'CREATE SEQUENCE %s;' % sequence_name
|
||||||
final_output.append(sequence_statement)
|
final_output.append(sequence_statement)
|
||||||
trigger_statement = '' + \
|
trigger_statement = '' + \
|
||||||
'CREATE OR REPLACE trigger %s\n' % truncate_name('%s_tr' % m_table, backend.get_max_name_length()) + \
|
'CREATE OR REPLACE TRIGGER %s\n' % truncate_name('%s_tr' % m_table, backend.get_max_name_length()) + \
|
||||||
' before insert on %s\n' % backend.quote_name(m_table) + \
|
' BEFORE INSERT ON %s\n' % backend.quote_name(m_table) + \
|
||||||
' for each row\n' + \
|
' FOR EACH ROW\n' + \
|
||||||
' when (new.id is NULL)\n' + \
|
' WHEN (new.id IS NULL)\n' + \
|
||||||
' begin\n' + \
|
' BEGIN\n' + \
|
||||||
' select %s.NEXTVAL into :new.id from DUAL;\n' % sequence_name + \
|
' SELECT %s.nextval INTO :new.id FROM dual;\n' % sequence_name + \
|
||||||
' end;\n'
|
' END;\n'
|
||||||
final_output.append(trigger_statement)
|
final_output.append(trigger_statement)
|
||||||
return final_output
|
return final_output
|
||||||
|
|
||||||
|
@ -180,9 +180,6 @@ def get_drop_foreignkey_sql():
|
|||||||
def get_pk_default_value():
|
def get_pk_default_value():
|
||||||
return "DEFAULT"
|
return "DEFAULT"
|
||||||
|
|
||||||
def get_max_name_length():
|
|
||||||
return 64
|
|
||||||
|
|
||||||
OPERATOR_MAPPING = {
|
OPERATOR_MAPPING = {
|
||||||
'exact': '= %s',
|
'exact': '= %s',
|
||||||
'iexact': 'LIKE %s',
|
'iexact': 'LIKE %s',
|
||||||
|
@ -40,8 +40,8 @@ class DatabaseWrapper(local):
|
|||||||
conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME)
|
conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME)
|
||||||
self.connection = Database.connect(conn_string)
|
self.connection = Database.connect(conn_string)
|
||||||
# set oracle date to ansi date format
|
# set oracle date to ansi date format
|
||||||
cursor = self.connection.cursor()
|
cursor = self.connection.cursor()
|
||||||
cursor.execute("alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'")
|
cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'")
|
||||||
cursor.close()
|
cursor.close()
|
||||||
return FormatStylePlaceholderCursor(self.connection)
|
return FormatStylePlaceholderCursor(self.connection)
|
||||||
|
|
||||||
@ -68,54 +68,62 @@ class FormatStylePlaceholderCursor(Database.Cursor):
|
|||||||
Django uses "format" (e.g. '%s') style placeholders, but Oracle uses ":var" style.
|
Django uses "format" (e.g. '%s') style placeholders, but Oracle uses ":var" style.
|
||||||
This fixes it -- but note that if you want to use a literal "%s" in a query,
|
This fixes it -- but note that if you want to use a literal "%s" in a query,
|
||||||
you'll need to use "%%s".
|
you'll need to use "%%s".
|
||||||
"""
|
"""
|
||||||
def execute(self, query, params=None):
|
def _rewrite_args(self, query, params=None):
|
||||||
if params is None:
|
if params is None:
|
||||||
params = []
|
params = []
|
||||||
args = [(':arg%s' % i) for i in range(len(params))]
|
args = [(':arg%d' % i) for i in range(len(params))]
|
||||||
query = query % tuple(args)
|
query = query % tuple(args)
|
||||||
|
# cx_Oracle cannot execute a query with the closing ';'
|
||||||
# cx can not execute the query with the closing ';'
|
|
||||||
if query.endswith(';'):
|
if query.endswith(';'):
|
||||||
query = query[:-1]
|
query = query[:-1]
|
||||||
|
return query, params
|
||||||
|
|
||||||
|
def execute(self, query, params=None):
|
||||||
|
query, params = self._rewrite_args(query, params)
|
||||||
|
self.arraysize = 200
|
||||||
return Database.Cursor.execute(self, query, params)
|
return Database.Cursor.execute(self, query, params)
|
||||||
|
|
||||||
def executemany(self, query, params=None):
|
def executemany(self, query, params=None):
|
||||||
if params is None: params = []
|
query, params = self._rewrite_args(query, params)
|
||||||
query = self.convert_arguments(query, len(params[0]))
|
self.arraysize = 200
|
||||||
# cx can not execute the query with the closing ';'
|
|
||||||
if query.endswith(';') :
|
|
||||||
query = query[0:len(query)-1]
|
|
||||||
return Database.Cursor.executemany(self, query, params)
|
return Database.Cursor.executemany(self, query, params)
|
||||||
|
|
||||||
|
|
||||||
def quote_name(name):
|
def quote_name(name):
|
||||||
if name.startswith('"') and name.endswith('"'):
|
# Oracle requires that quoted names be uppercase.
|
||||||
return name # Quoting once is enough.
|
name = name.upper()
|
||||||
|
if not name.startswith('"') and not name.endswith('"'):
|
||||||
# Oracle requires that quoted names be uppercase.
|
name = '"%s"' % util.truncate_name(name.upper(), get_max_name_length())
|
||||||
return '"%s"' % name.upper()
|
return name
|
||||||
|
|
||||||
dictfetchone = util.dictfetchone
|
dictfetchone = util.dictfetchone
|
||||||
dictfetchmany = util.dictfetchmany
|
dictfetchmany = util.dictfetchmany
|
||||||
dictfetchall = util.dictfetchall
|
dictfetchall = util.dictfetchall
|
||||||
|
|
||||||
def get_last_insert_id(cursor, table_name, pk_name):
|
def get_last_insert_id(cursor, table_name, pk_name):
|
||||||
query = "SELECT %s_sq.currval from dual" % table_name
|
cursor.execute('SELECT %s_sq.currval FROM dual' % table_name)
|
||||||
cursor.execute(query)
|
|
||||||
return cursor.fetchone()[0]
|
return cursor.fetchone()[0]
|
||||||
|
|
||||||
def get_date_extract_sql(lookup_type, table_name):
|
def get_date_extract_sql(lookup_type, table_name):
|
||||||
# lookup_type is 'year', 'month', 'day'
|
# lookup_type is 'year', 'month', 'day'
|
||||||
# http://www.psoug.org/reference/date_func.html
|
# http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions42a.htm#1017163
|
||||||
return "EXTRACT(%s FROM %s)" % (lookup_type, table_name)
|
return "EXTRACT(%s FROM %s)" % (lookup_type, table_name)
|
||||||
|
|
||||||
def get_date_trunc_sql(lookup_type, field_name):
|
def get_date_trunc_sql(lookup_type, field_name):
|
||||||
return "EXTRACT(%s FROM TRUNC(%s))" % (lookup_type, field_name)
|
# lookup_type is 'year', 'month', 'day'
|
||||||
|
# Oracle uses TRUNC() for both dates and numbers.
|
||||||
|
# http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions155a.htm#SQLRF06151
|
||||||
|
if lookup_type == 'day':
|
||||||
|
sql = 'TRUNC(%s)' % (field_name,)
|
||||||
|
else:
|
||||||
|
sql = "TRUNC(%s, '%s')" % (field_name, lookup_type)
|
||||||
|
return sql
|
||||||
|
|
||||||
def get_limit_offset_sql(limit, offset=None):
|
def get_limit_offset_sql(limit, offset=None):
|
||||||
# Limits and offset are too complicated to be handled here.
|
# Limits and offset are too complicated to be handled here.
|
||||||
# Instead, they are handled in django/db/query.py.
|
# Instead, they are handled in django/db/backends/oracle/query.py.
|
||||||
pass
|
raise NotImplementedError
|
||||||
|
|
||||||
def get_random_function_sql():
|
def get_random_function_sql():
|
||||||
return "DBMS_RANDOM.RANDOM"
|
return "DBMS_RANDOM.RANDOM"
|
||||||
|
@ -1,34 +1,40 @@
|
|||||||
import sys
|
import sys, time
|
||||||
|
|
||||||
|
# This dictionary maps Field objects to their associated Oracle column
|
||||||
|
# types, as strings. Column-type strings can contain format strings; they'll
|
||||||
|
# be interpolated against the values of Field.__dict__ before being output.
|
||||||
|
# If a column type is set to None, it won't be included in the output.
|
||||||
DATA_TYPES = {
|
DATA_TYPES = {
|
||||||
'AutoField': 'number(11)',
|
'AutoField': 'NUMBER(11)',
|
||||||
'BooleanField': 'number(1) CHECK (%(column)s IN (0,1))',
|
'BooleanField': 'NUMBER(1) CHECK (%(column)s IN (0,1))',
|
||||||
'CharField': 'varchar2(%(maxlength)s)',
|
'CharField': 'VARCHAR2(%(maxlength)s)',
|
||||||
'CommaSeparatedIntegerField': 'varchar2(%(maxlength)s)',
|
'CommaSeparatedIntegerField': 'VARCHAR2(%(maxlength)s)',
|
||||||
'DateField': 'date',
|
'DateField': 'DATE',
|
||||||
'DateTimeField': 'timestamp with time zone',
|
'DateTimeField': 'TIMESTAMP WITH TIME ZONE',
|
||||||
'FileField': 'varchar2(100)',
|
'FileField': 'VARCHAR2(100)',
|
||||||
'FilePathField': 'varchar2(100)',
|
'FilePathField': 'VARCHAR2(100)',
|
||||||
'FloatField': 'number(%(max_digits)s, %(decimal_places)s)',
|
'FloatField': 'NUMBER(%(max_digits)s, %(decimal_places)s)',
|
||||||
'ImageField': 'varchar2(100)',
|
'ImageField': 'VARCHAR2(100)',
|
||||||
'IntegerField': 'number(11)',
|
'IntegerField': 'NUMBER(11)',
|
||||||
'IPAddressField': 'char(15)',
|
'IPAddressField': 'CHAR(15)',
|
||||||
'ManyToManyField': None,
|
'ManyToManyField': None,
|
||||||
'NullBooleanField': 'number(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
|
'NullBooleanField': 'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
|
||||||
'OneToOneField': 'number(11)',
|
'OneToOneField': 'NUMBER(11)',
|
||||||
'PhoneNumberField': 'varchar2(20)',
|
'PhoneNumberField': 'VARCHAR2(20)',
|
||||||
'PositiveIntegerField': 'number(11) CHECK (%(column)s >= 1)',
|
'PositiveIntegerField': 'NUMBER(11) CHECK (%(column)s >= 1)',
|
||||||
'PositiveSmallIntegerField': 'number(11) CHECK (%(column)s >= 1)',
|
'PositiveSmallIntegerField': 'NUMBER(11) CHECK (%(column)s >= 1)',
|
||||||
'SlugField': 'varchar2(50)',
|
'SlugField': 'VARCHAR2(50)',
|
||||||
'SmallIntegerField': 'number(11)',
|
'SmallIntegerField': 'NUMBER(11)',
|
||||||
'TextField': 'clob',
|
'TextField': 'NCLOB',
|
||||||
'TimeField': 'timestamp',
|
'TimeField': 'TIMESTAMP',
|
||||||
'URLField': 'varchar2(200)',
|
'URLField': 'VARCHAR2(200)',
|
||||||
'USStateField': 'char(2)',
|
'USStateField': 'CHAR(2)',
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_DATABASE_PREFIX = 'test_'
|
TEST_DATABASE_PREFIX = 'test_'
|
||||||
PASSWORD = 'Im_a_lumberjack'
|
PASSWORD = 'Im_a_lumberjack'
|
||||||
|
OLD_DATABASE_USER = None
|
||||||
|
OLD_DATABASE_PASSWORD = None
|
||||||
|
|
||||||
def create_test_db(settings, connection, backend, verbosity=1, autoclobber=False):
|
def create_test_db(settings, connection, backend, verbosity=1, autoclobber=False):
|
||||||
if verbosity >= 1:
|
if verbosity >= 1:
|
||||||
@ -46,7 +52,7 @@ def create_test_db(settings, connection, backend, verbosity=1, autoclobber=False
|
|||||||
if autoclobber or confirm == 'yes':
|
if autoclobber or confirm == 'yes':
|
||||||
try:
|
try:
|
||||||
if verbosity >= 1:
|
if verbosity >= 1:
|
||||||
print "Destroying old test database..."
|
print "Destroying old test database..."
|
||||||
_destroy_test_db(cursor, TEST_DATABASE_NAME, verbosity)
|
_destroy_test_db(cursor, TEST_DATABASE_NAME, verbosity)
|
||||||
if verbosity >= 1:
|
if verbosity >= 1:
|
||||||
print "Creating test database..."
|
print "Creating test database..."
|
||||||
@ -66,13 +72,15 @@ def create_test_db(settings, connection, backend, verbosity=1, autoclobber=False
|
|||||||
# the side effect of initializing the test database.
|
# the side effect of initializing the test database.
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
def destroy_test_db(settings, connection, old_database_name, verbosity=1):
|
def destroy_test_db(settings, connection, backend, old_database_name, verbosity=1):
|
||||||
if verbosity >= 1:
|
if verbosity >= 1:
|
||||||
print "Destroying test database..."
|
print "Destroying test database..."
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
||||||
TEST_DATABASE_NAME = _test_database_name(settings)
|
TEST_DATABASE_NAME = _test_database_name(settings)
|
||||||
settings.DATABASE_NAME = old_database_name
|
settings.DATABASE_NAME = old_database_name
|
||||||
|
#settings.DATABASE_USER = 'old_user'
|
||||||
|
#settings.DATABASE_PASSWORD = 'old_password'
|
||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
time.sleep(1) # To avoid "database is being accessed by other users" errors.
|
time.sleep(1) # To avoid "database is being accessed by other users" errors.
|
||||||
@ -83,19 +91,18 @@ def _create_test_db(cursor, dbname, verbosity):
|
|||||||
if verbosity >= 2:
|
if verbosity >= 2:
|
||||||
print "_create_test_db(): dbname = %s" % dbname
|
print "_create_test_db(): dbname = %s" % dbname
|
||||||
statements = [
|
statements = [
|
||||||
"""create tablespace %(user)s
|
"""CREATE TABLESPACE %(user)s
|
||||||
datafile '%(user)s.dbf' size 10M autoextend on next 10M maxsize 20M
|
DATAFILE '%(user)s.dbf' SIZE 10M AUTOEXTEND ON NEXT 10M MAXSIZE 20M
|
||||||
""",
|
""",
|
||||||
"""create temporary tablespace %(user)s_temp
|
"""CREATE TEMPORARY TABLESPACE %(user)s_temp
|
||||||
tempfile '%(user)s_temp.dbf' size 10M autoextend on next 10M maxsize 20M
|
TEMPFILE '%(user)s_temp.dbf' SIZE 10M AUTOEXTEND ON NEXT 10M MAXSIZE 20M
|
||||||
""",
|
""",
|
||||||
"""create user %(user)s
|
"""CREATE USER %(user)s
|
||||||
identified by %(password)s
|
IDENTIFIED BY %(password)s
|
||||||
default tablespace %(user)s
|
DEFAULT TABLESPACE %(user)s
|
||||||
temporary tablespace %(user)s_temp
|
TEMPORARY TABLESPACE %(user)s_temp
|
||||||
""",
|
""",
|
||||||
"""grant resource to %(user)s""",
|
"""GRANT CONNECT, RESOURCE TO %(user)s""",
|
||||||
"""grant connect to %(user)s""",
|
|
||||||
]
|
]
|
||||||
_execute_statements(cursor, statements, dbname, verbosity)
|
_execute_statements(cursor, statements, dbname, verbosity)
|
||||||
|
|
||||||
@ -103,9 +110,9 @@ def _destroy_test_db(cursor, dbname, verbosity):
|
|||||||
if verbosity >= 2:
|
if verbosity >= 2:
|
||||||
print "_destroy_test_db(): dbname=%s" % dbname
|
print "_destroy_test_db(): dbname=%s" % dbname
|
||||||
statements = [
|
statements = [
|
||||||
"""drop user %(user)s cascade""",
|
'DROP USER %(user)s CASCADE',
|
||||||
"""drop tablespace %(user)s including contents and datafiles cascade constraints""",
|
'DROP TABLESPACE %(user)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS',
|
||||||
"""drop tablespace %(user)s_temp including contents and datafiles cascade constraints""",
|
'DROP TABLESPACE %(user)s_TEMP INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS',
|
||||||
]
|
]
|
||||||
_execute_statements(cursor, statements, dbname, verbosity)
|
_execute_statements(cursor, statements, dbname, verbosity)
|
||||||
|
|
||||||
@ -119,8 +126,7 @@ def _execute_statements(cursor, statements, dbname, verbosity):
|
|||||||
cursor.execute(stmt)
|
cursor.execute(stmt)
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
sys.stderr.write("Failed (%s)\n" % (err))
|
sys.stderr.write("Failed (%s)\n" % (err))
|
||||||
if required:
|
raise
|
||||||
raise
|
|
||||||
|
|
||||||
def _test_database_name(settings):
|
def _test_database_name(settings):
|
||||||
if settings.TEST_DATABASE_NAME:
|
if settings.TEST_DATABASE_NAME:
|
||||||
@ -128,4 +134,3 @@ def _test_database_name(settings):
|
|||||||
else:
|
else:
|
||||||
name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
|
name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
@ -28,16 +28,16 @@ def get_relations(cursor, table_name):
|
|||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
SELECT ta.column_id - 1, tb.table_name, tb.column_id - 1
|
SELECT ta.column_id - 1, tb.table_name, tb.column_id - 1
|
||||||
FROM user_constraints, USER_CONS_COLUMNS ca, USER_CONS_COLUMNS cb,
|
FROM user_constraints, USER_CONS_COLUMNS ca, USER_CONS_COLUMNS cb,
|
||||||
user_tab_cols ta, user_tab_cols tb
|
user_tab_cols ta, user_tab_cols tb
|
||||||
WHERE user_constraints.table_name = %s AND
|
WHERE user_constraints.table_name = %s AND
|
||||||
ta.table_name = %s AND
|
ta.table_name = %s AND
|
||||||
ta.column_name = ca.column_name AND
|
ta.column_name = ca.column_name AND
|
||||||
ca.table_name = %s AND
|
ca.table_name = %s AND
|
||||||
user_constraints.constraint_name = ca.constraint_name AND
|
user_constraints.constraint_name = ca.constraint_name AND
|
||||||
user_constraints.r_constraint_name = cb.constraint_name AND
|
user_constraints.r_constraint_name = cb.constraint_name AND
|
||||||
cb.table_name = tb.table_name AND
|
cb.table_name = tb.table_name AND
|
||||||
cb.column_name = tb.column_name AND
|
cb.column_name = tb.column_name AND
|
||||||
ca.position = cb.position""", [table_name, table_name, table_name])
|
ca.position = cb.position""", [table_name, table_name, table_name])
|
||||||
|
|
||||||
relations = {}
|
relations = {}
|
||||||
for row in cursor.fetchall():
|
for row in cursor.fetchall():
|
||||||
|
@ -67,7 +67,7 @@ def get_query_set_class(DefaultQuerySet):
|
|||||||
|
|
||||||
# so here's the logic;
|
# so here's the logic;
|
||||||
# 1. retrieve each row in turn
|
# 1. retrieve each row in turn
|
||||||
# 2. convert CLOBs
|
# 2. convert NCLOBs
|
||||||
|
|
||||||
def resolve_lobs(row):
|
def resolve_lobs(row):
|
||||||
for field in row:
|
for field in row:
|
||||||
|
@ -171,7 +171,7 @@ class _QuerySet(object):
|
|||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
full_query = None
|
full_query = None
|
||||||
select, sql, params = self._get_sql_clause()
|
select, sql, params, full_query = self._get_sql_clause()
|
||||||
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
|
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
|
||||||
|
|
||||||
fill_cache = self._select_related
|
fill_cache = self._select_related
|
||||||
@ -196,7 +196,7 @@ class _QuerySet(object):
|
|||||||
counter._offset = None
|
counter._offset = None
|
||||||
counter._limit = None
|
counter._limit = None
|
||||||
counter._select_related = False
|
counter._select_related = False
|
||||||
select, sql, params = counter._get_sql_clause()[:3]
|
select, sql, params, full_query = counter._get_sql_clause()
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
if self._distinct:
|
if self._distinct:
|
||||||
id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table),
|
id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table),
|
||||||
@ -535,7 +535,7 @@ class ValuesQuerySet(QuerySet):
|
|||||||
field_names = [f.attname for f in self.model._meta.fields]
|
field_names = [f.attname for f in self.model._meta.fields]
|
||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
select, sql, params = self._get_sql_clause()[:3]
|
select, sql, params, full_query = self._get_sql_clause()
|
||||||
select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
|
select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
|
||||||
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
|
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
|
||||||
while 1:
|
while 1:
|
||||||
@ -557,16 +557,26 @@ class DateQuerySet(QuerySet):
|
|||||||
if self._field.null:
|
if self._field.null:
|
||||||
self._where.append('%s.%s IS NOT NULL' % \
|
self._where.append('%s.%s IS NOT NULL' % \
|
||||||
(backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column)))
|
(backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column)))
|
||||||
select, sql, params = self._get_sql_clause()
|
select, sql, params, full_query = self._get_sql_clause()
|
||||||
sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \
|
table_name = backend.quote_name(self.model._meta.db_table)
|
||||||
(backend.get_date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table),
|
field_name = backend.quote_name(self._field.column)
|
||||||
backend.quote_name(self._field.column))), sql, self._order)
|
date_trunc_sql = backend.get_date_trunc_sql(self._kind,
|
||||||
cursor = connection.cursor()
|
'%s.%s' % (table_name, field_name))
|
||||||
cursor.execute(sql, params)
|
fmt = 'SELECT %s %s GROUP BY %s ORDER BY 1 %s'
|
||||||
# We have to manually run typecast_timestamp(str()) on the results, because
|
|
||||||
# MySQL doesn't automatically cast the result of date functions as datetime
|
if settings.DATABASE_ENGINE == 'oracle':
|
||||||
# objects -- MySQL returns the values as strings, instead.
|
sql = fmt % (date_trunc_sql, sql, date_trunc_sql, self._order)
|
||||||
return [typecast_timestamp(str(row[0])) for row in cursor.fetchall()]
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(sql, params)
|
||||||
|
return [row[0] for row in cursor.fetchall()]
|
||||||
|
else:
|
||||||
|
sql = fmt % (date_trunc_sql, sql, 1, self._order_by)
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(sql, params)
|
||||||
|
# We have to manually run typecast_timestamp(str()) on the results, because
|
||||||
|
# MySQL doesn't automatically cast the result of date functions as datetime
|
||||||
|
# objects -- MySQL returns the values as strings, instead.
|
||||||
|
return [typecast_timestamp(str(row[0])) for row in cursor.fetchall()]
|
||||||
|
|
||||||
def _clone(self, klass=None, **kwargs):
|
def _clone(self, klass=None, **kwargs):
|
||||||
c = super(DateQuerySet, self)._clone(klass, **kwargs)
|
c = super(DateQuerySet, self)._clone(klass, **kwargs)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user