Skip to content

Commit 0946ff4

Browse files
committed
fix(introspection): fix #57
1 parent 88137d1 commit 0946ff4

File tree

4 files changed

+28
-33
lines changed

4 files changed

+28
-33
lines changed

.github/workflows/base-test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ jobs:
1515
matrix:
1616
python-version: ["3.8", "3.9", "3.10", "3.11"]
1717
django-version: ["3.2", "4.0", "4.1", "4.2"]
18+
clickhouse-version: ["23.8", "latest"]
1819
include:
1920
- python-version: "3.7"
2021
django-version: "3.2"
@@ -34,7 +35,7 @@ jobs:
3435
- name: Lint code
3536
run: tox -e lint
3637
- name: Start clickhouse cluster
37-
run: docker compose up -d --wait
38+
run: CLICKHOUSE_VERSION=${{ matrix.clickhouse-version }} docker compose up -d --wait
3839
- name: Run test
3940
# Run tox using the version of Python in `PATH`
4041
run: tox -e py-django${{ matrix.django-version }}

clickhouse_backend/backend/introspection.py

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import re
2+
from collections import namedtuple
23

3-
from django.db.backends.base.introspection import (
4-
BaseDatabaseIntrospection,
5-
FieldInfo,
6-
TableInfo,
7-
)
4+
from django.db.backends.base.introspection import BaseDatabaseIntrospection
5+
from django.db.backends.base.introspection import FieldInfo as BaseFieldInfo
6+
from django.db.backends.base.introspection import TableInfo as BaseTableInfo
87
from django.utils.functional import cached_property
98

9+
FieldInfo = namedtuple("FieldInfo", BaseFieldInfo._fields + ("comment",))
10+
TableInfo = namedtuple("TableInfo", BaseTableInfo._fields + ("comment",))
11+
1012
constraint_pattern = re.compile(
1113
r"CONSTRAINT (`)?((?(1)(?:[^\\`]|\\.)+|\S+))(?(1)`|) (CHECK .+?),?\n"
1214
)
@@ -16,18 +18,16 @@
1618

1719

1820
class DatabaseIntrospection(BaseDatabaseIntrospection):
19-
ignored_tables = []
20-
2121
def get_field_type(self, data_type, description):
2222
if data_type.startswith("LowCardinality"): # LowCardinality(Int16)
2323
data_type = data_type[15:-1]
2424
if data_type.startswith("Nullable"): # Nullable(Int16)
2525
data_type = data_type[9:-1]
2626
if data_type.startswith("FixedString"): # FixedString(20)
2727
return "FixedStringField"
28-
elif data_type.startswith("DateTime64"):
28+
elif data_type.startswith("DateTime64"): # DateTime64(6, 'UTC')
2929
return "DateTime64Field"
30-
elif data_type.startswith("Decimal"):
30+
elif data_type.startswith("Decimal"): # Decimal(9, 3)
3131
return "DecimalField"
3232
elif data_type.startswith("Enum8"):
3333
return "Enum8Field"
@@ -50,40 +50,34 @@ def get_table_list(self, cursor):
5050
"""Return a list of table and view names in the current database."""
5151
cursor.execute(
5252
"""
53-
SELECT table_name,
54-
CASE table_type WHEN 2 THEN 'v' ELSE 't' END
55-
FROM INFORMATION_SCHEMA.TABLES
56-
WHERE table_catalog = currentDatabase()
57-
AND table_type IN (1, 2)
53+
SELECT name,
54+
if(engine LIKE '%%View', 'v', 't'),
55+
comment
56+
FROM system.tables
57+
WHERE database = currentDatabase()
58+
AND NOT is_temporary
59+
AND engine NOT LIKE 'System%%'
60+
AND has_own_data
5861
"""
5962
)
60-
return [
61-
TableInfo(*row)
62-
for row in cursor.fetchall()
63-
if row[0] not in self.ignored_tables
64-
]
63+
return [TableInfo(*row) for row in cursor.fetchall()]
6564

6665
def get_table_description(self, cursor, table_name):
67-
"""
68-
Return a description of the table.
69-
"""
70-
# Query the INFORMATION_SCHEMA.COLUMNS table.
66+
"""Return a description of the table."""
7167
cursor.execute(
7268
"""
73-
SELECT column_name, data_type, NULL, character_maximum_length,
69+
SELECT name, type, character_octet_length, character_octet_length,
7470
coalesce(numeric_precision, datetime_precision),
75-
numeric_scale, is_nullable::Bool, column_default, NULL
76-
FROM INFORMATION_SCHEMA.COLUMNS
77-
WHERE table_catalog = currentDatabase() AND table_name = %s
71+
numeric_scale, type LIKE 'Nullable(%%)', default_expression, NULL, comment
72+
FROM system.columns
73+
WHERE database = currentDatabase() AND table = %s
7874
""",
7975
[table_name],
8076
)
8177
return [FieldInfo(*line) for line in cursor.fetchall()]
8278

8379
def get_constraints(self, cursor, table_name):
84-
"""
85-
Retrieve any constraints and indexes.
86-
"""
80+
"""Retrieve any constraints and indexes."""
8781
constraints = {}
8882
# No way to get structured data, parse from SHOW CREATE TABLE.
8983
# https://clickhouse.com/docs/en/sql-reference/statements/show#show-create-table

compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
x-base-service: &base-service
2-
image: clickhouse/clickhouse-server:23.6.2.18
2+
image: clickhouse/clickhouse-server:${CLICKHOUSE_VERSION:-23.6.2.18}
33
restart: always
44
ulimits:
55
nofile:

tests/backends/clickhouse/test_introspection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def test_field_type(self):
2222
def test_table_list(self):
2323
with connection.cursor() as cursor:
2424
self.assertIn(
25-
(Person._meta.db_table, "t"),
25+
(Person._meta.db_table, "t", ""),
2626
connection.introspection.get_table_list(cursor),
2727
)
2828

0 commit comments

Comments
 (0)