pycubrid 0.5.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.
- pycubrid-0.5.0/LICENSE +21 -0
- pycubrid-0.5.0/PKG-INFO +273 -0
- pycubrid-0.5.0/README.md +243 -0
- pycubrid-0.5.0/pycubrid/__init__.py +113 -0
- pycubrid-0.5.0/pycubrid/connection.py +271 -0
- pycubrid-0.5.0/pycubrid/constants.py +447 -0
- pycubrid-0.5.0/pycubrid/cursor.py +354 -0
- pycubrid-0.5.0/pycubrid/exceptions.py +139 -0
- pycubrid-0.5.0/pycubrid/lob.py +56 -0
- pycubrid-0.5.0/pycubrid/packet.py +291 -0
- pycubrid-0.5.0/pycubrid/protocol.py +947 -0
- pycubrid-0.5.0/pycubrid/py.typed +0 -0
- pycubrid-0.5.0/pycubrid/types.py +182 -0
- pycubrid-0.5.0/pycubrid.egg-info/PKG-INFO +273 -0
- pycubrid-0.5.0/pycubrid.egg-info/SOURCES.txt +28 -0
- pycubrid-0.5.0/pycubrid.egg-info/dependency_links.txt +1 -0
- pycubrid-0.5.0/pycubrid.egg-info/requires.txt +5 -0
- pycubrid-0.5.0/pycubrid.egg-info/top_level.txt +1 -0
- pycubrid-0.5.0/pyproject.toml +55 -0
- pycubrid-0.5.0/setup.cfg +4 -0
- pycubrid-0.5.0/tests/test_connection.py +473 -0
- pycubrid-0.5.0/tests/test_constants.py +448 -0
- pycubrid-0.5.0/tests/test_cursor.py +602 -0
- pycubrid-0.5.0/tests/test_exceptions.py +201 -0
- pycubrid-0.5.0/tests/test_integration.py +456 -0
- pycubrid-0.5.0/tests/test_lob.py +127 -0
- pycubrid-0.5.0/tests/test_packet.py +396 -0
- pycubrid-0.5.0/tests/test_pep249.py +84 -0
- pycubrid-0.5.0/tests/test_protocol.py +1533 -0
- pycubrid-0.5.0/tests/test_types.py +226 -0
pycubrid-0.5.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Yeongseon Choe
|
|
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.
|
pycubrid-0.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pycubrid
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Pure Python DB-API 2.0 driver for CUBRID database
|
|
5
|
+
Author-email: Yeongseon Choe <yeongseon.choe@gmail.com>, Gyeongjun Paik <paikend@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/cubrid-labs/pycubrid
|
|
8
|
+
Project-URL: Repository, https://github.com/cubrid-labs/pycubrid
|
|
9
|
+
Project-URL: Documentation, https://github.com/cubrid-labs/pycubrid/tree/main/docs
|
|
10
|
+
Keywords: CUBRID,database,driver,DB-API,PEP 249
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Database
|
|
21
|
+
Classifier: Topic :: Database :: Front-Ends
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
27
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# pycubrid
|
|
32
|
+
|
|
33
|
+
**Pure Python DB-API 2.0 driver for the CUBRID database** — no C extensions, no compilation, PEP 249 compliant database connector.
|
|
34
|
+
|
|
35
|
+
[🇰🇷 한국어](docs/README.ko.md) · [🇺🇸 English](README.md) · [🇨🇳 中文](docs/README.zh.md) · [🇮🇳 हिन्दी](docs/README.hi.md) · [🇩🇪 Deutsch](docs/README.de.md) · [🇷🇺 Русский](docs/README.ru.md)
|
|
36
|
+
|
|
37
|
+
<!-- BADGES:START -->
|
|
38
|
+
[](https://pypi.org/project/pycubrid)
|
|
39
|
+
[](https://www.python.org)
|
|
40
|
+
[](https://github.com/cubrid-labs/pycubrid/actions/workflows/ci.yml)
|
|
41
|
+
[](https://github.com/cubrid-labs/pycubrid/blob/main/LICENSE)
|
|
42
|
+
[](https://github.com/cubrid-labs/pycubrid)
|
|
43
|
+
[](https://www.python.org/downloads/)
|
|
44
|
+
[](docs/DEVELOPMENT.md#code-coverage)
|
|
45
|
+
<!-- BADGES:END -->
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Why pycubrid?
|
|
50
|
+
|
|
51
|
+
CUBRID is a high-performance open-source relational database, widely adopted in
|
|
52
|
+
Korean public-sector and enterprise applications. The existing C-extension driver
|
|
53
|
+
(`CUBRIDdb`) had build dependencies and platform compatibility issues.
|
|
54
|
+
|
|
55
|
+
**pycubrid** solves these problems:
|
|
56
|
+
|
|
57
|
+
- **Pure Python implementation** — no C build dependencies, install with `pip install` only
|
|
58
|
+
- **Full PEP 249 (DB-API 2.0) compliance** — standard exception hierarchy, type objects, cursor interface
|
|
59
|
+
- **471 offline tests** with **99%+ code coverage** — no database required to run them
|
|
60
|
+
- **PEP 561 typed package** — `py.typed` marker for modern IDE and static analysis support
|
|
61
|
+
- **Direct CUBRID CAS protocol** implementation — no additional middleware required
|
|
62
|
+
- **LOB (CLOB/BLOB) support** — handle large text and binary data
|
|
63
|
+
|
|
64
|
+
## Requirements
|
|
65
|
+
|
|
66
|
+
- Python 3.10+
|
|
67
|
+
- CUBRID database server 10.2+
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pip install pycubrid
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Quick Start
|
|
76
|
+
|
|
77
|
+
### Basic Connection
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import pycubrid
|
|
81
|
+
|
|
82
|
+
conn = pycubrid.connect(
|
|
83
|
+
host="localhost",
|
|
84
|
+
port=33000,
|
|
85
|
+
database="testdb",
|
|
86
|
+
user="dba",
|
|
87
|
+
password="",
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
cur = conn.cursor()
|
|
91
|
+
cur.execute("SELECT 1 + 1")
|
|
92
|
+
print(cur.fetchone()) # (2,)
|
|
93
|
+
|
|
94
|
+
cur.close()
|
|
95
|
+
conn.close()
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Context Manager
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
import pycubrid
|
|
102
|
+
|
|
103
|
+
with pycubrid.connect(host="localhost", port=33000, database="testdb", user="dba") as conn:
|
|
104
|
+
with conn.cursor() as cur:
|
|
105
|
+
cur.execute("CREATE TABLE IF NOT EXISTS cookbook_users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100))")
|
|
106
|
+
cur.execute("INSERT INTO cookbook_users (name) VALUES (?)", ("Alice",))
|
|
107
|
+
conn.commit()
|
|
108
|
+
|
|
109
|
+
cur.execute("SELECT * FROM cookbook_users")
|
|
110
|
+
for row in cur:
|
|
111
|
+
print(row)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Parameter Binding
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
# qmark style (question marks)
|
|
118
|
+
cur.execute("SELECT * FROM users WHERE name = ? AND age > ?", ("Alice", 25))
|
|
119
|
+
|
|
120
|
+
# Batch insert with executemany
|
|
121
|
+
data = [("Alice", 30), ("Bob", 25), ("Charlie", 35)]
|
|
122
|
+
cur.executemany("INSERT INTO users (name, age) VALUES (?, ?)", data)
|
|
123
|
+
conn.commit()
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Prepared Statements
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
cur.prepare("SELECT * FROM users WHERE department = ?")
|
|
130
|
+
cur.execute(None, ("Engineering",))
|
|
131
|
+
engineers = cur.fetchall()
|
|
132
|
+
|
|
133
|
+
cur.execute(None, ("Marketing",))
|
|
134
|
+
marketers = cur.fetchall()
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## PEP 249 Compliance
|
|
138
|
+
|
|
139
|
+
| Attribute | Value |
|
|
140
|
+
|---|---|
|
|
141
|
+
| `apilevel` | `"2.0"` |
|
|
142
|
+
| `threadsafety` | `1` (connections cannot be shared between threads) |
|
|
143
|
+
| `paramstyle` | `"qmark"` (positional parameters `?`) |
|
|
144
|
+
|
|
145
|
+
- Full standard exception hierarchy: `Warning`, `Error`, `InterfaceError`, `DatabaseError`, `OperationalError`, `IntegrityError`, `InternalError`, `ProgrammingError`, `NotSupportedError`
|
|
146
|
+
- Standard type objects: `STRING`, `BINARY`, `NUMBER`, `DATETIME`, `ROWID`
|
|
147
|
+
- Standard constructors: `Date()`, `Time()`, `Timestamp()`, `Binary()`, `DateFromTicks()`, `TimeFromTicks()`, `TimestampFromTicks()`
|
|
148
|
+
|
|
149
|
+
## Features
|
|
150
|
+
|
|
151
|
+
- **Pure Python** — no C extensions, no compilation, works everywhere Python runs
|
|
152
|
+
- **Complete DB-API 2.0** — `connect()`, `Cursor`, `fetchone/many/all`, `executemany`, `callproc`
|
|
153
|
+
- **Prepared statements** — `cursor.prepare()` / `cursor.execute()` for server-side preparation
|
|
154
|
+
- **Batch operations** — `executemany()` and `executemany_batch()` for bulk inserts
|
|
155
|
+
- **LOB support** — `create_lob()`, read/write CLOB and BLOB columns
|
|
156
|
+
- **Schema introspection** — `get_schema_info()` for tables, columns, indexes, constraints
|
|
157
|
+
- **Auto-commit control** — `connection.autocommit` property for transaction management
|
|
158
|
+
- **Server version detection** — `connection.get_server_version()` returns version string (e.g., `"11.2.0.0378"`)
|
|
159
|
+
- **Iterator protocol** — iterate over cursor results with `for row in cursor`
|
|
160
|
+
- **Context managers** — `with` statements for both connections and cursors
|
|
161
|
+
|
|
162
|
+
## Supported CUBRID Versions
|
|
163
|
+
|
|
164
|
+
The project targets CUBRID 11.x series and is validated in CI against:
|
|
165
|
+
|
|
166
|
+
- 11.2
|
|
167
|
+
- 11.4
|
|
168
|
+
|
|
169
|
+
## SQLAlchemy Integration
|
|
170
|
+
|
|
171
|
+
pycubrid works as a driver for [sqlalchemy-cubrid](https://github.com/cubrid-labs/sqlalchemy-cubrid) — the SQLAlchemy 2.0 dialect for CUBRID:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
pip install "sqlalchemy-cubrid[pycubrid]"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from sqlalchemy import create_engine, text
|
|
179
|
+
|
|
180
|
+
engine = create_engine("cubrid+pycubrid://dba@localhost:33000/testdb")
|
|
181
|
+
|
|
182
|
+
with engine.connect() as conn:
|
|
183
|
+
result = conn.execute(text("SELECT 1"))
|
|
184
|
+
print(result.scalar())
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
All SQLAlchemy features (ORM, Core, Alembic migrations, schema reflection) work transparently with the pycubrid driver.
|
|
188
|
+
|
|
189
|
+
## Documentation
|
|
190
|
+
|
|
191
|
+
| Guide | Description |
|
|
192
|
+
|---|---|
|
|
193
|
+
| [Connection](docs/CONNECTION.md) | Connection strings, URL format, configuration, connection pool |
|
|
194
|
+
| [Type Mapping](docs/TYPES.md) | Full type mapping, CUBRID-specific types, collection types |
|
|
195
|
+
| [API Reference](docs/API_REFERENCE.md) | Complete API documentation — modules, classes, functions |
|
|
196
|
+
| [Protocol](docs/PROTOCOL.md) | CAS wire protocol reference |
|
|
197
|
+
| [Development](docs/DEVELOPMENT.md) | Dev setup, testing, Docker, coverage, CI/CD |
|
|
198
|
+
| [Examples](docs/EXAMPLES.md) | Practical usage examples with code |
|
|
199
|
+
| [Troubleshooting](docs/TROUBLESHOOTING.md) | Connection errors, query problems, LOB handling, debugging |
|
|
200
|
+
|
|
201
|
+
## Compatibility
|
|
202
|
+
|
|
203
|
+
| | Python 3.10 | Python 3.11 | Python 3.12 | Python 3.13 |
|
|
204
|
+
|---|:---:|:---:|:---:|:---:|
|
|
205
|
+
| **Offline Tests** | ✅ | ✅ | ✅ | ✅ |
|
|
206
|
+
| **CUBRID 11.4** | ✅ | -- | ✅ | -- |
|
|
207
|
+
| **CUBRID 11.2** | ✅ | -- | ✅ | -- |
|
|
208
|
+
|
|
209
|
+
## Architecture
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
pycubrid/
|
|
213
|
+
├── __init__.py # Public API — connect(), types, exceptions, __version__
|
|
214
|
+
├── connection.py # Connection class — connect, commit, rollback, cursor, LOB
|
|
215
|
+
├── cursor.py # Cursor class — execute, fetch, prepare, callproc, iterator
|
|
216
|
+
├── types.py # DB-API 2.0 type objects and constructors
|
|
217
|
+
├── exceptions.py # PEP 249 exception hierarchy
|
|
218
|
+
├── constants.py # CAS function codes, data types, protocol constants
|
|
219
|
+
├── protocol.py # CAS wire protocol packet classes (18 packet types)
|
|
220
|
+
├── packet.py # Low-level packet reader/writer
|
|
221
|
+
├── lob.py # LOB (Large Object) support
|
|
222
|
+
└── py.typed # PEP 561 marker
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## FAQ
|
|
226
|
+
|
|
227
|
+
### How do I connect to CUBRID with Python?
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
import pycubrid
|
|
231
|
+
conn = pycubrid.connect(host="localhost", port=33000, database="testdb", user="dba")
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### How do I install pycubrid?
|
|
235
|
+
|
|
236
|
+
`pip install pycubrid` — no C extensions or build tools required.
|
|
237
|
+
|
|
238
|
+
### What parameter style does pycubrid use?
|
|
239
|
+
|
|
240
|
+
Question mark (`qmark`) style: `cursor.execute("SELECT * FROM users WHERE id = ?", (1,))`
|
|
241
|
+
|
|
242
|
+
### Does pycubrid work with SQLAlchemy?
|
|
243
|
+
|
|
244
|
+
Yes. Install `pip install "sqlalchemy-cubrid[pycubrid]"` and use the connection URL `cubrid+pycubrid://dba@localhost:33000/testdb`.
|
|
245
|
+
|
|
246
|
+
### What Python versions are supported?
|
|
247
|
+
|
|
248
|
+
Python 3.10, 3.11, 3.12, and 3.13.
|
|
249
|
+
|
|
250
|
+
### Does pycubrid support LOBs (CLOB/BLOB)?
|
|
251
|
+
|
|
252
|
+
Yes. Insert strings/bytes directly into CLOB/BLOB columns. For reading, LOB columns return data that can be accessed through the cursor.
|
|
253
|
+
|
|
254
|
+
### Is pycubrid thread-safe?
|
|
255
|
+
|
|
256
|
+
pycubrid has `threadsafety = 1`, meaning connections cannot be shared between threads. Create a separate connection per thread.
|
|
257
|
+
|
|
258
|
+
### What CUBRID versions are supported?
|
|
259
|
+
|
|
260
|
+
CUBRID 10.2, 11.0, 11.2, and 11.4 are tested in CI.
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
## Contributing
|
|
264
|
+
|
|
265
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines and [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for development setup.
|
|
266
|
+
|
|
267
|
+
## Security
|
|
268
|
+
|
|
269
|
+
Report vulnerabilities via email — see [SECURITY.md](SECURITY.md). Do not open public issues for security concerns.
|
|
270
|
+
|
|
271
|
+
## License
|
|
272
|
+
|
|
273
|
+
MIT — see [LICENSE](LICENSE).
|
pycubrid-0.5.0/README.md
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# pycubrid
|
|
2
|
+
|
|
3
|
+
**Pure Python DB-API 2.0 driver for the CUBRID database** — no C extensions, no compilation, PEP 249 compliant database connector.
|
|
4
|
+
|
|
5
|
+
[🇰🇷 한국어](docs/README.ko.md) · [🇺🇸 English](README.md) · [🇨🇳 中文](docs/README.zh.md) · [🇮🇳 हिन्दी](docs/README.hi.md) · [🇩🇪 Deutsch](docs/README.de.md) · [🇷🇺 Русский](docs/README.ru.md)
|
|
6
|
+
|
|
7
|
+
<!-- BADGES:START -->
|
|
8
|
+
[](https://pypi.org/project/pycubrid)
|
|
9
|
+
[](https://www.python.org)
|
|
10
|
+
[](https://github.com/cubrid-labs/pycubrid/actions/workflows/ci.yml)
|
|
11
|
+
[](https://github.com/cubrid-labs/pycubrid/blob/main/LICENSE)
|
|
12
|
+
[](https://github.com/cubrid-labs/pycubrid)
|
|
13
|
+
[](https://www.python.org/downloads/)
|
|
14
|
+
[](docs/DEVELOPMENT.md#code-coverage)
|
|
15
|
+
<!-- BADGES:END -->
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Why pycubrid?
|
|
20
|
+
|
|
21
|
+
CUBRID is a high-performance open-source relational database, widely adopted in
|
|
22
|
+
Korean public-sector and enterprise applications. The existing C-extension driver
|
|
23
|
+
(`CUBRIDdb`) had build dependencies and platform compatibility issues.
|
|
24
|
+
|
|
25
|
+
**pycubrid** solves these problems:
|
|
26
|
+
|
|
27
|
+
- **Pure Python implementation** — no C build dependencies, install with `pip install` only
|
|
28
|
+
- **Full PEP 249 (DB-API 2.0) compliance** — standard exception hierarchy, type objects, cursor interface
|
|
29
|
+
- **471 offline tests** with **99%+ code coverage** — no database required to run them
|
|
30
|
+
- **PEP 561 typed package** — `py.typed` marker for modern IDE and static analysis support
|
|
31
|
+
- **Direct CUBRID CAS protocol** implementation — no additional middleware required
|
|
32
|
+
- **LOB (CLOB/BLOB) support** — handle large text and binary data
|
|
33
|
+
|
|
34
|
+
## Requirements
|
|
35
|
+
|
|
36
|
+
- Python 3.10+
|
|
37
|
+
- CUBRID database server 10.2+
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install pycubrid
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
### Basic Connection
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
import pycubrid
|
|
51
|
+
|
|
52
|
+
conn = pycubrid.connect(
|
|
53
|
+
host="localhost",
|
|
54
|
+
port=33000,
|
|
55
|
+
database="testdb",
|
|
56
|
+
user="dba",
|
|
57
|
+
password="",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
cur = conn.cursor()
|
|
61
|
+
cur.execute("SELECT 1 + 1")
|
|
62
|
+
print(cur.fetchone()) # (2,)
|
|
63
|
+
|
|
64
|
+
cur.close()
|
|
65
|
+
conn.close()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Context Manager
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
import pycubrid
|
|
72
|
+
|
|
73
|
+
with pycubrid.connect(host="localhost", port=33000, database="testdb", user="dba") as conn:
|
|
74
|
+
with conn.cursor() as cur:
|
|
75
|
+
cur.execute("CREATE TABLE IF NOT EXISTS cookbook_users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100))")
|
|
76
|
+
cur.execute("INSERT INTO cookbook_users (name) VALUES (?)", ("Alice",))
|
|
77
|
+
conn.commit()
|
|
78
|
+
|
|
79
|
+
cur.execute("SELECT * FROM cookbook_users")
|
|
80
|
+
for row in cur:
|
|
81
|
+
print(row)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Parameter Binding
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
# qmark style (question marks)
|
|
88
|
+
cur.execute("SELECT * FROM users WHERE name = ? AND age > ?", ("Alice", 25))
|
|
89
|
+
|
|
90
|
+
# Batch insert with executemany
|
|
91
|
+
data = [("Alice", 30), ("Bob", 25), ("Charlie", 35)]
|
|
92
|
+
cur.executemany("INSERT INTO users (name, age) VALUES (?, ?)", data)
|
|
93
|
+
conn.commit()
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Prepared Statements
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
cur.prepare("SELECT * FROM users WHERE department = ?")
|
|
100
|
+
cur.execute(None, ("Engineering",))
|
|
101
|
+
engineers = cur.fetchall()
|
|
102
|
+
|
|
103
|
+
cur.execute(None, ("Marketing",))
|
|
104
|
+
marketers = cur.fetchall()
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## PEP 249 Compliance
|
|
108
|
+
|
|
109
|
+
| Attribute | Value |
|
|
110
|
+
|---|---|
|
|
111
|
+
| `apilevel` | `"2.0"` |
|
|
112
|
+
| `threadsafety` | `1` (connections cannot be shared between threads) |
|
|
113
|
+
| `paramstyle` | `"qmark"` (positional parameters `?`) |
|
|
114
|
+
|
|
115
|
+
- Full standard exception hierarchy: `Warning`, `Error`, `InterfaceError`, `DatabaseError`, `OperationalError`, `IntegrityError`, `InternalError`, `ProgrammingError`, `NotSupportedError`
|
|
116
|
+
- Standard type objects: `STRING`, `BINARY`, `NUMBER`, `DATETIME`, `ROWID`
|
|
117
|
+
- Standard constructors: `Date()`, `Time()`, `Timestamp()`, `Binary()`, `DateFromTicks()`, `TimeFromTicks()`, `TimestampFromTicks()`
|
|
118
|
+
|
|
119
|
+
## Features
|
|
120
|
+
|
|
121
|
+
- **Pure Python** — no C extensions, no compilation, works everywhere Python runs
|
|
122
|
+
- **Complete DB-API 2.0** — `connect()`, `Cursor`, `fetchone/many/all`, `executemany`, `callproc`
|
|
123
|
+
- **Prepared statements** — `cursor.prepare()` / `cursor.execute()` for server-side preparation
|
|
124
|
+
- **Batch operations** — `executemany()` and `executemany_batch()` for bulk inserts
|
|
125
|
+
- **LOB support** — `create_lob()`, read/write CLOB and BLOB columns
|
|
126
|
+
- **Schema introspection** — `get_schema_info()` for tables, columns, indexes, constraints
|
|
127
|
+
- **Auto-commit control** — `connection.autocommit` property for transaction management
|
|
128
|
+
- **Server version detection** — `connection.get_server_version()` returns version string (e.g., `"11.2.0.0378"`)
|
|
129
|
+
- **Iterator protocol** — iterate over cursor results with `for row in cursor`
|
|
130
|
+
- **Context managers** — `with` statements for both connections and cursors
|
|
131
|
+
|
|
132
|
+
## Supported CUBRID Versions
|
|
133
|
+
|
|
134
|
+
The project targets CUBRID 11.x series and is validated in CI against:
|
|
135
|
+
|
|
136
|
+
- 11.2
|
|
137
|
+
- 11.4
|
|
138
|
+
|
|
139
|
+
## SQLAlchemy Integration
|
|
140
|
+
|
|
141
|
+
pycubrid works as a driver for [sqlalchemy-cubrid](https://github.com/cubrid-labs/sqlalchemy-cubrid) — the SQLAlchemy 2.0 dialect for CUBRID:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
pip install "sqlalchemy-cubrid[pycubrid]"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from sqlalchemy import create_engine, text
|
|
149
|
+
|
|
150
|
+
engine = create_engine("cubrid+pycubrid://dba@localhost:33000/testdb")
|
|
151
|
+
|
|
152
|
+
with engine.connect() as conn:
|
|
153
|
+
result = conn.execute(text("SELECT 1"))
|
|
154
|
+
print(result.scalar())
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
All SQLAlchemy features (ORM, Core, Alembic migrations, schema reflection) work transparently with the pycubrid driver.
|
|
158
|
+
|
|
159
|
+
## Documentation
|
|
160
|
+
|
|
161
|
+
| Guide | Description |
|
|
162
|
+
|---|---|
|
|
163
|
+
| [Connection](docs/CONNECTION.md) | Connection strings, URL format, configuration, connection pool |
|
|
164
|
+
| [Type Mapping](docs/TYPES.md) | Full type mapping, CUBRID-specific types, collection types |
|
|
165
|
+
| [API Reference](docs/API_REFERENCE.md) | Complete API documentation — modules, classes, functions |
|
|
166
|
+
| [Protocol](docs/PROTOCOL.md) | CAS wire protocol reference |
|
|
167
|
+
| [Development](docs/DEVELOPMENT.md) | Dev setup, testing, Docker, coverage, CI/CD |
|
|
168
|
+
| [Examples](docs/EXAMPLES.md) | Practical usage examples with code |
|
|
169
|
+
| [Troubleshooting](docs/TROUBLESHOOTING.md) | Connection errors, query problems, LOB handling, debugging |
|
|
170
|
+
|
|
171
|
+
## Compatibility
|
|
172
|
+
|
|
173
|
+
| | Python 3.10 | Python 3.11 | Python 3.12 | Python 3.13 |
|
|
174
|
+
|---|:---:|:---:|:---:|:---:|
|
|
175
|
+
| **Offline Tests** | ✅ | ✅ | ✅ | ✅ |
|
|
176
|
+
| **CUBRID 11.4** | ✅ | -- | ✅ | -- |
|
|
177
|
+
| **CUBRID 11.2** | ✅ | -- | ✅ | -- |
|
|
178
|
+
|
|
179
|
+
## Architecture
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
pycubrid/
|
|
183
|
+
├── __init__.py # Public API — connect(), types, exceptions, __version__
|
|
184
|
+
├── connection.py # Connection class — connect, commit, rollback, cursor, LOB
|
|
185
|
+
├── cursor.py # Cursor class — execute, fetch, prepare, callproc, iterator
|
|
186
|
+
├── types.py # DB-API 2.0 type objects and constructors
|
|
187
|
+
├── exceptions.py # PEP 249 exception hierarchy
|
|
188
|
+
├── constants.py # CAS function codes, data types, protocol constants
|
|
189
|
+
├── protocol.py # CAS wire protocol packet classes (18 packet types)
|
|
190
|
+
├── packet.py # Low-level packet reader/writer
|
|
191
|
+
├── lob.py # LOB (Large Object) support
|
|
192
|
+
└── py.typed # PEP 561 marker
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## FAQ
|
|
196
|
+
|
|
197
|
+
### How do I connect to CUBRID with Python?
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
import pycubrid
|
|
201
|
+
conn = pycubrid.connect(host="localhost", port=33000, database="testdb", user="dba")
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### How do I install pycubrid?
|
|
205
|
+
|
|
206
|
+
`pip install pycubrid` — no C extensions or build tools required.
|
|
207
|
+
|
|
208
|
+
### What parameter style does pycubrid use?
|
|
209
|
+
|
|
210
|
+
Question mark (`qmark`) style: `cursor.execute("SELECT * FROM users WHERE id = ?", (1,))`
|
|
211
|
+
|
|
212
|
+
### Does pycubrid work with SQLAlchemy?
|
|
213
|
+
|
|
214
|
+
Yes. Install `pip install "sqlalchemy-cubrid[pycubrid]"` and use the connection URL `cubrid+pycubrid://dba@localhost:33000/testdb`.
|
|
215
|
+
|
|
216
|
+
### What Python versions are supported?
|
|
217
|
+
|
|
218
|
+
Python 3.10, 3.11, 3.12, and 3.13.
|
|
219
|
+
|
|
220
|
+
### Does pycubrid support LOBs (CLOB/BLOB)?
|
|
221
|
+
|
|
222
|
+
Yes. Insert strings/bytes directly into CLOB/BLOB columns. For reading, LOB columns return data that can be accessed through the cursor.
|
|
223
|
+
|
|
224
|
+
### Is pycubrid thread-safe?
|
|
225
|
+
|
|
226
|
+
pycubrid has `threadsafety = 1`, meaning connections cannot be shared between threads. Create a separate connection per thread.
|
|
227
|
+
|
|
228
|
+
### What CUBRID versions are supported?
|
|
229
|
+
|
|
230
|
+
CUBRID 10.2, 11.0, 11.2, and 11.4 are tested in CI.
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
## Contributing
|
|
234
|
+
|
|
235
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines and [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for development setup.
|
|
236
|
+
|
|
237
|
+
## Security
|
|
238
|
+
|
|
239
|
+
Report vulnerabilities via email — see [SECURITY.md](SECURITY.md). Do not open public issues for security concerns.
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""pycubrid — Pure Python DB-API 2.0 driver for CUBRID."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
from pycubrid.exceptions import (
|
|
8
|
+
DatabaseError,
|
|
9
|
+
DataError,
|
|
10
|
+
Error,
|
|
11
|
+
IntegrityError,
|
|
12
|
+
InterfaceError,
|
|
13
|
+
InternalError,
|
|
14
|
+
NotSupportedError,
|
|
15
|
+
OperationalError,
|
|
16
|
+
ProgrammingError,
|
|
17
|
+
Warning,
|
|
18
|
+
)
|
|
19
|
+
from pycubrid.types import (
|
|
20
|
+
BINARY,
|
|
21
|
+
DATETIME,
|
|
22
|
+
NUMBER,
|
|
23
|
+
ROWID,
|
|
24
|
+
STRING,
|
|
25
|
+
Binary,
|
|
26
|
+
Date,
|
|
27
|
+
DateFromTicks,
|
|
28
|
+
Time,
|
|
29
|
+
Timestamp,
|
|
30
|
+
TimestampFromTicks,
|
|
31
|
+
TimeFromTicks,
|
|
32
|
+
)
|
|
33
|
+
from pycubrid.lob import Lob
|
|
34
|
+
|
|
35
|
+
if TYPE_CHECKING:
|
|
36
|
+
from pycubrid.connection import Connection
|
|
37
|
+
|
|
38
|
+
__version__ = "0.5.0"
|
|
39
|
+
|
|
40
|
+
# PEP 249 module-level attributes
|
|
41
|
+
apilevel = "2.0"
|
|
42
|
+
threadsafety = 1 # Threads may share the module but not connections
|
|
43
|
+
paramstyle = "qmark" # Question mark style: WHERE name = ?
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def connect(
|
|
47
|
+
host: str = "localhost",
|
|
48
|
+
port: int = 33000,
|
|
49
|
+
database: str = "",
|
|
50
|
+
user: str = "dba",
|
|
51
|
+
password: str = "",
|
|
52
|
+
**kwargs: Any,
|
|
53
|
+
) -> Connection:
|
|
54
|
+
"""Create a new database connection.
|
|
55
|
+
|
|
56
|
+
PEP 249 module-level constructor.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
host: CUBRID server hostname or IP address.
|
|
60
|
+
port: CUBRID broker port (default 33000).
|
|
61
|
+
database: Database name.
|
|
62
|
+
user: Database user (default ``"dba"``).
|
|
63
|
+
password: Database password (default ``""``).
|
|
64
|
+
**kwargs: Additional connection parameters.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
A new :class:`~pycubrid.connection.Connection` instance.
|
|
68
|
+
"""
|
|
69
|
+
from pycubrid.connection import Connection
|
|
70
|
+
|
|
71
|
+
return Connection(
|
|
72
|
+
host=host,
|
|
73
|
+
port=port,
|
|
74
|
+
database=database,
|
|
75
|
+
user=user,
|
|
76
|
+
password=password,
|
|
77
|
+
**kwargs,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
__all__ = [
|
|
82
|
+
"__version__",
|
|
83
|
+
"apilevel",
|
|
84
|
+
"threadsafety",
|
|
85
|
+
"paramstyle",
|
|
86
|
+
"connect",
|
|
87
|
+
# Exceptions
|
|
88
|
+
"Warning",
|
|
89
|
+
"Error",
|
|
90
|
+
"InterfaceError",
|
|
91
|
+
"DatabaseError",
|
|
92
|
+
"DataError",
|
|
93
|
+
"OperationalError",
|
|
94
|
+
"IntegrityError",
|
|
95
|
+
"InternalError",
|
|
96
|
+
"ProgrammingError",
|
|
97
|
+
"NotSupportedError",
|
|
98
|
+
# Type objects
|
|
99
|
+
"STRING",
|
|
100
|
+
"BINARY",
|
|
101
|
+
"NUMBER",
|
|
102
|
+
"DATETIME",
|
|
103
|
+
"ROWID",
|
|
104
|
+
# Constructors
|
|
105
|
+
"Date",
|
|
106
|
+
"Time",
|
|
107
|
+
"Timestamp",
|
|
108
|
+
"DateFromTicks",
|
|
109
|
+
"TimeFromTicks",
|
|
110
|
+
"TimestampFromTicks",
|
|
111
|
+
"Binary",
|
|
112
|
+
"Lob",
|
|
113
|
+
]
|