mirror of
https://github.com/KohakuBlueleaf/KohakuHub.git
synced 2026-03-11 17:34:08 -05:00
200 lines
6.0 KiB
Python
200 lines
6.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Migration 013: Change size fields from INTEGER to BIGINT.
|
|
|
|
This fixes the "integer out of range" error when uploading large files (>2GB).
|
|
PostgreSQL INTEGER is limited to 2,147,483,647 (~2.1GB), but LFS files
|
|
can be much larger.
|
|
|
|
Changes:
|
|
- File.size: INTEGER → BIGINT
|
|
- StagingUpload.size: INTEGER → BIGINT
|
|
- LFSObjectHistory.size: INTEGER → BIGINT
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
|
|
# Add src to path
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "src"))
|
|
# Add db_migrations to path (for _migration_utils)
|
|
sys.path.insert(0, os.path.dirname(__file__))
|
|
|
|
from kohakuhub.db import db
|
|
from kohakuhub.config import cfg
|
|
from _migration_utils import should_skip_due_to_future_migrations, check_table_exists
|
|
|
|
MIGRATION_NUMBER = 13
|
|
|
|
|
|
def is_applied(db, cfg):
|
|
"""Check if THIS migration has been applied.
|
|
|
|
Returns True if all size columns are already BIGINT.
|
|
"""
|
|
try:
|
|
cursor = db.cursor()
|
|
if cfg.app.db_backend == "postgres":
|
|
# Check File.size
|
|
cursor.execute(
|
|
"""
|
|
SELECT data_type
|
|
FROM information_schema.columns
|
|
WHERE table_name='file' AND column_name='size'
|
|
"""
|
|
)
|
|
result = cursor.fetchone()
|
|
if not result or result[0] != "bigint":
|
|
return False
|
|
|
|
# Check StagingUpload.size
|
|
cursor.execute(
|
|
"""
|
|
SELECT data_type
|
|
FROM information_schema.columns
|
|
WHERE table_name='stagingupload' AND column_name='size'
|
|
"""
|
|
)
|
|
result = cursor.fetchone()
|
|
if not result or result[0] != "bigint":
|
|
return False
|
|
|
|
# Check LFSObjectHistory.size
|
|
cursor.execute(
|
|
"""
|
|
SELECT data_type
|
|
FROM information_schema.columns
|
|
WHERE table_name='lfsobjecthistory' AND column_name='size'
|
|
"""
|
|
)
|
|
result = cursor.fetchone()
|
|
if not result or result[0] != "bigint":
|
|
return False
|
|
|
|
return True
|
|
else:
|
|
# SQLite uses INTEGER for both int and bigint, no distinction needed
|
|
# SQLite INTEGER can store up to 8 bytes (64-bit), so no migration needed
|
|
return True
|
|
except Exception:
|
|
# Error = treat as applied (safe fallback)
|
|
return True
|
|
|
|
|
|
def migrate_postgres():
|
|
"""Change size fields to BIGINT in PostgreSQL."""
|
|
cursor = db.cursor()
|
|
|
|
print("Changing size fields from INTEGER to BIGINT...")
|
|
|
|
# File.size
|
|
print(" 1. File.size...")
|
|
try:
|
|
cursor.execute("ALTER TABLE file ALTER COLUMN size TYPE BIGINT")
|
|
print(" ✓ Changed File.size to BIGINT")
|
|
except Exception as e:
|
|
if "does not exist" in str(e).lower():
|
|
print(f" - Table/column doesn't exist: {e}")
|
|
else:
|
|
raise
|
|
|
|
# StagingUpload.size
|
|
print(" 2. StagingUpload.size...")
|
|
try:
|
|
cursor.execute("ALTER TABLE stagingupload ALTER COLUMN size TYPE BIGINT")
|
|
print(" ✓ Changed StagingUpload.size to BIGINT")
|
|
except Exception as e:
|
|
if "does not exist" in str(e).lower():
|
|
print(f" - Table/column doesn't exist: {e}")
|
|
else:
|
|
raise
|
|
|
|
# LFSObjectHistory.size
|
|
print(" 3. LFSObjectHistory.size...")
|
|
try:
|
|
cursor.execute("ALTER TABLE lfsobjecthistory ALTER COLUMN size TYPE BIGINT")
|
|
print(" ✓ Changed LFSObjectHistory.size to BIGINT")
|
|
except Exception as e:
|
|
if "does not exist" in str(e).lower():
|
|
print(f" - Table/column doesn't exist: {e}")
|
|
else:
|
|
raise
|
|
|
|
return True
|
|
|
|
|
|
def migrate_sqlite():
|
|
"""No migration needed for SQLite.
|
|
|
|
SQLite INTEGER can store up to 8 bytes (64-bit signed), which is
|
|
equivalent to BIGINT. No schema change is needed.
|
|
"""
|
|
print("SQLite migration not needed:")
|
|
print(" SQLite INTEGER already supports 64-bit values (same as BIGINT)")
|
|
print(
|
|
" ✓ All size fields can already store values up to 9,223,372,036,854,775,807"
|
|
)
|
|
return True
|
|
|
|
|
|
def run():
|
|
"""Run this migration.
|
|
|
|
Returns:
|
|
True if successful, False otherwise
|
|
"""
|
|
db.connect(reuse_if_open=True)
|
|
|
|
try:
|
|
# Check if should skip due to future migrations
|
|
if should_skip_due_to_future_migrations(MIGRATION_NUMBER, db, cfg):
|
|
print("Migration 013: Skipped (superseded by future migration)")
|
|
return True
|
|
|
|
# Check if tables exist
|
|
required_tables = ["file", "stagingupload", "lfsobjecthistory"]
|
|
for table_name in required_tables:
|
|
if not check_table_exists(db, table_name):
|
|
print(f"Migration 013: Skipped ({table_name} table doesn't exist yet)")
|
|
return True
|
|
|
|
# Check if already applied
|
|
if is_applied(db, cfg):
|
|
print("Migration 013: Already applied (all size fields are BIGINT)")
|
|
return True
|
|
|
|
print("=" * 70)
|
|
print("Migration 013: Change size fields to BIGINT")
|
|
print("=" * 70)
|
|
|
|
# Run migration in transaction
|
|
with db.atomic():
|
|
if cfg.app.db_backend == "postgres":
|
|
result = migrate_postgres()
|
|
else:
|
|
result = migrate_sqlite()
|
|
|
|
if result:
|
|
print("\n" + "=" * 70)
|
|
print("Migration 013: ✓ Completed Successfully")
|
|
print("=" * 70)
|
|
print("\nSummary:")
|
|
print(" • File.size: INTEGER → BIGINT")
|
|
print(" • StagingUpload.size: INTEGER → BIGINT")
|
|
print(" • LFSObjectHistory.size: INTEGER → BIGINT")
|
|
print("\nFiles larger than 2GB can now be stored without errors.")
|
|
|
|
return result
|
|
|
|
except Exception as e:
|
|
print(f"\nMigration 013: ✗ Failed - {e}")
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
success = run()
|
|
sys.exit(0 if success else 1)
|