django-gbase8s 2.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ __version__ = "2.2.0"
django_gbase8s/base.py ADDED
@@ -0,0 +1,288 @@
1
+ import decimal
2
+ import copy
3
+ import re
4
+ from collections import Mapping
5
+
6
+ from django.conf import settings
7
+ from django.core.exceptions import ImproperlyConfigured
8
+ from django.db.backends.base.base import BaseDatabaseWrapper
9
+ from django.db.backends.base.base import NO_DB_ALIAS
10
+ from django.utils.functional import cached_property
11
+
12
+ try:
13
+ import gbase8sdb as Database
14
+ Database.defaults.fetch_decimals = True
15
+ Database.defaults.fetch_lobs = False
16
+ except ImportError as e:
17
+ raise ImproperlyConfigured("Error loading gbase8sdb module: %s" % e)
18
+
19
+ from .client import DatabaseClient
20
+ from .creation import DatabaseCreation
21
+ from .features import DatabaseFeatures
22
+ from .introspection import DatabaseIntrospection
23
+ from .operations import DatabaseOperations
24
+ from .schema import DatabaseSchemaEditor
25
+ from .validation import DatabaseValidation
26
+ from .utils import dsn
27
+ from .utils import GBase8sParam
28
+
29
+
30
+ FORMAT_QMARK_REGEX = re.compile(r"(?<!%)%s")
31
+
32
+
33
+
34
+ class CursorWrapper(object):
35
+ def __init__(self, cursor):
36
+ self.cursor = cursor
37
+
38
+ def _format_params(self, params):
39
+ if isinstance(params, (list, tuple)):
40
+ return tuple(GBase8sParam(p) for p in params)
41
+ elif isinstance(params, dict):
42
+ return {k: GBase8sParam(v) for k, v in params.items()}
43
+ else:
44
+ raise TypeError("params must be tuple or dict")
45
+
46
+
47
+ def _param_generator(self, gbase8sparams):
48
+ if isinstance(gbase8sparams, (list, tuple)):
49
+ return tuple(p.param for p in gbase8sparams)
50
+ elif isinstance(gbase8sparams, dict):
51
+ return {k: v.param for k, v in gbase8sparams.items()}
52
+ else:
53
+ raise TypeError("params must be tuple or dict")
54
+
55
+ def _param_inputsize(self, gbase8sparams_list):
56
+ if hasattr(gbase8sparams_list[0], 'keys'): # [{k: gbase8sparams}, {}...]
57
+ sizes = {}
58
+ for params in gbase8sparams_list:
59
+ for k, value in params.items():
60
+ if value.input_size:
61
+ sizes[k] = value.input_size
62
+ else:
63
+ sizes = [None] * len(gbase8sparams_list[0])
64
+ for params in gbase8sparams_list:
65
+ for i, value in enumerate(params):
66
+ if value.input_size:
67
+ sizes[i] = value.input_size
68
+ return sizes
69
+
70
+ def _format_sql(self, sql, params):
71
+ """replace %s to ? on sql,if mapping then replace to :named """
72
+ if not params:
73
+ return FORMAT_QMARK_REGEX.sub("?", sql).replace("%%", "%")
74
+ elif isinstance(params, (tuple, list)):
75
+ sql = sql % tuple('?' * len(params))
76
+ elif isinstance(params, Mapping):
77
+ sql = sql % {name: ":{name}".format(name=name) for name in params}
78
+ else:
79
+ raise TypeError("params must be tuple or dict")
80
+ return sql
81
+
82
+ def execute(self, sql, params=None):
83
+
84
+ if params is None:
85
+ return self.cursor.execute(sql)
86
+ sql = self._format_sql(sql, params)
87
+ gbase8sparams = self._format_params(params)
88
+ params = self._param_generator(gbase8sparams)
89
+ input_sizes = self._param_inputsize([gbase8sparams])
90
+ if isinstance(input_sizes, (list, tuple)):
91
+ self.cursor.setinputsizes(*input_sizes)
92
+ elif isinstance(input_sizes, dict):
93
+ self.cursor.setinputsizes(**input_sizes)
94
+ cursor = self.cursor.execute(sql, params)
95
+ return cursor
96
+
97
+
98
+ def executemany(self, sql, params_list=()):
99
+ if not params_list:
100
+ return None
101
+ params_list = list(params_list)
102
+ sql = self._format_sql(sql, params_list[0])
103
+
104
+ new_params_list = []
105
+ gbase8sparams_list = []
106
+ for params in params_list:
107
+ gbase8sparams = self._format_params(params)
108
+ gbase8sparams_list.append(gbase8sparams)
109
+ params = self._param_generator(gbase8sparams)
110
+ new_params_list.append(params)
111
+ input_sizes = self._param_inputsize(gbase8sparams_list)
112
+ if isinstance(input_sizes, (list, tuple)):
113
+ self.cursor.setinputsizes(*input_sizes)
114
+ elif isinstance(input_sizes, dict):
115
+ self.cursor.setinputsizes(**input_sizes)
116
+ return self.cursor.executemany(sql, new_params_list)
117
+
118
+ @property
119
+ def lastrowid(self):
120
+ return self.cursor.lastrowid
121
+
122
+ def __getattr__(self, attr):
123
+ return getattr(self.cursor, attr)
124
+
125
+ def __iter__(self):
126
+ return iter(self.cursor)
127
+
128
+ def close(self):
129
+ try:
130
+ self.cursor.close()
131
+ except Database.InterfaceError:
132
+ pass
133
+
134
+
135
+
136
+ class DatabaseWrapper(BaseDatabaseWrapper):
137
+ vendor = 'gbase8s'
138
+ display_name = 'GBase 8s'
139
+ Database = Database
140
+ SchemaEditorClass = DatabaseSchemaEditor
141
+ client_class = DatabaseClient
142
+ creation_class = DatabaseCreation
143
+ features_class = DatabaseFeatures
144
+ introspection_class = DatabaseIntrospection
145
+ ops_class = DatabaseOperations
146
+ isolation_levels = [
147
+ "DIRTY READ",
148
+ "COMMITTED READ LAST COMMITTED",
149
+ "COMMITTED READ",
150
+ "CURSOR STABILITY",
151
+ "REPEATABLE READ",
152
+ ]
153
+ _limited_data_types = ("clob", "nclob", "blob")
154
+ data_types = {
155
+ 'AutoField': 'SERIAL',
156
+ 'SmallAutoField': 'SERIAL',
157
+ 'BigAutoField': 'BIGSERIAL',
158
+ 'BinaryField': 'BLOB',
159
+ 'BooleanField': 'NUMBER(1)',
160
+ 'NullBooleanField': 'NUMBER(1)',
161
+ 'CharField': 'VARCHAR(%(max_length)s)',
162
+ 'CommaSeparatedIntegerField': 'VARCHAR(%(max_length)s)',
163
+ 'DateField': 'TIMESTAMP(0)',
164
+ 'DateTimeField': 'TIMESTAMP',
165
+ 'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)',
166
+ 'DurationField': 'INTERVAL DAY(9) TO SECOND(5)',
167
+ 'FileField': 'VARCHAR(%(max_length)s)',
168
+ 'FilePathField': 'VARCHAR(%(max_length)s)',
169
+ 'FloatField': 'FLOAT',
170
+ 'IntegerField': 'INTEGER',
171
+ 'BigIntegerField': 'BIGINT',
172
+ 'IPAddressField': 'VARCHAR(15)',
173
+ 'GenericIPAddressField': 'VARCHAR(39)',
174
+ 'OneToOneField': 'INTEGER',
175
+ 'PositiveIntegerField': 'INTEGER',
176
+ 'PositiveSmallIntegerField': 'INTEGER',
177
+ 'SlugField': 'VARCHAR(%(max_length)s)',
178
+ 'SmallIntegerField': 'INTEGER',
179
+ 'TextField': 'NCLOB',
180
+ 'TimeField': 'TIMESTAMP',
181
+ "URLField": "VARCHAR(%(max_length)s)",
182
+ 'UUIDField': 'VARCHAR(32)',
183
+ }
184
+ data_type_check_constraints = {
185
+ "BooleanField": "%(qn_column)s IN (0,1)",
186
+ 'NullBooleanField': '(%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL)',
187
+ "PositiveIntegerField": "%(qn_column)s >= 0",
188
+ "PositiveSmallIntegerField": "%(qn_column)s >= 0",
189
+ }
190
+ operators = {
191
+ "exact": "= %s",
192
+ "iexact": "= UPPER(%s)",
193
+ "contains": "LIKE %s ESCAPE '\\'",
194
+ "icontains": "LIKE UPPER(%s) ESCAPE '\\'",
195
+ "gt": "> %s",
196
+ "gte": ">= %s",
197
+ "lt": "< %s",
198
+ "lte": "<= %s",
199
+ "startswith": "LIKE %s ESCAPE '\\'",
200
+ "endswith": "LIKE %s ESCAPE '\\'",
201
+ "istartswith": "LIKE UPPER(%s) ESCAPE '\\'",
202
+ "iendswith": "LIKE UPPER(%s) ESCAPE '\\'",
203
+ }
204
+ pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\', '\\'), '%%', '\%%'), '_', '\_')"
205
+ pattern_ops = {
206
+ "contains": r"LIKE '%%' || {} || '%%' ESCAPE '\'",
207
+ "icontains": r"LIKE '%%' || UPPER({}) || '%%' ESCAPE '\'",
208
+ "startswith": r"LIKE {} || '%%' ESCAPE '\'",
209
+ "istartswith": r"LIKE UPPER({}) || '%%' ESCAPE '\'",
210
+ "endswith": r"LIKE '%%' || {} ESCAPE '\'",
211
+ "iendswith": r"LIKE '%%' || UPPER({}) ESCAPE '\'",
212
+ }
213
+
214
+
215
+ def __init__(self, *args, **kwargs):
216
+ super().__init__(*args, **kwargs)
217
+ self.features = DatabaseFeatures(self)
218
+ self.ops = DatabaseOperations(self)
219
+ self.client = DatabaseClient(self)
220
+ self.creation = DatabaseCreation(self)
221
+ self.introspection = DatabaseIntrospection(self)
222
+ self.validation = DatabaseValidation(self)
223
+ self.isolation_level = 'COMMITTED READ LAST COMMITTED'
224
+
225
+ def get_database_version(self):
226
+ return (8, 8)
227
+
228
+ def get_connection_params(self):
229
+ conn_params = {
230
+ "user": self.settings_dict["USER"],
231
+ "password": self.settings_dict["PASSWORD"],
232
+ "dsn": dsn(self.settings_dict)
233
+ }
234
+ if 'ISOLATION_LEVEL' in self.settings_dict['OPTIONS']:
235
+ if self.settings_dict['OPTIONS']['ISOLATION_LEVEL'].upper() in self.isolation_levels:
236
+ self.isolation_level = self.settings_dict['OPTIONS']['ISOLATION_LEVEL']
237
+ else:
238
+ raise ImproperlyConfigured("Invalid isolation level, need {}".format(self.isolation_levels))
239
+
240
+ return conn_params
241
+
242
+ def get_new_connection(self, conn_params):
243
+ return Database.connect(**conn_params)
244
+
245
+ def init_connection_state(self):
246
+ if self.isolation_level:
247
+ with self.cursor() as cursor:
248
+ cursor.execute("SET ISOLATION TO {}".format(self.isolation_level))
249
+
250
+ def create_cursor(self, name=None):
251
+ return CursorWrapper(self.connection.cursor())
252
+
253
+ def _set_autocommit(self, autocommit):
254
+ with self.wrap_database_errors:
255
+ self.connection.autocommit = autocommit
256
+
257
+ def check_constraints(self, table_names=None):
258
+ with self.cursor() as cursor:
259
+ cursor.execute('SET CONSTRAINTS ALL IMMEDIATE')
260
+ cursor.execute('SET CONSTRAINTS ALL DEFERRED')
261
+
262
+ def enable_constraint_checking(self):
263
+ pass
264
+
265
+ def disable_constraint_checking(self):
266
+ with self.cursor() as cursor:
267
+ cursor.execute('SET CONSTRAINTS ALL DEFERRED')
268
+ return True
269
+
270
+ def is_usable(self):
271
+ try:
272
+ self.connection.ping()
273
+ except Database.Error:
274
+ return False
275
+ else:
276
+ return True
277
+
278
+ @property
279
+ def _nodb_connection(self):
280
+ settings_dict = self.settings_dict.copy()
281
+ settings_dict['NAME'] = 'sysmaster'
282
+ nodb_connection = self.__class__(
283
+ settings_dict,
284
+ alias=NO_DB_ALIAS,
285
+ )
286
+ return nodb_connection
287
+
288
+
@@ -0,0 +1,18 @@
1
+ # coding: utf-8
2
+ import shutil
3
+ from django.db.backends.base.client import BaseDatabaseClient
4
+
5
+ class DatabaseClient(BaseDatabaseClient):
6
+ executable_name = "dbaccess"
7
+ wrapper_name = "rlwrap"
8
+
9
+ @classmethod
10
+ def settings_to_cmd_args_env(cls, settings_dict, parameters):
11
+ server_name = settings_dict.get("SERVER_NAME")
12
+ db_name = settings_dict.get("NAME")
13
+ args = [cls.executable_name, db_name, '-']
14
+ wrapper_path = shutil.which(cls.wrapper_name)
15
+ if wrapper_path:
16
+ args = [wrapper_path] + args
17
+ args.extend(parameters)
18
+ return args, {'GBASEDBTSERVER': server_name}
@@ -0,0 +1,275 @@
1
+ import warnings
2
+ from django.db.models.sql import compiler
3
+ from django.db.transaction import TransactionManagementError
4
+ from django.db.utils import DatabaseError, NotSupportedError
5
+ from django.core.exceptions import EmptyResultSet
6
+ from django.db.models.expressions import (
7
+ Ref,
8
+ Exists
9
+ )
10
+ from django.utils.deprecation import (
11
+ RemovedInDjango30Warning, RemovedInDjango31Warning,
12
+ )
13
+
14
+ def as_gbase8s_for_exists(self, compiler, connection, template=None, **extra_context):
15
+ sql, params = self.as_sql(compiler, connection, template, **extra_context)
16
+ sql = 'CASE WHEN {} THEN 1 ELSE 0 END'.format(sql)
17
+ return sql, params
18
+
19
+ setattr(Exists, 'as_gbase8s', as_gbase8s_for_exists)
20
+
21
+ class SQLCompiler(compiler.SQLCompiler):
22
+
23
+ def get_group_by(self, select, order_by):
24
+ """
25
+ Returns a list of 2-tuples of form (sql, params).
26
+
27
+ The logic of what exactly the GROUP BY clause contains is hard
28
+ to describe in other words than "if it passes the test suite,
29
+ then it is correct".
30
+ """
31
+
32
+ if self.query.group_by is None:
33
+ return []
34
+ expressions = []
35
+ group_by_refs = set()
36
+ if self.query.group_by is not True:
37
+ for expr in self.query.group_by:
38
+ if not hasattr(expr, 'as_sql'):
39
+ expressions.append(self.query.resolve_ref(expr))
40
+ if isinstance(expr, Ref):
41
+ if expr.refs not in group_by_refs:
42
+ group_by_refs.add(expr.name)
43
+ expressions.append(expr.source)
44
+ else:
45
+ expressions.append(expr)
46
+ # Note that even if the group_by is set, it is only the minimal
47
+ # set to group by. So, we need to add cols in select, order_by, and
48
+ # having into the select in any case.
49
+ selected_expr_positions = {}
50
+ for ordinal, (expr, _, alias) in enumerate(select, start=1):
51
+ if alias:
52
+ selected_expr_positions[expr] = ordinal
53
+ if alias in group_by_refs:
54
+ continue
55
+ expressions.extend(expr.get_group_by_cols())
56
+ # cols = expr.get_group_by_cols()
57
+ # for col in cols:
58
+ # expressions.append(col)
59
+ for expr, (sql, params, is_ref) in order_by:
60
+ if expr.contains_aggregate:
61
+ continue
62
+ # We can skip References to select clause, as all expressions in
63
+ # the select clause are already part of the group by.
64
+ if is_ref:
65
+ continue
66
+ expressions.extend(expr.get_source_expressions())
67
+ having_group_by = self.having.get_group_by_cols() if self.having else ()
68
+ for expr in having_group_by:
69
+ expressions.append(expr)
70
+ result = []
71
+ seen = set()
72
+ expressions = self.collapse_group_by(expressions, having_group_by)
73
+
74
+ allows_group_by_select_index = (
75
+ self.connection.features.allows_group_by_select_index
76
+ )
77
+
78
+ for expr in expressions:
79
+ sql, params = self.compile(expr)
80
+ if (
81
+ allows_group_by_select_index
82
+ and selected_expr_positions.get(expr)
83
+ ):
84
+ sql, params = str(selected_expr_positions.get(expr)), ()
85
+ if (sql, tuple(params)) not in seen:
86
+ result.append((sql, params))
87
+ seen.add((sql, tuple(params)))
88
+ return result
89
+ def as_sql(self, with_limits=True, with_col_aliases=False):
90
+ """
91
+ Creates the SQL for this query. Returns the SQL string and list of
92
+ parameters.
93
+
94
+ If 'with_limits' is False, any limit/offset information is not included
95
+ in the query.
96
+ """
97
+ refcounts_before = self.query.alias_refcount.copy()
98
+ try:
99
+ extra_select, order_by, group_by = self.pre_sql_setup()
100
+ for_update_part = None
101
+ # Is a LIMIT/OFFSET clause needed?
102
+ with_limit_offset = with_limits and (self.query.high_mark is not None or self.query.low_mark)
103
+ combinator = self.query.combinator
104
+ features = self.connection.features
105
+ if combinator:
106
+ if not getattr(features, 'supports_select_{}'.format(combinator)):
107
+ raise NotSupportedError('{} is not supported on this database backend.'.format(combinator))
108
+ result, params = self.get_combinator_sql(combinator, self.query.combinator_all)
109
+ else:
110
+ distinct_fields, distinct_params = self.get_distinct()
111
+ # This must come after 'select', 'ordering', and 'distinct'
112
+ # (see docstring of get_from_clause() for details).
113
+ from_, f_params = self.get_from_clause()
114
+ where, w_params = self.compile(self.where) if self.where is not None else ("", [])
115
+ having, h_params = self.compile(self.having) if self.having is not None else ("", [])
116
+ result = ['SELECT']
117
+ params = []
118
+
119
+ if self.query.distinct:
120
+ distinct_result, distinct_params = self.connection.ops.distinct_sql(
121
+ distinct_fields,
122
+ distinct_params,
123
+ )
124
+ result += distinct_result
125
+ params += distinct_params
126
+
127
+ out_cols = []
128
+ col_idx = 1
129
+ for _, (s_sql, s_params), alias in self.select + extra_select:
130
+ if alias:
131
+ s_sql = '%s AS %s' % (s_sql, self.connection.ops.quote_name(alias))
132
+ elif with_col_aliases:
133
+ s_sql = '%s AS %s' % (s_sql, 'Col%d' % col_idx)
134
+ col_idx += 1
135
+ params.extend(s_params)
136
+ out_cols.append(s_sql)
137
+
138
+ # result.append(', '.join(out_cols))
139
+ # result.append('FROM')
140
+ # result.extend(from_)
141
+ result += [', '.join(out_cols), 'FROM', *from_]
142
+ params.extend(f_params)
143
+
144
+ if self.query.select_for_update and self.connection.features.has_select_for_update:
145
+ if self.connection.get_autocommit():
146
+ raise TransactionManagementError('select_for_update cannot be used outside of a transaction.')
147
+
148
+ if with_limit_offset and not self.connection.features.supports_select_for_update_with_limit:
149
+ raise NotSupportedError(
150
+ 'LIMIT/OFFSET is not supported with '
151
+ 'select_for_update on this database backend.'
152
+ )
153
+ nowait = self.query.select_for_update_nowait
154
+ skip_locked = self.query.select_for_update_skip_locked
155
+ of = self.query.select_for_update_of
156
+ # If it's a NOWAIT/SKIP LOCKED/OF query but the backend
157
+ # doesn't support it, raise NotSupportedError to prevent a
158
+ # possible deadlock.
159
+ if nowait and not self.connection.features.has_select_for_update_nowait:
160
+ raise NotSupportedError('NOWAIT is not supported on this database backend.')
161
+ elif skip_locked and not self.connection.features.has_select_for_update_skip_locked:
162
+ raise NotSupportedError('SKIP LOCKED is not supported on this database backend.')
163
+ elif of and not self.connection.features.has_select_for_update_of:
164
+ raise NotSupportedError('FOR UPDATE OF is not supported on this database backend.')
165
+ for_update_part = self.connection.ops.for_update_sql(
166
+ nowait=nowait,
167
+ skip_locked=skip_locked,
168
+ of=self.get_select_for_update_of_arguments(),
169
+ )
170
+
171
+ if for_update_part and self.connection.features.for_update_after_from:
172
+ result.append(for_update_part)
173
+
174
+ if where:
175
+ result.append('WHERE %s' % where)
176
+ params.extend(w_params)
177
+
178
+ grouping = []
179
+ for g_sql, g_params in group_by:
180
+ grouping.append(g_sql)
181
+ params.extend(g_params)
182
+ if grouping:
183
+ if distinct_fields:
184
+ raise NotImplementedError('annotate() + distinct(fields) is not implemented.')
185
+ order_by = order_by or self.connection.ops.force_no_ordering()
186
+ result.append('GROUP BY %s' % ', '.join(grouping))
187
+ if self._meta_ordering:
188
+ # When the deprecation ends, replace with:
189
+ # order_by = None
190
+ warnings.warn(
191
+ "%s QuerySet won't use Meta.ordering in Django 3.1. "
192
+ "Add .order_by(%s) to retain the current query." % (
193
+ self.query.model.__name__,
194
+ ', '.join(repr(f) for f in self._meta_ordering),
195
+ ),
196
+ RemovedInDjango31Warning,
197
+ stacklevel=4,
198
+ )
199
+
200
+ if having:
201
+ result.append('HAVING %s' % having)
202
+ params.extend(h_params)
203
+
204
+ if self.query.explain_query:
205
+ result.insert(0, self.connection.ops.explain_query_prefix(
206
+ self.query.explain_format,
207
+ **self.query.explain_options
208
+ ))
209
+
210
+ if order_by:
211
+ ordering = []
212
+ for _, (o_sql, o_params, _) in order_by:
213
+ ordering.append(o_sql)
214
+ params.extend(o_params)
215
+ result.append('ORDER BY %s' % ', '.join(ordering))
216
+
217
+ if with_limit_offset:
218
+ if len(result) == 1:
219
+ result = ["SELECT","* FROM (", result[0], ")"]
220
+ result.insert(1,
221
+ self.connection.ops.limit_offset_sql(
222
+ self.query.low_mark,
223
+ self.query.high_mark
224
+ )
225
+ )
226
+
227
+ if for_update_part and not self.connection.features.for_update_after_from:
228
+ result.append(for_update_part)
229
+ if self.query.subquery and extra_select:
230
+ # If the query is used as a subquery, the extra selects would
231
+ # result in more columns than the left-hand side expression is
232
+ # expecting. This can happen when a subquery uses a combination
233
+ # of order_by() and distinct(), forcing the ordering expressions
234
+ # to be selected as well. Wrap the query in another subquery
235
+ # to exclude extraneous selects.
236
+ sub_selects = []
237
+ sub_params = []
238
+ for index, (select, _, alias) in enumerate(self.select, start=1):
239
+ if not alias and with_col_aliases:
240
+ alias = 'col%d' % index
241
+ if alias:
242
+ sub_selects.append("%s.%s" % (
243
+ self.connection.ops.quote_name('subquery'),
244
+ self.connection.ops.quote_name(alias),
245
+ ))
246
+ else:
247
+ select_clone = select.relabeled_clone({select.alias: 'subquery'})
248
+ subselect, subparams = select_clone.as_sql(self, self.connection)
249
+ sub_selects.append(subselect)
250
+ sub_params.extend(subparams)
251
+ return 'SELECT %s FROM (%s) subquery' % (
252
+ ', '.join(sub_selects),
253
+ ' '.join(result),
254
+ ), tuple(sub_params + params)
255
+
256
+ return ' '.join(result), tuple(params)
257
+ finally:
258
+ # Finally do cleanup - get rid of the joins we created above.
259
+ self.query.reset_refcounts(refcounts_before)
260
+
261
+
262
+ class SQLInsertCompiler(compiler.SQLInsertCompiler, SQLCompiler):
263
+ pass
264
+
265
+
266
+ class SQLDeleteCompiler(compiler.SQLDeleteCompiler, SQLCompiler):
267
+ pass
268
+
269
+
270
+ class SQLUpdateCompiler(compiler.SQLUpdateCompiler, SQLCompiler):
271
+ pass
272
+
273
+
274
+ class SQLAggregateCompiler(compiler.SQLAggregateCompiler, SQLCompiler):
275
+ pass
@@ -0,0 +1,15 @@
1
+ from django.db.backends.base.creation import BaseDatabaseCreation
2
+
3
+ class DatabaseCreation(BaseDatabaseCreation):
4
+
5
+ def sql_table_creation_suffix(self):
6
+ """
7
+ SQL to append to the end of the test table creation statements.
8
+ """
9
+ return "WITH LOG"
10
+
11
+ def _destroy_test_db(self, test_database_name, verbosity):
12
+ with self.connection._nodb_connection.cursor() as cursor:
13
+ cursor.execute("CLOSE DATABASE")
14
+ cursor.execute("DROP DATABASE %s"
15
+ % self.connection.ops.quote_name(test_database_name))