django-gbase8s 4.0.0__tar.gz
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.
- django_gbase8s-4.0.0/LICENSE +21 -0
- django_gbase8s-4.0.0/PKG-INFO +65 -0
- django_gbase8s-4.0.0/README.md +46 -0
- django_gbase8s-4.0.0/django_gbase8s/__init__.py +1 -0
- django_gbase8s-4.0.0/django_gbase8s/base.py +297 -0
- django_gbase8s-4.0.0/django_gbase8s/client.py +17 -0
- django_gbase8s-4.0.0/django_gbase8s/compiler.py +652 -0
- django_gbase8s-4.0.0/django_gbase8s/creation.py +14 -0
- django_gbase8s-4.0.0/django_gbase8s/features.py +119 -0
- django_gbase8s-4.0.0/django_gbase8s/introspection.py +355 -0
- django_gbase8s-4.0.0/django_gbase8s/operations.py +465 -0
- django_gbase8s-4.0.0/django_gbase8s/schema.py +508 -0
- django_gbase8s-4.0.0/django_gbase8s/utils.py +86 -0
- django_gbase8s-4.0.0/django_gbase8s/validation.py +22 -0
- django_gbase8s-4.0.0/django_gbase8s.egg-info/PKG-INFO +65 -0
- django_gbase8s-4.0.0/django_gbase8s.egg-info/SOURCES.txt +19 -0
- django_gbase8s-4.0.0/django_gbase8s.egg-info/dependency_links.txt +1 -0
- django_gbase8s-4.0.0/django_gbase8s.egg-info/requires.txt +2 -0
- django_gbase8s-4.0.0/django_gbase8s.egg-info/top_level.txt +1 -0
- django_gbase8s-4.0.0/pyproject.toml +35 -0
- django_gbase8s-4.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 zhaojinlong
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: django-gbase8s
|
|
3
|
+
Version: 4.0.0
|
|
4
|
+
Summary: Django backend for GBase 8s database
|
|
5
|
+
Author: GBase 8s team
|
|
6
|
+
Project-URL: Source, https://gitee.com/GBase8s/django-gbase8s
|
|
7
|
+
Classifier: Framework :: Django
|
|
8
|
+
Classifier: Framework :: Django :: 4.0
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Requires-Python: >=3.8
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: gbase8sdb
|
|
18
|
+
Requires-Dist: django>=4.0.0
|
|
19
|
+
|
|
20
|
+
# django-gbase8s
|
|
21
|
+
|
|
22
|
+
#### 介绍
|
|
23
|
+
GBase 8s数据库的Django方言,支持GBase 8s V8.8_3.6.2版本及以上。
|
|
24
|
+
|
|
25
|
+
#### 依赖
|
|
26
|
+
- gbase8sdb
|
|
27
|
+
- django>=4.0.0
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
#### 安装教程
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
pip install django-gbase8s
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
#### 使用说明
|
|
37
|
+
|
|
38
|
+
1. 方言使用python-gbase8sdb驱动连接数据库,安装django-gbase8s时会作为依赖进行安装,您也可以手动安装:
|
|
39
|
+
```python
|
|
40
|
+
pip install gbase8sdb
|
|
41
|
+
```
|
|
42
|
+
2. python-gbase8sdb驱动连接数据库依赖GSDK 1.1版本,所以您需要联系GBase 8s技术支持或通过官方渠道获取相应版本的GSDK,并安装到您的机器上, 并设置如下环境变量:
|
|
43
|
+
```bash
|
|
44
|
+
GSDK_PATH=/path/to/gsdk
|
|
45
|
+
export LD_LIBRARY_PATH=${GSDK_PATH}/lib:$LD_LIBRARY_PATH
|
|
46
|
+
export GBASEDBTDIR=${GSDK_PATH}/lib
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
3. 在Django项目的`settings.py`文件中进行如下配置:
|
|
51
|
+
```python
|
|
52
|
+
DATABASES = {
|
|
53
|
+
"default": {
|
|
54
|
+
"ENGINE": "django_gbase8s",
|
|
55
|
+
'SERVER_NAME': 'ol_gbasedbt1210_1', # 实例的名称
|
|
56
|
+
'NAME': 'testdb', # 数据库的名称
|
|
57
|
+
'HOST': '192.168.xxx.xxx', # 数据库IP
|
|
58
|
+
'PORT': 9088, # 实例端口号
|
|
59
|
+
'DB_LOCALE': 'zh_CN.utf8', # 数据库字符集
|
|
60
|
+
'USER': 'gbasedbt', # 用户名
|
|
61
|
+
'PASSWORD': 'xxxxxxx' # 密码
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# django-gbase8s
|
|
2
|
+
|
|
3
|
+
#### 介绍
|
|
4
|
+
GBase 8s数据库的Django方言,支持GBase 8s V8.8_3.6.2版本及以上。
|
|
5
|
+
|
|
6
|
+
#### 依赖
|
|
7
|
+
- gbase8sdb
|
|
8
|
+
- django>=4.0.0
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
#### 安装教程
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
pip install django-gbase8s
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
#### 使用说明
|
|
18
|
+
|
|
19
|
+
1. 方言使用python-gbase8sdb驱动连接数据库,安装django-gbase8s时会作为依赖进行安装,您也可以手动安装:
|
|
20
|
+
```python
|
|
21
|
+
pip install gbase8sdb
|
|
22
|
+
```
|
|
23
|
+
2. python-gbase8sdb驱动连接数据库依赖GSDK 1.1版本,所以您需要联系GBase 8s技术支持或通过官方渠道获取相应版本的GSDK,并安装到您的机器上, 并设置如下环境变量:
|
|
24
|
+
```bash
|
|
25
|
+
GSDK_PATH=/path/to/gsdk
|
|
26
|
+
export LD_LIBRARY_PATH=${GSDK_PATH}/lib:$LD_LIBRARY_PATH
|
|
27
|
+
export GBASEDBTDIR=${GSDK_PATH}/lib
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
3. 在Django项目的`settings.py`文件中进行如下配置:
|
|
32
|
+
```python
|
|
33
|
+
DATABASES = {
|
|
34
|
+
"default": {
|
|
35
|
+
"ENGINE": "django_gbase8s",
|
|
36
|
+
'SERVER_NAME': 'ol_gbasedbt1210_1', # 实例的名称
|
|
37
|
+
'NAME': 'testdb', # 数据库的名称
|
|
38
|
+
'HOST': '192.168.xxx.xxx', # 数据库IP
|
|
39
|
+
'PORT': 9088, # 实例端口号
|
|
40
|
+
'DB_LOCALE': 'zh_CN.utf8', # 数据库字符集
|
|
41
|
+
'USER': 'gbasedbt', # 用户名
|
|
42
|
+
'PASSWORD': 'xxxxxxx' # 密码
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "4.0.0"
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import decimal
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
|
|
5
|
+
from django.core.exceptions import ImproperlyConfigured
|
|
6
|
+
from django.db.backends.base.base import BaseDatabaseWrapper
|
|
7
|
+
from django.db.backends.base.base import NO_DB_ALIAS
|
|
8
|
+
from django.utils.asyncio import async_unsafe
|
|
9
|
+
from django.utils.regex_helper import _lazy_re_compile
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
import gbase8sdb as Database
|
|
13
|
+
Database.defaults.fetch_decimals = True
|
|
14
|
+
except ImportError as e:
|
|
15
|
+
raise ImproperlyConfigured("Error loading gbase8sdb module: %s" % e)
|
|
16
|
+
|
|
17
|
+
from .client import DatabaseClient
|
|
18
|
+
from .creation import DatabaseCreation
|
|
19
|
+
from .features import DatabaseFeatures
|
|
20
|
+
from .introspection import DatabaseIntrospection
|
|
21
|
+
from .operations import DatabaseOperations
|
|
22
|
+
from .schema import DatabaseSchemaEditor
|
|
23
|
+
from .validation import DatabaseValidation
|
|
24
|
+
from .utils import dsn
|
|
25
|
+
from .utils import GBase8sParam
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
FORMAT_QMARK_REGEX = _lazy_re_compile(r"(?<!%)%s")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class CursorWrapper(object):
|
|
32
|
+
def __init__(self, cursor):
|
|
33
|
+
self.cursor = cursor
|
|
34
|
+
|
|
35
|
+
def _format_params(self, params):
|
|
36
|
+
if isinstance(params, (list, tuple)):
|
|
37
|
+
return tuple(GBase8sParam(p) for p in params)
|
|
38
|
+
elif isinstance(params, dict):
|
|
39
|
+
return {k: GBase8sParam(v) for k, v in params.items()}
|
|
40
|
+
else:
|
|
41
|
+
raise TypeError("params must be tuple or dict")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _param_generator(self, gbase8sparams):
|
|
45
|
+
if isinstance(gbase8sparams, (list, tuple)):
|
|
46
|
+
return tuple(p.param for p in gbase8sparams)
|
|
47
|
+
elif isinstance(gbase8sparams, dict):
|
|
48
|
+
return {k: v.param for k, v in gbase8sparams.items()}
|
|
49
|
+
else:
|
|
50
|
+
raise TypeError("params must be tuple or dict")
|
|
51
|
+
|
|
52
|
+
def _param_inputsize(self, gbase8sparams_list):
|
|
53
|
+
if hasattr(gbase8sparams_list[0], 'keys'): # [{k: gbase8sparams}, {}...]
|
|
54
|
+
sizes = {}
|
|
55
|
+
for params in gbase8sparams_list:
|
|
56
|
+
for k, value in params.items():
|
|
57
|
+
if value.input_size:
|
|
58
|
+
sizes[k] = value.input_size
|
|
59
|
+
else:
|
|
60
|
+
sizes = [None] * len(gbase8sparams_list[0])
|
|
61
|
+
for params in gbase8sparams_list:
|
|
62
|
+
for i, value in enumerate(params):
|
|
63
|
+
if value.input_size:
|
|
64
|
+
sizes[i] = value.input_size
|
|
65
|
+
return sizes
|
|
66
|
+
|
|
67
|
+
def _format_sql(self, sql, params):
|
|
68
|
+
if not params:
|
|
69
|
+
return FORMAT_QMARK_REGEX.sub("?", sql).replace("%%", "%")
|
|
70
|
+
elif isinstance(params, (tuple, list)):
|
|
71
|
+
sql = sql % tuple('?' * len(params))
|
|
72
|
+
elif isinstance(params, Mapping):
|
|
73
|
+
sql = sql % {name: ":{name}".format(name=name) for name in params}
|
|
74
|
+
else:
|
|
75
|
+
raise TypeError("params must be tuple or dict")
|
|
76
|
+
return sql
|
|
77
|
+
|
|
78
|
+
def execute(self, sql, params=None):
|
|
79
|
+
if params is None:
|
|
80
|
+
return self.cursor.execute(sql)
|
|
81
|
+
sql = self._format_sql(sql, params)
|
|
82
|
+
gbase8sparams = self._format_params(params)
|
|
83
|
+
params = self._param_generator(gbase8sparams)
|
|
84
|
+
input_sizes = self._param_inputsize([gbase8sparams])
|
|
85
|
+
if isinstance(input_sizes, (list, tuple)):
|
|
86
|
+
self.cursor.setinputsizes(*input_sizes)
|
|
87
|
+
elif isinstance(input_sizes, dict):
|
|
88
|
+
self.cursor.setinputsizes(**input_sizes)
|
|
89
|
+
cursor = self.cursor.execute(sql, params)
|
|
90
|
+
return cursor
|
|
91
|
+
|
|
92
|
+
def executemany(self, sql, params_list=()):
|
|
93
|
+
if not params_list:
|
|
94
|
+
return None
|
|
95
|
+
params_list = list(params_list)
|
|
96
|
+
sql = self._format_sql(sql, params_list[0])
|
|
97
|
+
|
|
98
|
+
new_params_list = []
|
|
99
|
+
gbase8sparams_list = []
|
|
100
|
+
for params in params_list:
|
|
101
|
+
gbase8sparams = self._format_params(params)
|
|
102
|
+
gbase8sparams_list.append(gbase8sparams)
|
|
103
|
+
params = self._param_generator(gbase8sparams)
|
|
104
|
+
new_params_list.append(params)
|
|
105
|
+
input_sizes = self._param_inputsize(gbase8sparams_list)
|
|
106
|
+
if isinstance(input_sizes, (list, tuple)):
|
|
107
|
+
self.cursor.setinputsizes(*input_sizes)
|
|
108
|
+
elif isinstance(input_sizes, dict):
|
|
109
|
+
self.cursor.setinputsizes(**input_sizes)
|
|
110
|
+
return self.cursor.executemany(sql, new_params_list)
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def lastrowid(self):
|
|
114
|
+
return self.cursor.lastrowid
|
|
115
|
+
|
|
116
|
+
def __getattr__(self, attr):
|
|
117
|
+
return getattr(self.cursor, attr)
|
|
118
|
+
|
|
119
|
+
def __iter__(self):
|
|
120
|
+
return iter(self.cursor)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class DatabaseWrapper(BaseDatabaseWrapper):
|
|
124
|
+
vendor = 'gbase8s'
|
|
125
|
+
display_name = "GBase 8s"
|
|
126
|
+
Database = Database
|
|
127
|
+
isolation_levels = [
|
|
128
|
+
"DIRTY READ",
|
|
129
|
+
"COMMITTED READ LAST COMMITTED",
|
|
130
|
+
"COMMITTED READ",
|
|
131
|
+
"CURSOR STABILITY",
|
|
132
|
+
"REPEATABLE READ",
|
|
133
|
+
]
|
|
134
|
+
_limited_data_types = ("clob", "nclob", "blob")
|
|
135
|
+
data_types = {
|
|
136
|
+
'AutoField': 'SERIAL',
|
|
137
|
+
'SmallAutoField': 'SERIAL',
|
|
138
|
+
'BigAutoField': 'BIGSERIAL',
|
|
139
|
+
'BinaryField': 'BLOB',
|
|
140
|
+
'BooleanField': 'NUMBER(1)',
|
|
141
|
+
'CharField': 'VARCHAR(%(max_length)s)',
|
|
142
|
+
'DateField': 'TIMESTAMP(0)',
|
|
143
|
+
'DateTimeField': 'TIMESTAMP',
|
|
144
|
+
'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)',
|
|
145
|
+
'DurationField': 'INTERVAL DAY(9) TO SECOND(5)',
|
|
146
|
+
'FileField': 'VARCHAR(%(max_length)s)',
|
|
147
|
+
'FilePathField': 'VARCHAR(%(max_length)s)',
|
|
148
|
+
'FloatField': 'FLOAT',
|
|
149
|
+
'IntegerField': 'INTEGER',
|
|
150
|
+
"JSONField": 'VARCHAR(32765)',
|
|
151
|
+
'BigIntegerField': 'BIGINT',
|
|
152
|
+
'IPAddressField': 'VARCHAR(15)',
|
|
153
|
+
'GenericIPAddressField': 'VARCHAR(39)',
|
|
154
|
+
'OneToOneField': 'INTEGER',
|
|
155
|
+
'PositiveIntegerField': 'INTEGER',
|
|
156
|
+
'PositiveSmallIntegerField': 'INTEGER',
|
|
157
|
+
"PositiveBigIntegerField": "BIGINT",
|
|
158
|
+
'SlugField': 'VARCHAR(%(max_length)s)',
|
|
159
|
+
'SmallIntegerField': 'INTEGER',
|
|
160
|
+
'TextField': 'NCLOB',
|
|
161
|
+
'TimeField': 'TIMESTAMP',
|
|
162
|
+
"URLField": "VARCHAR(%(max_length)s)",
|
|
163
|
+
'UUIDField': 'VARCHAR(32)',
|
|
164
|
+
}
|
|
165
|
+
data_type_check_constraints = {
|
|
166
|
+
"BooleanField": "%(qn_column)s IN (0,1)",
|
|
167
|
+
"JSONField": "%(qn_column)s IS JSON",
|
|
168
|
+
"PositiveBigIntegerField": "%(qn_column)s >= 0",
|
|
169
|
+
"PositiveIntegerField": "%(qn_column)s >= 0",
|
|
170
|
+
"PositiveSmallIntegerField": "%(qn_column)s >= 0",
|
|
171
|
+
}
|
|
172
|
+
operators = {
|
|
173
|
+
"exact": "= %s",
|
|
174
|
+
"iexact": "= UPPER(%s)",
|
|
175
|
+
"contains": "LIKE %s ESCAPE '\\'",
|
|
176
|
+
"icontains": "LIKE UPPER(%s) ESCAPE '\\'",
|
|
177
|
+
"gt": "> %s",
|
|
178
|
+
"gte": ">= %s",
|
|
179
|
+
"lt": "< %s",
|
|
180
|
+
"lte": "<= %s",
|
|
181
|
+
"startswith": "LIKE %s ESCAPE '\\'",
|
|
182
|
+
"endswith": "LIKE %s ESCAPE '\\'",
|
|
183
|
+
"istartswith": "LIKE UPPER(%s) ESCAPE '\\'",
|
|
184
|
+
"iendswith": "LIKE UPPER(%s) ESCAPE '\\'",
|
|
185
|
+
}
|
|
186
|
+
pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\', '\\'), '%%', '\%%'), '_', '\_')"
|
|
187
|
+
pattern_ops = {
|
|
188
|
+
"contains": r"LIKE '%%' || {} || '%%' ESCAPE '\'",
|
|
189
|
+
"icontains": r"LIKE '%%' || UPPER({}) || '%%' ESCAPE '\'",
|
|
190
|
+
"startswith": r"LIKE {} || '%%' ESCAPE '\'",
|
|
191
|
+
"istartswith": r"LIKE UPPER({}) || '%%' ESCAPE '\'",
|
|
192
|
+
"endswith": r"LIKE '%%' || {} ESCAPE '\'",
|
|
193
|
+
"iendswith": r"LIKE '%%' || UPPER({}) ESCAPE '\'",
|
|
194
|
+
}
|
|
195
|
+
client_class = DatabaseClient
|
|
196
|
+
creation_class = DatabaseCreation
|
|
197
|
+
features_class = DatabaseFeatures
|
|
198
|
+
introspection_class = DatabaseIntrospection
|
|
199
|
+
ops_class = DatabaseOperations
|
|
200
|
+
SchemaEditorClass = DatabaseSchemaEditor
|
|
201
|
+
validation_class = DatabaseValidation
|
|
202
|
+
|
|
203
|
+
def __init__(self, *args, **kwargs):
|
|
204
|
+
super().__init__(*args, **kwargs)
|
|
205
|
+
self.isolation_level = 'COMMITTED READ LAST COMMITTED'
|
|
206
|
+
|
|
207
|
+
def get_database_version(self):
|
|
208
|
+
return (8, 8)
|
|
209
|
+
|
|
210
|
+
def get_connection_params(self):
|
|
211
|
+
conn_params = {
|
|
212
|
+
"user": self.settings_dict["USER"],
|
|
213
|
+
"password": self.settings_dict["PASSWORD"],
|
|
214
|
+
"dsn": dsn(self.settings_dict)
|
|
215
|
+
}
|
|
216
|
+
if 'ISOLATION_LEVEL' in self.settings_dict['OPTIONS']:
|
|
217
|
+
if self.settings_dict['OPTIONS']['ISOLATION_LEVEL'].upper() in self.isolation_levels:
|
|
218
|
+
self.isolation_level = self.settings_dict['OPTIONS']['ISOLATION_LEVEL']
|
|
219
|
+
else:
|
|
220
|
+
raise ImproperlyConfigured(f"Invalid isolation level, need {self.isolation_levels}")
|
|
221
|
+
|
|
222
|
+
return conn_params
|
|
223
|
+
|
|
224
|
+
@async_unsafe
|
|
225
|
+
def get_new_connection(self, conn_params):
|
|
226
|
+
conn = Database.connect(**conn_params)
|
|
227
|
+
cursor = conn.cursor()
|
|
228
|
+
cursor.execute("select 1 from sysprocedures where procname='django_isoyear_extract'")
|
|
229
|
+
if not cursor.fetchone():
|
|
230
|
+
cursor.execute("""
|
|
231
|
+
create or replace function django_isoyear_extract(d in timestamp)
|
|
232
|
+
return int as
|
|
233
|
+
v_year int;
|
|
234
|
+
begin
|
|
235
|
+
SELECT
|
|
236
|
+
CASE
|
|
237
|
+
WHEN WEEKDAY(d) = 0 THEN YEAR(d -3 UNITS DAY)
|
|
238
|
+
ELSE YEAR(d + (4 - WEEKDAY(d)) UNITS DAY)
|
|
239
|
+
END AS iso_year
|
|
240
|
+
INTO v_year
|
|
241
|
+
FROM DUAL;
|
|
242
|
+
return v_year;
|
|
243
|
+
end django_isoyear_extract;
|
|
244
|
+
""")
|
|
245
|
+
cursor.close()
|
|
246
|
+
|
|
247
|
+
return conn
|
|
248
|
+
|
|
249
|
+
def init_connection_state(self):
|
|
250
|
+
# super().init_connection_state()
|
|
251
|
+
if self.isolation_level:
|
|
252
|
+
with self.cursor() as cursor:
|
|
253
|
+
cursor.execute(f"SET ISOLATION TO {self.isolation_level}")
|
|
254
|
+
|
|
255
|
+
def create_cursor(self, name=None):
|
|
256
|
+
return CursorWrapper(self.connection.cursor())
|
|
257
|
+
|
|
258
|
+
def _set_autocommit(self, autocommit):
|
|
259
|
+
with self.wrap_database_errors:
|
|
260
|
+
self.connection.autocommit = autocommit
|
|
261
|
+
|
|
262
|
+
def disable_constraint_checking(self):
|
|
263
|
+
with self.cursor() as cursor:
|
|
264
|
+
cursor.execute("SET CONSTRAINTS ALL DEFERRED")
|
|
265
|
+
return True
|
|
266
|
+
|
|
267
|
+
def enable_constraint_checking(self):
|
|
268
|
+
pass
|
|
269
|
+
|
|
270
|
+
def check_constraints(self, table_names=None):
|
|
271
|
+
"""
|
|
272
|
+
To check constraints, we set constraints to immediate. Then, when, we're done we must ensure they
|
|
273
|
+
are returned to deferred.
|
|
274
|
+
"""
|
|
275
|
+
with self.cursor() as cursor:
|
|
276
|
+
cursor.execute('SET CONSTRAINTS ALL IMMEDIATE')
|
|
277
|
+
cursor.execute('SET CONSTRAINTS ALL DEFERRED')
|
|
278
|
+
|
|
279
|
+
def is_usable(self):
|
|
280
|
+
try:
|
|
281
|
+
self.connection.ping()
|
|
282
|
+
except Database.Error:
|
|
283
|
+
return False
|
|
284
|
+
else:
|
|
285
|
+
return True
|
|
286
|
+
|
|
287
|
+
@contextmanager
|
|
288
|
+
def _nodb_cursor(self):
|
|
289
|
+
conn = self.__class__({**self.settings_dict, "NAME": "sysmaster"}, alias=NO_DB_ALIAS)
|
|
290
|
+
try:
|
|
291
|
+
with conn.cursor() as cursor:
|
|
292
|
+
cursor.execute("CLOSE DATABASE")
|
|
293
|
+
yield cursor
|
|
294
|
+
finally:
|
|
295
|
+
conn.close()
|
|
296
|
+
|
|
297
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
from django.db.backends.base.client import BaseDatabaseClient
|
|
3
|
+
|
|
4
|
+
class DatabaseClient(BaseDatabaseClient):
|
|
5
|
+
executable_name = "dbaccess"
|
|
6
|
+
wrapper_name = "rlwrap"
|
|
7
|
+
|
|
8
|
+
@classmethod
|
|
9
|
+
def settings_to_cmd_args_env(cls, settings_dict, parameters):
|
|
10
|
+
server_name = settings_dict.get("SERVER_NAME")
|
|
11
|
+
db_name = settings_dict.get("NAME")
|
|
12
|
+
args = [cls.executable_name, db_name, '-']
|
|
13
|
+
wrapper_path = shutil.which(cls.wrapper_name)
|
|
14
|
+
if wrapper_path:
|
|
15
|
+
args = [wrapper_path, *args]
|
|
16
|
+
args.extend(parameters)
|
|
17
|
+
return args, {'GBASEDBTSERVER': server_name}
|