Skip to content

Commit 9f0f562

Browse files
authored
Prepare for 1.5 release (#390)
2 parents bca6aab + 970a66f commit 9f0f562

File tree

6 files changed

+30
-24
lines changed

6 files changed

+30
-24
lines changed

CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ After changes made to the project, it's a good idea to run the unit tests before
1111
Download and install SQL Server [here](https://www.microsoft.com/en-us/sql-server/sql-server-downloads), or you could use docker. Change `testapp/settings.py` to match your SQL Server login username and password.
1212

1313
```
14-
docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=MyPassword42' -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-latest
14+
docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Placeholder' -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-latest
1515
```
1616
2. **Clone Django**
1717
In `mssql-django` folder.
@@ -45,4 +45,4 @@ provided by the bot. You will only need to do this once across all repos using o
4545

4646
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4747
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
48-
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
48+
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

mssql/base.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -618,11 +618,14 @@ def format_sql(self, sql, params):
618618
return sql
619619

620620
def format_group_by_params(self, query, params):
621+
# Prepare query for string formatting
622+
query = re.sub(r'%\w+', '{}', query)
623+
621624
if params:
622625
# Insert None params directly into the query
623626
if None in params:
624-
null_params = ['NULL' if param is None else '%s' for param in params]
625-
query = query % tuple(null_params)
627+
null_params = ['NULL' if param is None else '{}' for param in params]
628+
query = query.format(*null_params)
626629
params = tuple(p for p in params if p is not None)
627630
params = [(param, type(param)) for param in params]
628631
params_dict = {param: '@var%d' % i for i, param in enumerate(set(params))}
@@ -634,8 +637,7 @@ def format_group_by_params(self, query, params):
634637
datatype = self._as_sql_type(key[1], key[0])
635638
variables.append("%s %s = %%s " % (value, datatype))
636639
params.append(key[0])
637-
query = ('DECLARE %s \n' % ','.join(variables)) + (query % tuple(args))
638-
640+
query = ('DECLARE %s \n' % ','.join(variables)) + (query.format(*args))
639641
return query, params
640642

641643
def format_params(self, params):

mssql/introspection.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,22 @@ def get_table_list(self, cursor):
7777
"""
7878
Returns a list of table and view names in the current database.
7979
"""
80-
sql = """SELECT
81-
TABLE_NAME,
82-
TABLE_TYPE,
83-
CAST(ep.value AS VARCHAR) AS COMMENT
84-
FROM INFORMATION_SCHEMA.TABLES i
85-
LEFT JOIN sys.tables t ON t.name = i.TABLE_NAME
86-
LEFT JOIN sys.extended_properties ep ON t.object_id = ep.major_id
87-
AND ((ep.name = 'MS_DESCRIPTION' AND ep.minor_id = 0) OR ep.value IS NULL)
88-
AND i.TABLE_SCHEMA = %s""" % (
89-
get_schema_name())
80+
if VERSION >= (4, 2) and self.connection.features.supports_comments:
81+
sql = """SELECT
82+
TABLE_NAME,
83+
TABLE_TYPE,
84+
CAST(ep.value AS VARCHAR) AS COMMENT
85+
FROM INFORMATION_SCHEMA.TABLES i
86+
LEFT JOIN sys.tables t ON t.name = i.TABLE_NAME
87+
LEFT JOIN sys.extended_properties ep ON t.object_id = ep.major_id
88+
AND ((ep.name = 'MS_DESCRIPTION' AND ep.minor_id = 0) OR ep.value IS NULL)
89+
WHERE i.TABLE_SCHEMA = %s""" % (
90+
get_schema_name())
91+
else:
92+
sql = 'SELECT TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = %s' % (get_schema_name())
9093
cursor.execute(sql)
9194
types = {'BASE TABLE': 't', 'VIEW': 'v'}
92-
if VERSION >= (4, 2):
95+
if VERSION >= (4, 2) and self.connection.features.supports_comments:
9396
return [TableInfo(row[0], types.get(row[1]), row[2])
9497
for row in cursor.fetchall()
9598
if row[0] not in self.ignored_tables]
@@ -145,7 +148,7 @@ def get_table_description(self, cursor, table_name, identity_check=True):
145148
column.append(collation_name[0] if collation_name else '')
146149
else:
147150
column.append('')
148-
if VERSION >= (4, 2):
151+
if VERSION >= (4, 2) and self.connection.features.supports_comments:
149152
sql = """select CAST(ep.value AS VARCHAR) AS COMMENT
150153
FROM sys.columns c
151154
INNER JOIN sys.tables t ON c.object_id = t.object_id
@@ -174,8 +177,7 @@ def get_table_description(self, cursor, table_name, identity_check=True):
174177
start += 1
175178
end -= 1
176179
column[7] = default_value[start:end + 1]
177-
178-
if VERSION >= (4, 2):
180+
if VERSION >= (4, 2) and self.connection.features.supports_comments:
179181
items.append(FieldInfo(*column))
180182
else:
181183
items.append(BaseFieldInfo(*column))

mssql/schema.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,9 +388,10 @@ def _column_generated_sql(self, field):
388388
"""Return the SQL to use in a GENERATED ALWAYS clause."""
389389
expression_sql, params = field.generated_sql(self.connection)
390390
persistency_sql = "PERSISTED" if field.db_persist else ""
391-
if params:
391+
if self.connection.features.requires_literal_defaults:
392392
expression_sql = expression_sql % tuple(self.quote_value(p) for p in params)
393-
return f"AS {expression_sql} {persistency_sql}"
393+
params = ()
394+
return f"GENERATED ALWAYS AS ({expression_sql}) {persistency_sql}", params
394395

395396
def _alter_field(self, model, old_field, new_field, old_type, new_type,
396397
old_db_params, new_db_params, strict=False):
@@ -1024,6 +1025,8 @@ def add_field(self, model, field):
10241025
# It might not actually have a column behind it
10251026
if definition is None:
10261027
return
1028+
if col_type_suffix := field.db_type_suffix(connection=self.connection):
1029+
definition += f" {col_type_suffix}"
10271030
# Remove column type from definition if field is generated
10281031
if (django_version >= (5,0) and field.generated):
10291032
definition = definition[definition.find('AS'):]

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
setup(
3131
name='mssql-django',
32-
version='1.4.2',
32+
version='1.5',
3333
description='Django backend for Microsoft SQL Server',
3434
long_description=long_description,
3535
long_description_content_type='text/markdown',

testapp/settings.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,6 @@
266266
'db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_extract_lookup_name_sql_injection',
267267
'db_functions.datetime.test_extract_trunc.DateFunctionTests.test_extract_lookup_name_sql_injection',
268268
'schema.tests.SchemaTests.test_autofield_to_o2o',
269-
'schema.tests.SchemaTests.test_add_auto_field',
270269
'prefetch_related.tests.PrefetchRelatedTests.test_m2m_prefetching_iterator_with_chunks',
271270
'migrations.test_operations.OperationTests.test_create_model_with_boolean_expression_in_check_constraint',
272271
'queries.test_qs_combinators.QuerySetSetOperationTests.test_union_in_subquery_related_outerref',

0 commit comments

Comments
 (0)