Postgres real backend: psycopg adapter, schema, migration
Replace the PostgresDatabase skeleton with a real implementation: psycopg (v3) first, psycopg2 second, lazy load, missing driver still raises PostgresDriverMissingError with no silent SQLite fallback. A sqlite3-style adapter (PgConnection/PgCursor/PgRow) translates ? placeholders to %s outside string literals, maps UNIQUE/FK violations, lock errors and connection failures to explicit Postgres error types, and handles INSERT OR REPLACE, PRAGMA table_info, AUTOINCREMENT and FTS5 refusal. POSTGRES_SCHEMA covers all business tables with tasks result columns; server init_db uses it under CLOUD_DB_BACKEND=postgres, SQLite path unchanged. migrate_sqlite_to_postgres.py copies rows with ON CONFLICT DO NOTHING and reseeds identity sequences. Tests: cloud 239 (235 pass, 4 skipped without a real server), host 27 pass; real-server tests skip unless CLOUD_TEST_PG_DSN is set.
This commit is contained in:
1 parent
a19e77ee44
commit
dc3f572b2b
10 files changed
+1542
-66
No files matched your search
@@ -0,0 +1,37 @@
|
||||
"""把 SQLite 控制面库迁移到 Postgres 的命令行入口。
|
||||
|
||||
用法(Postgres 连接参数只走 CLOUD_DB_* 环境变量,本脚本
|
||||
不接受、不打印任何密码或密钥):
|
||||
|
||||
CLOUD_DB_HOST=... CLOUD_DB_PORT=5432 CLOUD_DB_NAME=... \
|
||||
CLOUD_DB_USER=... CLOUD_DB_PASSWORD=... \
|
||||
python3 -m cloud.migrate_sqlite_to_postgres --sqlite <sqlite 文件>
|
||||
|
||||
输出:每张表本次插入的行数(第二次跑应全为 0,即幂等,
|
||||
不重复插)。驱动缺失时明确报错,绝不静默回落到 SQLite;
|
||||
目标库须事先存在(本脚本不建库,建库见 cloud/README.md)。
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from cloud.migrations import migrate_sqlite_to_postgres
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Migrate a SQLite control-plane DB to Postgres.")
|
||||
parser.add_argument("--sqlite", required=True,
|
||||
help="source SQLite file path")
|
||||
args = parser.parse_args(argv)
|
||||
result = migrate_sqlite_to_postgres(args.sqlite)
|
||||
total = 0
|
||||
for table, count in result.items():
|
||||
print("%s: %d" % (table, count))
|
||||
total += count
|
||||
print("total inserted: %d" % total)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user