sqlcarbon 0.1.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.
- sqlcarbon-0.1.0/.claude/settings.local.json +7 -0
- sqlcarbon-0.1.0/PKG-INFO +395 -0
- sqlcarbon-0.1.0/README.md +371 -0
- sqlcarbon-0.1.0/pyproject.toml +39 -0
- sqlcarbon-0.1.0/sqlcarbon/__init__.py +41 -0
- sqlcarbon-0.1.0/sqlcarbon/cli.py +122 -0
- sqlcarbon-0.1.0/sqlcarbon/config_loader.py +94 -0
- sqlcarbon-0.1.0/sqlcarbon/connection.py +30 -0
- sqlcarbon-0.1.0/sqlcarbon/copier.py +124 -0
- sqlcarbon-0.1.0/sqlcarbon/ddl_generator.py +125 -0
- sqlcarbon-0.1.0/sqlcarbon/orchestrator.py +282 -0
- sqlcarbon-0.1.0/sqlcarbon/schema_reader.py +345 -0
- sqlcarbon-0.1.0/sqlcarbon/version_checker.py +80 -0
sqlcarbon-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sqlcarbon
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Reliable, deterministic SQL Server table-to-table copy tool
|
|
5
|
+
Project-URL: Homepage, https://github.com/yourusername/sqlcarbon
|
|
6
|
+
Project-URL: Issues, https://github.com/yourusername/sqlcarbon/issues
|
|
7
|
+
License: MIT
|
|
8
|
+
Keywords: data-migration,database,etl,sql,sqlserver
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Intended Audience :: System Administrators
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Database
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: click>=8.0
|
|
20
|
+
Requires-Dist: pydantic>=2.0
|
|
21
|
+
Requires-Dist: pyodbc>=4.0
|
|
22
|
+
Requires-Dist: pyyaml>=6.0
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# SQLcarbon
|
|
26
|
+
|
|
27
|
+
**Reliable, deterministic SQL Server table-to-table copy tool.**
|
|
28
|
+
|
|
29
|
+
Copy tables between SQL Server instances with a single command or a few lines of Python — no SSIS, no BCP scripts, no fuss.
|
|
30
|
+
|
|
31
|
+
> Created by **TroBeeOne LLC**
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- Copy tables across different SQL Server instances (same or different versions)
|
|
38
|
+
- Supports trusted (Windows) and SQL authentication
|
|
39
|
+
- Recreates schema: columns, identity columns (with correct seed/increment), computed columns
|
|
40
|
+
- Optionally copies indexes, check/default constraints, and extended properties
|
|
41
|
+
- Three copy modes: **full**, **schema_only**, **data_only**
|
|
42
|
+
- Chunked streaming reads with `fast_executemany` inserts — handles tables of any size
|
|
43
|
+
- Continues to the next job when one fails (configurable `stop_on_failure`)
|
|
44
|
+
- Clear, structured log files written to your working directory
|
|
45
|
+
- Version compatibility warnings (e.g., using `datetime2` against a SQL Server 2005 target)
|
|
46
|
+
- Use as a **CLI tool** or a **Python library**
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install sqlcarbon
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Requires **Python 3.10+** and the [Microsoft ODBC Driver for SQL Server](https://learn.microsoft.com/en-us/sql/connect/odbc/download-odbc-driver-for-sql-server).
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Quick Start — CLI
|
|
61
|
+
|
|
62
|
+
### 1. Generate a sample config
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
sqlcarbon init > plan.yaml
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 2. Edit `plan.yaml`
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
connections:
|
|
72
|
+
my_source:
|
|
73
|
+
server: "sql01.example.com"
|
|
74
|
+
database: "Sales"
|
|
75
|
+
auth:
|
|
76
|
+
mode: "trusted"
|
|
77
|
+
|
|
78
|
+
my_dest:
|
|
79
|
+
server: "sql02.example.com"
|
|
80
|
+
database: "Archive"
|
|
81
|
+
auth:
|
|
82
|
+
mode: "sql"
|
|
83
|
+
username: "sa"
|
|
84
|
+
password: "yourpassword"
|
|
85
|
+
|
|
86
|
+
defaults:
|
|
87
|
+
batch_size: 100000
|
|
88
|
+
stop_on_failure: false
|
|
89
|
+
create_indexes: false
|
|
90
|
+
create_constraints: false
|
|
91
|
+
include_extended_properties: false
|
|
92
|
+
copy_mode: "full"
|
|
93
|
+
nolock: true
|
|
94
|
+
|
|
95
|
+
jobs:
|
|
96
|
+
- name: CopyCustomers
|
|
97
|
+
source_connection: my_source
|
|
98
|
+
destination_connection: my_dest
|
|
99
|
+
source_table: dbo.Customers
|
|
100
|
+
destination_table: dbo.Customers_Archive
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 3. Validate your config (no database changes)
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
sqlcarbon validate plan.yaml
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
OK: Config is valid — 2 connection(s), 1 job(s).
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 4. Run it
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
sqlcarbon run plan.yaml
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
2026-03-08 10:00:01 INFO ============================================================
|
|
121
|
+
2026-03-08 10:00:01 INFO Starting Job: [CopyCustomers]
|
|
122
|
+
2026-03-08 10:00:01 INFO ============================================================
|
|
123
|
+
2026-03-08 10:00:01 INFO [CopyCustomers] Source: sql01.example.com / Sales
|
|
124
|
+
2026-03-08 10:00:01 INFO [CopyCustomers] Destination: sql02.example.com / Archive
|
|
125
|
+
2026-03-08 10:00:01 INFO [CopyCustomers] Copy mode: full
|
|
126
|
+
2026-03-08 10:00:02 INFO [CopyCustomers] Source: SQL Server 2019 | Destination: SQL Server 2019
|
|
127
|
+
2026-03-08 10:00:02 INFO [CopyCustomers] Creating table [dbo].[Customers_Archive]...
|
|
128
|
+
2026-03-08 10:00:02 INFO [CopyCustomers] Table created.
|
|
129
|
+
2026-03-08 10:00:02 INFO [CopyCustomers] Starting data copy (batch_size=100,000, nolock=True)...
|
|
130
|
+
2026-03-08 10:00:04 INFO [CopyCustomers] ... 100,000 rows inserted.
|
|
131
|
+
2026-03-08 10:00:05 INFO [CopyCustomers] ... 185,432 rows inserted.
|
|
132
|
+
2026-03-08 10:00:05 INFO [CopyCustomers] SUCCESS | rows=185,432 | duration=3.84s
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
A log file is also written to your current directory: `sqlcarbon_20260308_100001.log`
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Quick Start — Python Library
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from sqlcarbon import MigrationPlan, run_plan
|
|
143
|
+
|
|
144
|
+
plan = MigrationPlan.from_yaml("plan.yaml")
|
|
145
|
+
summary = run_plan(plan)
|
|
146
|
+
|
|
147
|
+
print(f"Succeeded: {summary.succeeded} / {summary.total_jobs}")
|
|
148
|
+
for result in summary.results:
|
|
149
|
+
print(f" {result.job_name}: {result.rows_copied:,} rows in {result.duration_seconds:.2f}s")
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Load from a Python dict
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from sqlcarbon import MigrationPlan, run_plan
|
|
156
|
+
|
|
157
|
+
plan = MigrationPlan.from_dict({
|
|
158
|
+
"connections": {
|
|
159
|
+
"src": {
|
|
160
|
+
"server": "sql01.example.com",
|
|
161
|
+
"database": "Sales",
|
|
162
|
+
"auth": {"mode": "trusted"},
|
|
163
|
+
},
|
|
164
|
+
"dst": {
|
|
165
|
+
"server": "sql02.example.com",
|
|
166
|
+
"database": "Archive",
|
|
167
|
+
"auth": {"mode": "sql", "username": "sa", "password": "yourpassword"},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
"jobs": [
|
|
171
|
+
{
|
|
172
|
+
"name": "CopyCustomers",
|
|
173
|
+
"source_connection": "src",
|
|
174
|
+
"destination_connection": "dst",
|
|
175
|
+
"source_table": "dbo.Customers",
|
|
176
|
+
"destination_table": "dbo.Customers_Archive",
|
|
177
|
+
}
|
|
178
|
+
],
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
summary = run_plan(plan)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Load from a YAML string
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from sqlcarbon import MigrationPlan, run_plan
|
|
188
|
+
|
|
189
|
+
yaml_text = """
|
|
190
|
+
connections:
|
|
191
|
+
src:
|
|
192
|
+
server: "sql01.example.com"
|
|
193
|
+
database: "Sales"
|
|
194
|
+
auth:
|
|
195
|
+
mode: "trusted"
|
|
196
|
+
dst:
|
|
197
|
+
server: "sql02.example.com"
|
|
198
|
+
database: "Archive"
|
|
199
|
+
auth:
|
|
200
|
+
mode: "trusted"
|
|
201
|
+
jobs:
|
|
202
|
+
- name: CopyOrders
|
|
203
|
+
source_connection: src
|
|
204
|
+
destination_connection: dst
|
|
205
|
+
source_table: dbo.Orders
|
|
206
|
+
destination_table: dbo.Orders_Archive
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
plan = MigrationPlan.from_yaml_string(yaml_text)
|
|
210
|
+
summary = run_plan(plan)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Configuration Reference
|
|
216
|
+
|
|
217
|
+
### `connections`
|
|
218
|
+
|
|
219
|
+
Each named connection supports:
|
|
220
|
+
|
|
221
|
+
| Field | Required | Default | Description |
|
|
222
|
+
|-------|----------|---------|-------------|
|
|
223
|
+
| `server` | Yes | — | Server name, IP, or `server,port` / `server:port` |
|
|
224
|
+
| `database` | Yes | — | Target database name |
|
|
225
|
+
| `auth.mode` | No | `trusted` | `trusted` (Windows auth) or `sql` (SQL auth) |
|
|
226
|
+
| `auth.username` | If `sql` | — | SQL login username |
|
|
227
|
+
| `auth.password` | If `sql` | — | SQL login password |
|
|
228
|
+
| `driver` | No | `ODBC Driver 17 for SQL Server` | ODBC driver name |
|
|
229
|
+
| `trust_server_certificate` | No | `false` | Set `true` to bypass SSL certificate validation (equivalent to SSMS "Trust server certificate") |
|
|
230
|
+
|
|
231
|
+
**Custom port example:**
|
|
232
|
+
```yaml
|
|
233
|
+
connections:
|
|
234
|
+
my_conn:
|
|
235
|
+
server: "sql01.example.com,1445"
|
|
236
|
+
database: "MyDB"
|
|
237
|
+
auth:
|
|
238
|
+
mode: "trusted"
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**ODBC Driver 18 example** (needed for newer SQL Server / Azure SQL):
|
|
242
|
+
```yaml
|
|
243
|
+
connections:
|
|
244
|
+
my_conn:
|
|
245
|
+
server: "sql01.example.com"
|
|
246
|
+
database: "MyDB"
|
|
247
|
+
auth:
|
|
248
|
+
mode: "trusted"
|
|
249
|
+
driver: "ODBC Driver 18 for SQL Server"
|
|
250
|
+
trust_server_certificate: true # bypass cert validation (like SSMS checkbox)
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
### `defaults`
|
|
256
|
+
|
|
257
|
+
Global defaults applied to all jobs unless overridden at the job level.
|
|
258
|
+
|
|
259
|
+
| Field | Default | Description |
|
|
260
|
+
|-------|---------|-------------|
|
|
261
|
+
| `batch_size` | `100000` | Rows per read/insert chunk |
|
|
262
|
+
| `stop_on_failure` | `false` | Stop all remaining jobs if one fails |
|
|
263
|
+
| `create_indexes` | `false` | Recreate indexes on destination |
|
|
264
|
+
| `create_constraints` | `false` | Recreate check and default constraints |
|
|
265
|
+
| `include_extended_properties` | `false` | Copy extended properties |
|
|
266
|
+
| `copy_mode` | `full` | `full`, `schema_only`, or `data_only` |
|
|
267
|
+
| `nolock` | `true` | Use `WITH (NOLOCK)` on source reads |
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
### `jobs`
|
|
272
|
+
|
|
273
|
+
Each job represents one table copy operation.
|
|
274
|
+
|
|
275
|
+
| Field | Required | Description |
|
|
276
|
+
|-------|----------|-------------|
|
|
277
|
+
| `name` | Yes | Friendly name shown in logs |
|
|
278
|
+
| `source_connection` | Yes | Name of a connection defined under `connections` |
|
|
279
|
+
| `destination_connection` | Yes | Name of a connection defined under `connections` |
|
|
280
|
+
| `source_table` | Yes | Source table, e.g. `dbo.Customers` |
|
|
281
|
+
| `destination_table` | Yes | Destination table, e.g. `dbo.Customers_Archive` |
|
|
282
|
+
| `options` | No | Per-job overrides (see below) |
|
|
283
|
+
|
|
284
|
+
**Per-job `options`** (all optional — fall back to `defaults` if omitted):
|
|
285
|
+
|
|
286
|
+
```yaml
|
|
287
|
+
options:
|
|
288
|
+
batch_size: 50000
|
|
289
|
+
create_indexes: true
|
|
290
|
+
create_constraints: true
|
|
291
|
+
include_extended_properties: false
|
|
292
|
+
stop_on_failure: true
|
|
293
|
+
copy_mode: "schema_only"
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Copy Modes
|
|
299
|
+
|
|
300
|
+
| Mode | Creates Table | Copies Data | Use When |
|
|
301
|
+
|------|:---:|:---:|----------|
|
|
302
|
+
| `full` (default) | Yes | Yes | Normal table archiving / migration |
|
|
303
|
+
| `schema_only` | Yes | No | Pre-create table structure before a data load |
|
|
304
|
+
| `data_only` | No | Yes | Destination table already exists; just load rows |
|
|
305
|
+
|
|
306
|
+
> **Safety:** SQLcarbon will **never** drop or truncate an existing table. If a destination table already exists when running `full` or `schema_only`, the job hard-fails with a clear error message and no data is touched.
|
|
307
|
+
>
|
|
308
|
+
> For `data_only`, if the destination table does **not** exist, the job hard-fails with a clear error message.
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Multiple Jobs Example
|
|
313
|
+
|
|
314
|
+
```yaml
|
|
315
|
+
connections:
|
|
316
|
+
prod:
|
|
317
|
+
server: "sql-prod.example.com"
|
|
318
|
+
database: "Operations"
|
|
319
|
+
auth:
|
|
320
|
+
mode: "trusted"
|
|
321
|
+
|
|
322
|
+
archive:
|
|
323
|
+
server: "sql-archive.example.com"
|
|
324
|
+
database: "Archive2026"
|
|
325
|
+
auth:
|
|
326
|
+
mode: "trusted"
|
|
327
|
+
|
|
328
|
+
defaults:
|
|
329
|
+
batch_size: 100000
|
|
330
|
+
stop_on_failure: false
|
|
331
|
+
create_indexes: true
|
|
332
|
+
copy_mode: "full"
|
|
333
|
+
nolock: true
|
|
334
|
+
|
|
335
|
+
jobs:
|
|
336
|
+
- name: CopyCustomers
|
|
337
|
+
source_connection: prod
|
|
338
|
+
destination_connection: archive
|
|
339
|
+
source_table: dbo.Customers
|
|
340
|
+
destination_table: dbo.Customers
|
|
341
|
+
|
|
342
|
+
- name: CopyOrders
|
|
343
|
+
source_connection: prod
|
|
344
|
+
destination_connection: archive
|
|
345
|
+
source_table: dbo.Orders
|
|
346
|
+
destination_table: dbo.Orders
|
|
347
|
+
options:
|
|
348
|
+
stop_on_failure: true # stop everything if Orders fails
|
|
349
|
+
|
|
350
|
+
- name: CopyOrderLines
|
|
351
|
+
source_connection: prod
|
|
352
|
+
destination_connection: archive
|
|
353
|
+
source_table: dbo.OrderLines
|
|
354
|
+
destination_table: dbo.OrderLines
|
|
355
|
+
|
|
356
|
+
- name: SchemaOnlyProducts
|
|
357
|
+
source_connection: prod
|
|
358
|
+
destination_connection: archive
|
|
359
|
+
source_table: dbo.Products
|
|
360
|
+
destination_table: dbo.Products
|
|
361
|
+
options:
|
|
362
|
+
copy_mode: "schema_only"
|
|
363
|
+
create_indexes: true
|
|
364
|
+
create_constraints: true
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Behavior Notes
|
|
370
|
+
|
|
371
|
+
- **Identity columns** — SQLcarbon reads the exact seed and increment from the source and recreates them on the destination. `SET IDENTITY_INSERT ON/OFF` is handled automatically.
|
|
372
|
+
- **Computed columns** — Detected and recreated as computed columns on the destination. They are excluded from the data `INSERT` (SQL Server recalculates them automatically).
|
|
373
|
+
- **Partial failures** — If a batch insert fails mid-copy, SQLcarbon logs a clear `PARTIAL FAILURE` warning with the number of rows already committed. The partial data is left in place for inspection; SQLcarbon does not attempt cleanup.
|
|
374
|
+
- **Version compatibility** — If the source uses a data type not available on the destination (e.g., `datetime2` targeting SQL Server 2005), a warning is logged before the job runs. SQLcarbon does not attempt type transformations.
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## CLI Reference
|
|
379
|
+
|
|
380
|
+
```
|
|
381
|
+
sqlcarbon --help
|
|
382
|
+
sqlcarbon run <config.yaml> Run all jobs in the plan
|
|
383
|
+
sqlcarbon validate <config.yaml> Validate config without touching any database
|
|
384
|
+
sqlcarbon init Print a sample plan.yaml to stdout
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## License
|
|
390
|
+
|
|
391
|
+
MIT License — see `LICENSE` for details.
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
*SQLcarbon is an open-source project initially created by **TroBeeOne LLC**.*
|