1 from django
.db
.backends
import BaseDatabaseOperations
4 class DatabaseOperations(BaseDatabaseOperations
):
5 def __init__(self
, connection
):
6 super(DatabaseOperations
, self
).__init
__(connection
)
8 def date_extract_sql(self
, lookup_type
, field_name
):
9 # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
10 if lookup_type
== 'week_day':
11 # For consistency across backends, we return Sunday=1, Saturday=7.
12 return "EXTRACT('dow' FROM %s) + 1" % field_name
14 return "EXTRACT('%s' FROM %s)" % (lookup_type
, field_name
)
16 def date_interval_sql(self
, sql
, connector
, timedelta
):
18 implements the interval functionality for expressions
20 (datefield + interval '3 days 200 seconds 5 microseconds')
24 modifiers
.append(u
'%s days' % timedelta
.days
)
26 modifiers
.append(u
'%s seconds' % timedelta
.seconds
)
27 if timedelta
.microseconds
:
28 modifiers
.append(u
'%s microseconds' % timedelta
.microseconds
)
29 mods
= u
' '.join(modifiers
)
30 conn
= u
' %s ' % connector
31 return u
'(%s)' % conn
.join([sql
, u
'interval \'%s\'' % mods
])
33 def date_trunc_sql(self
, lookup_type
, field_name
):
34 # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
35 return "DATE_TRUNC('%s', %s)" % (lookup_type
, field_name
)
37 def deferrable_sql(self
):
38 return " DEFERRABLE INITIALLY DEFERRED"
40 def lookup_cast(self
, lookup_type
):
43 # Cast text lookups to text to allow things like filter(x__contains=4)
44 if lookup_type
in ('iexact', 'contains', 'icontains', 'startswith',
45 'istartswith', 'endswith', 'iendswith'):
48 # Use UPPER(x) for case-insensitive lookups; it's faster.
49 if lookup_type
in ('iexact', 'icontains', 'istartswith', 'iendswith'):
50 lookup
= 'UPPER(%s)' % lookup
54 def field_cast_sql(self
, db_type
):
59 def last_insert_id(self
, cursor
, table_name
, pk_name
):
60 # Use pg_get_serial_sequence to get the underlying sequence name
61 # from the table name and column name (available since PostgreSQL 8)
62 cursor
.execute("SELECT CURRVAL(pg_get_serial_sequence('%s','%s'))" % (
63 self
.quote_name(table_name
), pk_name
))
64 return cursor
.fetchone()[0]
66 def no_limit_value(self
):
69 def quote_name(self
, name
):
70 if name
.startswith('"') and name
.endswith('"'):
71 return name
# Quoting once is enough.
74 def set_time_zone_sql(self
):
75 return "SET TIME ZONE %s"
77 def sql_flush(self
, style
, tables
, sequences
):
79 # Perform a single SQL 'TRUNCATE x, y, z...;' statement. It allows
80 # us to truncate tables referenced by a foreign key in any other
83 (style
.SQL_KEYWORD('TRUNCATE'),
84 style
.SQL_FIELD(', '.join([self
.quote_name(table
) for table
in tables
]))
87 # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
88 # to reset sequence indices
89 for sequence_info
in sequences
:
90 table_name
= sequence_info
['table']
91 column_name
= sequence_info
['column']
92 if not (column_name
and len(column_name
) > 0):
93 # This will be the case if it's an m2m using an autogenerated
94 # intermediate table (see BaseDatabaseIntrospection.sequence_list)
96 sql
.append("%s setval(pg_get_serial_sequence('%s','%s'), 1, false);" % \
97 (style
.SQL_KEYWORD('SELECT'),
98 style
.SQL_TABLE(self
.quote_name(table_name
)),
99 style
.SQL_FIELD(column_name
))
105 def tablespace_sql(self
, tablespace
, inline
=False):
107 return "USING INDEX TABLESPACE %s" % self
.quote_name(tablespace
)
109 return "TABLESPACE %s" % self
.quote_name(tablespace
)
111 def sequence_reset_sql(self
, style
, model_list
):
112 from django
.db
import models
115 for model
in model_list
:
116 # Use `coalesce` to set the sequence for each model to the max pk value if there are records,
117 # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
118 # if there are records (as the max pk value is already in use), otherwise set it to false.
119 # Use pg_get_serial_sequence to get the underlying sequence name from the table name
120 # and column name (available since PostgreSQL 8)
122 for f
in model
._meta
.local_fields
:
123 if isinstance(f
, models
.AutoField
):
124 output
.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
125 (style
.SQL_KEYWORD('SELECT'),
126 style
.SQL_TABLE(qn(model
._meta
.db_table
)),
127 style
.SQL_FIELD(f
.column
),
128 style
.SQL_FIELD(qn(f
.column
)),
129 style
.SQL_FIELD(qn(f
.column
)),
130 style
.SQL_KEYWORD('IS NOT'),
131 style
.SQL_KEYWORD('FROM'),
132 style
.SQL_TABLE(qn(model
._meta
.db_table
))))
133 break # Only one AutoField is allowed per model, so don't bother continuing.
134 for f
in model
._meta
.many_to_many
:
135 if not f
.rel
.through
:
136 output
.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
137 (style
.SQL_KEYWORD('SELECT'),
138 style
.SQL_TABLE(qn(f
.m2m_db_table())),
139 style
.SQL_FIELD('id'),
140 style
.SQL_FIELD(qn('id')),
141 style
.SQL_FIELD(qn('id')),
142 style
.SQL_KEYWORD('IS NOT'),
143 style
.SQL_KEYWORD('FROM'),
144 style
.SQL_TABLE(qn(f
.m2m_db_table()))))
147 def savepoint_create_sql(self
, sid
):
148 return "SAVEPOINT %s" % sid
150 def savepoint_commit_sql(self
, sid
):
151 return "RELEASE SAVEPOINT %s" % sid
153 def savepoint_rollback_sql(self
, sid
):
154 return "ROLLBACK TO SAVEPOINT %s" % sid
156 def prep_for_iexact_query(self
, x
):
159 def check_aggregate_support(self
, aggregate
):
160 """Check that the backend fully supports the provided aggregate.
162 The implementation of population statistics (STDDEV_POP and VAR_POP)
163 under Postgres 8.2 - 8.2.4 is known to be faulty. Raise
164 NotImplementedError if this is the database in use.
166 if aggregate
.sql_function
in ('STDDEV_POP', 'VAR_POP'):
167 pg_version
= self
.connection
.pg_version
168 if pg_version
>= 80200 and pg_version
<= 80204:
169 raise NotImplementedError('PostgreSQL 8.2 to 8.2.4 is known to have a faulty implementation of %s. Please upgrade your version of PostgreSQL.' % aggregate
.sql_function
)
171 def max_name_length(self
):
173 Returns the maximum length of an identifier.
175 Note that the maximum length of an identifier is 63 by default, but can
176 be changed by recompiling PostgreSQL after editing the NAMEDATALEN
177 macro in src/include/pg_config_manual.h .
179 This implementation simply returns 63, but can easily be overridden by a
180 custom database backend that inherits most of its behavior from this one.
185 def distinct_sql(self
, fields
):
187 return 'DISTINCT ON (%s)' % ', '.join(fields
)
191 def last_executed_query(self
, cursor
, sql
, params
):
192 # http://initd.org/psycopg/docs/cursor.html#cursor.query
193 # The query attribute is a Psycopg extension to the DB API 2.0.
196 def return_insert_id(self
):
197 return "RETURNING %s", ()
199 def bulk_insert_sql(self
, fields
, num_values
):
200 items_sql
= "(%s)" % ", ".join(["%s"] * len(fields
))
201 return "VALUES " + ", ".join([items_sql
] * num_values
)