1
1
import re
2
+ import typing as T
3
+ from contextlib import contextmanager
2
4
3
5
from clickhouse_driver import connection
4
6
from clickhouse_driver .dbapi import connection as dbapi_connection
5
7
from clickhouse_driver .dbapi import cursor , errors
8
+ from clickhouse_driver .result import IterQueryResult , ProgressQueryResult , QueryResult
6
9
from django .conf import settings
7
10
8
11
from .escape import escape_params
@@ -70,6 +73,11 @@ def send_query(self, query, query_id=None, params=None):
70
73
71
74
72
75
class Cursor (cursor .Cursor ):
76
+
77
+ # Whether to return data in columnar format. For backwards-compatibility,
78
+ # let's default to None.
79
+ columnar = None
80
+
73
81
def close (self ):
74
82
"""Push client back to connection pool"""
75
83
if self .closed :
@@ -81,12 +89,64 @@ def close(self):
81
89
def closed (self ):
82
90
return self ._state == self ._states .CURSOR_CLOSED
83
91
92
+ @property
93
+ def use_numpy (self ):
94
+ return self ._client .client_settings ["use_numpy" ]
95
+
96
+ @use_numpy .setter
97
+ def use_numpy (self , value ):
98
+ self ._client .client_settings ["use_numpy" ] = value
99
+ if value :
100
+ try :
101
+ from clickhouse_driver .numpy .result import (
102
+ NumpyIterQueryResult ,
103
+ NumpyProgressQueryResult ,
104
+ NumpyQueryResult ,
105
+ )
106
+
107
+ self ._client .query_result_cls = NumpyQueryResult
108
+ self ._client .iter_query_result_cls = NumpyIterQueryResult
109
+ self ._client .progress_query_result_cls = NumpyProgressQueryResult
110
+ except ImportError as e :
111
+ raise RuntimeError ("Extras for NumPy must be installed" ) from e
112
+ else :
113
+ self ._client .query_result_cls = QueryResult
114
+ self ._client .iter_query_result_cls = IterQueryResult
115
+ self ._client .progress_query_result_cls = ProgressQueryResult
116
+
117
+ @contextmanager
118
+ def set_query_args (
119
+ self , columnar : T .Optional [bool ] = None , use_numpy : T .Optional [bool ] = None
120
+ ):
121
+ original_use_numpy = self .use_numpy
122
+ if use_numpy is not None :
123
+ self .use_numpy = use_numpy
124
+
125
+ original_columnar = self .columnar
126
+ if columnar is not None :
127
+ self .columnar = columnar
128
+
129
+ yield self
130
+
131
+ self .use_numpy = original_use_numpy
132
+ self .columnar = original_columnar
133
+
84
134
def __del__ (self ):
85
135
# If someone forgets calling close method,
86
136
# then release connection when gc happens.
87
137
if not self .closed :
88
138
self .close ()
89
139
140
+ def _prepare (self ):
141
+ """Override clickhouse_driver.Cursor._prepare() to add columnar kwargs.
142
+
143
+ See https://github.com/jayvynl/django-clickhouse-backend/issues/119
144
+ """
145
+ execute , execute_kwargs = super ()._prepare ()
146
+ if self .columnar is not None :
147
+ execute_kwargs ["columnar" ] = self .columnar
148
+ return execute , execute_kwargs
149
+
90
150
def execute (self , operation , parameters = None ):
91
151
"""fix https://github.com/jayvynl/django-clickhouse-backend/issues/9"""
92
152
if getattr (
0 commit comments