-
-
Notifications
You must be signed in to change notification settings - Fork 65
✨ add MySQL table prefix option #158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThe pull request adds configurable MySQL table prefix support. A new validated CLI option passes a prefix into the transporter; the transporter validates and stores it, and all generated MySQL table identifiers (creation, truncation, indexes, foreign keys, data transfer) are adjusted to use the prefix with length-safe trimming. Changes
Sequence DiagramsequenceDiagram
participant User as User
participant CLI as CLI handler
participant Validator as Prefix validator
participant Transporter as SQLite3toMySQL
participant SQLGen as SQL generator
User->>CLI: run with --mysql-table-prefix "pre_"
CLI->>Validator: validate("pre_")
alt valid
Validator-->>CLI: "pre_"
CLI->>Transporter: init(..., mysql_table_prefix="pre_")
Transporter->>Transporter: store & validate prefix
Transporter->>SQLGen: transfer(table="users")
SQLGen->>SQLGen: use _mysql_table_name("users") -> "pre_users" (trim if needed)
SQLGen-->>Transporter: CREATE TABLE `pre_users`...
SQLGen-->>Transporter: INSERT INTO `pre_users`...
else invalid
Validator-->>CLI: raise error (click.BadParameter) -> exit non-zero
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/sqlite3_to_mysql/transporter.py (2)
69-70: Table prefix validation and helper look robust and consistentThe compiled
MYSQL_TABLE_PREFIX_PATTERN, class alias,__init__validation, and_mysql_table_name()helper together give a clean, centralised implementation of prefixing while still respecting MySQL identifier limits viasafe_identifier_length(). Thegetattrfallback for_mysql_table_prefixalso keeps tests that bypass__init__safe.Only (very) minor thought: the CLI and
ValueErrormessages differ slightly in wording; if you ever touch this again, you might consider reusing a shared constant for the human‑facing text to avoid drift, but it’s not a blocker.Also applies to: 95-95, 179-185, 352-357
1121-1218: Index DDL and error logging fully switched to prefixed table namesUsing
_mysql_table_name(table_name)in_add_index()for theALTER TABLEtarget and all related log messages keeps index creation aligned with the actual MySQL table name (including prefix) and avoids confusion when troubleshooting. The duplicate‑key retry behaviour is unchanged; the static‑analysis suggestion to uselogging.exceptionin the generic error branch would be a nice‑to‑have if you want richer tracebacks in logs.tests/unit/sqlite3_to_mysql_test.py (1)
546-565:test_transfer_applies_mysql_table_prefixexercises DML path correctlyThis test sets
_mysql_table_prefix = "pre_"on the stub and asserts that the generated INSERT SQL targetsINTO \pre_tbl`, directly validating thattransfer()now uses_mysql_table_name()for data writes. The stubbed execute side‑effect is minimal but sufficient; if you ever touch this again, you could drop the unusedparams` argument to quieten the Ruff ARG001 hint, but that’s purely cosmetic.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/sqlite3_to_mysql/cli.py(4 hunks)src/sqlite3_to_mysql/transporter.py(20 hunks)src/sqlite3_to_mysql/types.py(2 hunks)tests/unit/sqlite3_to_mysql_test.py(4 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
src/sqlite3_to_mysql/types.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Provide typed parameter/attribute structures in types.py for consumption via typing.Unpack in SQLite3toMySQL.init
Files:
src/sqlite3_to_mysql/types.py
src/sqlite3_to_mysql/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/sqlite3_to_mysql/**/*.py: Always wrap dynamic table/index/column names with safe_identifier_length(...) before emitting SQL
Use the class _logger for logging; do not print directly; respect the quiet flag for progress/INFO while always emitting errors
Files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.pysrc/sqlite3_to_mysql/transporter.py
src/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.py: Format with Black (line length 120) and isort (profile=black); adhere to Flake8’s 88-column soft cap to avoid long chained expressions on one line
Preserve and add type hints for new public interfaces
Files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.pysrc/sqlite3_to_mysql/transporter.py
src/sqlite3_to_mysql/cli.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/sqlite3_to_mysql/cli.py: Define and maintain the Click CLI in cli.py, validating mutual exclusions and implied flags for options
Make --sqlite-tables and --exclude-sqlite-tables mutually exclusive; setting either implies --without-foreign-keys
Disallow simultaneous -K (skip create) and -J (skip transfer) with an early exit and clear error message
Expose insert method choices IGNORE (default), UPDATE, and DEFAULT via CLI with clear help text
Define new CLI flags above cli() with consistent help text and error messages; maintain mutual exclusion patterns
Files:
src/sqlite3_to_mysql/cli.py
src/sqlite3_to_mysql/{cli.py,transporter.py}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
In debug mode (--debug), surface exceptions instead of swallowing them
Files:
src/sqlite3_to_mysql/cli.pysrc/sqlite3_to_mysql/transporter.py
src/sqlite3_to_mysql/transporter.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/sqlite3_to_mysql/transporter.py: Keep SQLite3toMySQL.transfer() flow: create DB (if missing) → create tables → optionally truncate → bulk insert (chunked or streamed) → then create indices → then add foreign keys
On table creation failures due to expression DEFAULTs, retry without DEFAULTs (two-pass _create_table with skip_default=True)
Initialize MySQL capability booleans (e.g., _mysql_fulltext_support, _allow_expr_defaults) early in init, and gate conditional behavior on them
Extend column type translation only in _translate_type_from_sqlite_to_mysql instead of scattering conversions
Handle DEFAULT normalization in _translate_default_for_mysql; return empty string to suppress invalid defaults
During index creation, handle duplicate names by appending numeric suffixes, unless _ignore_duplicate_keys is set to skip retries
Implement chunked transfer with cursor.fetchmany when --chunk is set; otherwise use fetchall with tqdm progress
Only add foreign keys when no table include/exclude filters are set and --without-foreign-keys is not in effect
Implement insert methods: IGNORE (default), UPDATE using ON DUPLICATE KEY UPDATE (with optional VALUES alias), and DEFAULT (no modifiers)
Expose new capability booleans from init of SQLite3toMySQL for downstream logic
Use prepared cursors (cursor(prepared=True)) and batch inserts via executemany for performance
For large transfers, prefer --chunk and preserve commit granularity in any new bulk path
Files:
src/sqlite3_to_mysql/transporter.py
tests/{unit,func}/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Place unit tests under tests/unit and functional/CLI tests under tests/func
Files:
tests/unit/sqlite3_to_mysql_test.py
tests/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Format test code with Black/isort and respect Flake8’s 88-column soft cap
Files:
tests/unit/sqlite3_to_mysql_test.py
tests/unit/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Add unit tests for new behavior, isolating pure functions
Files:
tests/unit/sqlite3_to_mysql_test.py
🧠 Learnings (20)
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/types.py : Provide typed parameter/attribute structures in types.py for consumption via typing.Unpack in SQLite3toMySQL.__init__
Applied to files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.pysrc/sqlite3_to_mysql/transporter.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/{mysql_utils.py,sqlite_utils.py} : Add new MySQL/SQLite capability checks in mysql_utils.py/sqlite_utils.py and keep them as dedicated helpers
Applied to files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.pysrc/sqlite3_to_mysql/transporter.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Extend column type translation only in _translate_type_from_sqlite_to_mysql instead of scattering conversions
Applied to files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.pysrc/sqlite3_to_mysql/transporter.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/{mysql_utils.py,sqlite_utils.py} : Centralize dialect/version feature checks, type adaptation, and identifier safety in mysql_utils.py and sqlite_utils.py; add new MySQL capability gates here
Applied to files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.pysrc/sqlite3_to_mysql/transporter.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/**/*.py : Always wrap dynamic table/index/column names with safe_identifier_length(...) before emitting SQL
Applied to files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.pysrc/sqlite3_to_mysql/transporter.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Expose new capability booleans from __init__ of SQLite3toMySQL for downstream logic
Applied to files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.pysrc/sqlite3_to_mysql/transporter.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Make --sqlite-tables and --exclude-sqlite-tables mutually exclusive; setting either implies --without-foreign-keys
Applied to files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Initialize MySQL capability booleans (e.g., _mysql_fulltext_support, _allow_expr_defaults) early in __init__, and gate conditional behavior on them
Applied to files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.pysrc/sqlite3_to_mysql/transporter.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Define new CLI flags above cli() with consistent help text and error messages; maintain mutual exclusion patterns
Applied to files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Handle DEFAULT normalization in _translate_default_for_mysql; return empty string to suppress invalid defaults
Applied to files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Implement insert methods: IGNORE (default), UPDATE using ON DUPLICATE KEY UPDATE (with optional VALUES alias), and DEFAULT (no modifiers)
Applied to files:
src/sqlite3_to_mysql/types.pysrc/sqlite3_to_mysql/cli.pysrc/sqlite3_to_mysql/transporter.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Define and maintain the Click CLI in cli.py, validating mutual exclusions and implied flags for options
Applied to files:
src/sqlite3_to_mysql/cli.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Expose insert method choices IGNORE (default), UPDATE, and DEFAULT via CLI with clear help text
Applied to files:
src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/{cli.py,transporter.py} : In debug mode (--debug), surface exceptions instead of swallowing them
Applied to files:
src/sqlite3_to_mysql/cli.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Keep SQLite3toMySQL.transfer() flow: create DB (if missing) → create tables → optionally truncate → bulk insert (chunked or streamed) → then create indices → then add foreign keys
Applied to files:
src/sqlite3_to_mysql/transporter.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Use prepared cursors (cursor(prepared=True)) and batch inserts via executemany for performance
Applied to files:
src/sqlite3_to_mysql/transporter.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : During index creation, handle duplicate names by appending numeric suffixes, unless _ignore_duplicate_keys is set to skip retries
Applied to files:
src/sqlite3_to_mysql/transporter.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : On table creation failures due to expression DEFAULTs, retry without DEFAULTs (two-pass _create_table with skip_default=True)
Applied to files:
src/sqlite3_to_mysql/transporter.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Only add foreign keys when no table include/exclude filters are set and --without-foreign-keys is not in effect
Applied to files:
src/sqlite3_to_mysql/transporter.pytests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : For large transfers, prefer --chunk and preserve commit granularity in any new bulk path
Applied to files:
tests/unit/sqlite3_to_mysql_test.py
🧬 Code graph analysis (2)
src/sqlite3_to_mysql/transporter.py (1)
src/sqlite3_to_mysql/mysql_utils.py (1)
safe_identifier_length(166-168)
tests/unit/sqlite3_to_mysql_test.py (2)
tests/conftest.py (4)
cli_runner(333-334)sqlite_database(150-187)mysql_credentials(206-232)MySQLCredentials(195-202)src/sqlite3_to_mysql/transporter.py (3)
transfer(1324-1490)_transfer_table_data(1303-1322)_add_foreign_keys(1220-1301)
🪛 Ruff (0.14.4)
src/sqlite3_to_mysql/cli.py
28-31: Avoid specifying long messages outside the exception class
(TRY003)
src/sqlite3_to_mysql/transporter.py
181-184: Avoid specifying long messages outside the exception class
(TRY003)
997-1001: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
1212-1217: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
tests/unit/sqlite3_to_mysql_test.py
95-95: Consider [*common_args, "--mysql-table-prefix", "stage_"] instead of concatenation
Replace with [*common_args, "--mysql-table-prefix", "stage_"]
(RUF005)
123-123: Consider [*common_args, "--mysql-table-prefix", "123bad"] instead of concatenation
Replace with [*common_args, "--mysql-table-prefix", "123bad"]
(RUF005)
553-553: Unused function argument: params
(ARG001)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Test (python3.9, mariadb:5.5, 1, true, 3.9)
- GitHub Check: Test (python3.9, mariadb:10.0, 1, true, 3.9)
- GitHub Check: Test (python3.14, mariadb:5.5, 1, true, 3.14)
- GitHub Check: Test (python3.10, mariadb:10.0, 1, true, 3.10)
- GitHub Check: Test (python3.10, mariadb:5.5, 1, true, 3.10)
- GitHub Check: Test (python3.12, mariadb:5.5, 1, true, 3.12)
- GitHub Check: Test (python3.13, mariadb:5.5, 1, true, 3.13)
- GitHub Check: Test (python3.11, mariadb:5.5, 1, true, 3.11)
- GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (9)
src/sqlite3_to_mysql/transporter.py (4)
899-903: Prefixed table name use in_create_tableis correct and completeUsing
mysql_table_name = self._mysql_table_name(table_name)for theCREATE TABLEstatement, the optionalrowidconstraint name, and both the invalid‑default retry and error logs keeps MySQL‑side identifiers and diagnostics aligned with the actual table names, including any prefix. No functional issues spotted here.Also applies to: 980-985, 989-1002
1004-1019: Truncate and index setup correctly honour prefixed table names
_truncate_table()now checks and truncates the prefixed MySQL table, and_add_indices()logs missing metadata against the prefixed table name. This matches the new naming semantics and still respectssafe_identifier_length()for all dynamic identifiers.Also applies to: 1021-1031, 1083-1087
1220-1301: Foreign key DDL correctly applies prefix to both child and referenced tables
_add_foreign_keys()now derivesmysql_table_nameandmysql_ref_table_namevia_mysql_table_name(), so both theALTER TABLEtarget andREFERENCESclause use the prefixed names. This preserves referential integrity when all migrated tables share a prefix, and the log messages have been updated accordingly. The shorthand‑PK resolution still uses the SQLite table name and only prefixes at the MySQL boundary, which is the right separation of concerns.
1341-1345: Data‑transfer SQL now targets prefixed tables consistentlyIn
transfer(), computingmysql_table_nameonce per table and using it in all generatedINSERT/INSERT ... ON DUPLICATE KEY UPDATEstatements and the corresponding error log ensures that data loads always go to the prefixed table, without altering the SQLite‑side selection logic. Behaviour for insert methods (IGNORE/UPDATE/DEFAULT) remains intact.Also applies to: 1409-1439, 1443-1448
src/sqlite3_to_mysql/types.py (1)
50-50: Types formysql_table_prefixare aligned with transporter usageAdding
mysql_table_prefix: t.Optional[str]toSQLite3toMySQLParamsand_mysql_table_prefix: strtoSQLite3toMySQLAttributesmatches howSQLite3toMySQL.__init__normalises the value to astr. This keeps the Unpackable parameter surface and internal state consistent, as per the typed‑params guideline.Also applies to: 79-79
src/sqlite3_to_mysql/cli.py (1)
17-18: CLI table‑prefix option is well‑integrated and reuses core validationThe
_validate_mysql_table_prefix()callback correctly sharesMYSQL_TABLE_PREFIX_PATTERNwith the transporter, returning an empty string when unset and raisingclick.BadParameterfor invalid values. The new-b/--mysql-table-prefixoption is documented clearly, threads amysql_table_prefix: strparameter intocli(), and is passed through toSQLite3toMySQL(...)using the same keyword name, so type hints and runtime wiring stay in sync.No behavioural issues spotted; the error handling and debug flag semantics are unchanged.
Also applies to: 23-32, 132-138, 172-203, 230-259
tests/unit/sqlite3_to_mysql_test.py (3)
70-98: CLI tests cover prefix propagation end‑to‑end
test_cli_mysql_table_prefix_passed_to_transporterandtest_cli_mysql_table_prefix_validationnicely assert that--mysql-table-prefixboth reaches the transporter ctor kwargs and is rejected early when invalid. This gives good confidence that the new option is wired and guarded correctly at the CLI boundary.
432-470: Transfer stub initialises_mysql_table_prefix, keeping tests forward‑compatibleInitialising
_mysql_table_prefix = ""in_make_transfer_stub()mirrors the real constructor and ensures new uses of_mysql_table_name()intransfer()behave predictably in tests that use__new__. This avoids brittle AttributeErrors while still defaulting to no prefix.
1801-1827: Foreign‑key prefix test validates child and parent table naming
test_add_foreign_keys_apply_mysql_table_prefixbuilds a lightweight instance with_mysql_table_prefix = "pre_"and verifies bothALTER TABLE \pre_child`andREFERENCES `pre_parent`appear in the emitted DDL. This directly checks that_add_foreign_keys()` applies the prefix consistently to both sides of the relationship, complementing the existing shorthand‑PK tests.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #158 +/- ##
==========================================
- Coverage 98.05% 98.01% -0.04%
==========================================
Files 8 8
Lines 1132 1160 +28
==========================================
+ Hits 1110 1137 +27
- Misses 22 23 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…es in transporter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/sqlite3_to_mysql/transporter.py (1)
1338-1476: Table prefixing breaks MySQL views created from SQLite viewsIn
transfer(), you now:
- Create and populate base tables using
mysql_table_name = self._mysql_table_name(table_name).- Later, when
not self._sqlite_views_as_tables and self._mysql_create_tables, translate SQLite views via_translate_sqlite_view_definition(view_name, sql_definition)and create them with_create_mysql_view(view_name, mysql_view_sql).However,
_translate_sqlite_view_definitiondoes not rewrite table references inside the view SQL to useself._mysql_table_name(...). With a non‑emptymysql_table_prefix, the MySQL view definition will still reference unprefixed base table names (e.g.SELECT * FROM `my_table```), while the actual tables were created as{prefix}my_table``. That means:
- Views will fail at runtime with “table does not exist” errors when queried.
- The failure is silent at migration time because view creation itself does not touch the base table.
This is a functional regression for the combination “table prefix + view replication”.
A minimal mitigation would be to explicitly skip or forbid view creation when a prefix is configured, rather than silently creating broken views. For example:
@@ def transfer(self) -> None: - if not self._sqlite_views_as_tables and self._mysql_create_tables: - views: t.List[t.Dict[str, t.Any]] = self._fetch_sqlite_master_rows(("view",), include_sql=True) - else: - views = [] + if not self._sqlite_views_as_tables and self._mysql_create_tables: + views: t.List[t.Dict[str, t.Any]] = self._fetch_sqlite_master_rows(("view",), include_sql=True) + if getattr(self, "_mysql_table_prefix", ""): + self._logger.warning( + "Skipping creation of MySQL views for SQLite views because mysql_table_prefix %r is set; " + "view definitions currently reference unprefixed table names.", + self._mysql_table_prefix, + ) + views = [] + else: + views = []Longer term, a more complete fix would be to use
sqlglotto rewriteexp.Tablenodes in the parsed view expression so that any base table whose SQLite name istis rendered asself._mysql_table_name(t)in the MySQL view definition.
🧹 Nitpick comments (5)
src/sqlite3_to_mysql/cli.py (1)
17-32: Shared table-prefix validation is correct; consider centralising the message textReusing
MYSQL_TABLE_PREFIX_PATTERNin_validate_mysql_table_prefixkeeps CLI and transporter validation aligned, and returning""for falsy values matches the default behaviour. The long error message string is duplicated here and inSQLite3toMySQL.__init__, and Ruff flags it (TRY003); you could extract a shared constant (e.g.MYSQL_TABLE_PREFIX_HELP) and reuse it for both the exception text and the CLI help for easier maintenance.src/sqlite3_to_mysql/transporter.py (4)
179-186:mysql_table_prefixnormalisation/validation covers programmatic use; message could be sharedNormalising
mysql_table_prefixto a string, validating only when truthy, and raisingValueErrorif it doesn’t matchTABLE_PREFIX_PATTERNgives the same guarantees as the CLI for non‑CLI callers, which is good.As Ruff notes (TRY003), the long error message string here duplicates the CLI message; consider hoisting a shared constant (e.g.
MYSQL_TABLE_PREFIX_ERROR) used by both thisValueErrorand the ClickBadParameterto keep messages in sync.
900-999: Prefixed table names in_create_tableare consistent; DEFAULT handling remains correctUsing
mysql_table_name = self._mysql_table_name(table_name)for theCREATE TABLEstatement and for constraint names/logging keeps the physical MySQL table name consistent with the prefix configuration.The updated DEFAULT clause condition now relies on
self._column_type_supports_default(base_type, self._allow_expr_defaults)and passesself._allow_expr_defaultsinto_format_textual_default, which aligns with the capability flags initialised in__init__. The control flow around retrying without DEFAULTs still looks correct.One minor suggestion in light of identifier limits: constraint names like
`{mysql_table_name}_rowid`can now grow longer due to the prefix. If you start seeingER_TOO_LONG_IDENTon constraint creation, you may want to wrap the constraint identifier insafe_identifier_length(...)as well.
1128-1216: Index DDL and logging correctly target the prefixed table name; considerlogging.exceptionon hard failuresUsing
mysql_table_name = self._mysql_table_name(table_name)in_add_indexensuresALTER TABLE, duplicate-key retries, and warnings/errors all reference the actual MySQL table name, which is important once a prefix is configured.Ruff’s TRY400 hint about
logging.exceptionapplies to the finalself._logger.error(...); raisebranch: switching that last error log toself._logger.exception(...)would capture the traceback automatically and can aid debugging without changing control flow.
1219-1299: Foreign key definitions and logging now use prefixed table names consistentlyIn
_add_foreign_keys, usingmysql_table_nameandmysql_ref_table_namefor theALTER TABLEandREFERENCESclauses keeps foreign key constraints aligned with the prefixed tables, and the warnings/errors now log the same names, which should help correlate with MySQL’s own diagnostics.Just like with the rowid constraint, composite constraint names (
{table}_FK_{id}_{seq}) can become quite long when a prefix is used. If you hit identifier-length errors in practice, consider wrapping the generated constraint name withsafe_identifier_length(...).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/sqlite3_to_mysql/cli.py(4 hunks)src/sqlite3_to_mysql/transporter.py(21 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
src/sqlite3_to_mysql/transporter.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/sqlite3_to_mysql/transporter.py: Keep SQLite3toMySQL.transfer() flow: create DB (if missing) → create tables → optionally truncate → bulk insert (chunked or streamed) → then create indices → then add foreign keys
On table creation failures due to expression DEFAULTs, retry without DEFAULTs (two-pass _create_table with skip_default=True)
Initialize MySQL capability booleans (e.g., _mysql_fulltext_support, _allow_expr_defaults) early in init, and gate conditional behavior on them
Extend column type translation only in _translate_type_from_sqlite_to_mysql instead of scattering conversions
Handle DEFAULT normalization in _translate_default_for_mysql; return empty string to suppress invalid defaults
During index creation, handle duplicate names by appending numeric suffixes, unless _ignore_duplicate_keys is set to skip retries
Implement chunked transfer with cursor.fetchmany when --chunk is set; otherwise use fetchall with tqdm progress
Only add foreign keys when no table include/exclude filters are set and --without-foreign-keys is not in effect
Implement insert methods: IGNORE (default), UPDATE using ON DUPLICATE KEY UPDATE (with optional VALUES alias), and DEFAULT (no modifiers)
Expose new capability booleans from init of SQLite3toMySQL for downstream logic
Use prepared cursors (cursor(prepared=True)) and batch inserts via executemany for performance
For large transfers, prefer --chunk and preserve commit granularity in any new bulk path
Files:
src/sqlite3_to_mysql/transporter.py
src/sqlite3_to_mysql/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/sqlite3_to_mysql/**/*.py: Always wrap dynamic table/index/column names with safe_identifier_length(...) before emitting SQL
Use the class _logger for logging; do not print directly; respect the quiet flag for progress/INFO while always emitting errors
Files:
src/sqlite3_to_mysql/transporter.pysrc/sqlite3_to_mysql/cli.py
src/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.py: Format with Black (line length 120) and isort (profile=black); adhere to Flake8’s 88-column soft cap to avoid long chained expressions on one line
Preserve and add type hints for new public interfaces
Files:
src/sqlite3_to_mysql/transporter.pysrc/sqlite3_to_mysql/cli.py
src/sqlite3_to_mysql/{cli.py,transporter.py}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
In debug mode (--debug), surface exceptions instead of swallowing them
Files:
src/sqlite3_to_mysql/transporter.pysrc/sqlite3_to_mysql/cli.py
src/sqlite3_to_mysql/cli.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/sqlite3_to_mysql/cli.py: Define and maintain the Click CLI in cli.py, validating mutual exclusions and implied flags for options
Make --sqlite-tables and --exclude-sqlite-tables mutually exclusive; setting either implies --without-foreign-keys
Disallow simultaneous -K (skip create) and -J (skip transfer) with an early exit and clear error message
Expose insert method choices IGNORE (default), UPDATE, and DEFAULT via CLI with clear help text
Define new CLI flags above cli() with consistent help text and error messages; maintain mutual exclusion patterns
Files:
src/sqlite3_to_mysql/cli.py
🧠 Learnings (18)
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/**/*.py : Always wrap dynamic table/index/column names with safe_identifier_length(...) before emitting SQL
Applied to files:
src/sqlite3_to_mysql/transporter.pysrc/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Initialize MySQL capability booleans (e.g., _mysql_fulltext_support, _allow_expr_defaults) early in __init__, and gate conditional behavior on them
Applied to files:
src/sqlite3_to_mysql/transporter.pysrc/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/{mysql_utils.py,sqlite_utils.py} : Centralize dialect/version feature checks, type adaptation, and identifier safety in mysql_utils.py and sqlite_utils.py; add new MySQL capability gates here
Applied to files:
src/sqlite3_to_mysql/transporter.pysrc/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/{mysql_utils.py,sqlite_utils.py} : Add new MySQL/SQLite capability checks in mysql_utils.py/sqlite_utils.py and keep them as dedicated helpers
Applied to files:
src/sqlite3_to_mysql/transporter.pysrc/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Expose new capability booleans from __init__ of SQLite3toMySQL for downstream logic
Applied to files:
src/sqlite3_to_mysql/transporter.pysrc/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Extend column type translation only in _translate_type_from_sqlite_to_mysql instead of scattering conversions
Applied to files:
src/sqlite3_to_mysql/transporter.pysrc/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Keep SQLite3toMySQL.transfer() flow: create DB (if missing) → create tables → optionally truncate → bulk insert (chunked or streamed) → then create indices → then add foreign keys
Applied to files:
src/sqlite3_to_mysql/transporter.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Implement insert methods: IGNORE (default), UPDATE using ON DUPLICATE KEY UPDATE (with optional VALUES alias), and DEFAULT (no modifiers)
Applied to files:
src/sqlite3_to_mysql/transporter.pysrc/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Handle DEFAULT normalization in _translate_default_for_mysql; return empty string to suppress invalid defaults
Applied to files:
src/sqlite3_to_mysql/transporter.pysrc/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : On table creation failures due to expression DEFAULTs, retry without DEFAULTs (two-pass _create_table with skip_default=True)
Applied to files:
src/sqlite3_to_mysql/transporter.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/types.py : Provide typed parameter/attribute structures in types.py for consumption via typing.Unpack in SQLite3toMySQL.__init__
Applied to files:
src/sqlite3_to_mysql/transporter.pysrc/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : During index creation, handle duplicate names by appending numeric suffixes, unless _ignore_duplicate_keys is set to skip retries
Applied to files:
src/sqlite3_to_mysql/transporter.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Only add foreign keys when no table include/exclude filters are set and --without-foreign-keys is not in effect
Applied to files:
src/sqlite3_to_mysql/transporter.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Define new CLI flags above cli() with consistent help text and error messages; maintain mutual exclusion patterns
Applied to files:
src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Define and maintain the Click CLI in cli.py, validating mutual exclusions and implied flags for options
Applied to files:
src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Make --sqlite-tables and --exclude-sqlite-tables mutually exclusive; setting either implies --without-foreign-keys
Applied to files:
src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Expose insert method choices IGNORE (default), UPDATE, and DEFAULT via CLI with clear help text
Applied to files:
src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/{cli.py,transporter.py} : In debug mode (--debug), surface exceptions instead of swallowing them
Applied to files:
src/sqlite3_to_mysql/cli.py
🧬 Code graph analysis (1)
src/sqlite3_to_mysql/transporter.py (1)
src/sqlite3_to_mysql/mysql_utils.py (1)
safe_identifier_length(166-168)
🪛 Ruff (0.14.4)
src/sqlite3_to_mysql/transporter.py
181-184: Avoid specifying long messages outside the exception class
(TRY003)
995-999: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
1210-1215: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
src/sqlite3_to_mysql/cli.py
28-31: Avoid specifying long messages outside the exception class
(TRY003)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Test (python3.10, mariadb:10.0, 1, true, 3.10)
- GitHub Check: Test (python3.13, mariadb:5.5, 1, true, 3.13)
- GitHub Check: Test (python3.9, mariadb:10.0, 1, true, 3.9)
- GitHub Check: Test (python3.12, mariadb:5.5, 1, true, 3.12)
- GitHub Check: Test (python3.14, mariadb:5.5, 1, true, 3.14)
- GitHub Check: Test (python3.11, mariadb:5.5, 1, true, 3.11)
- GitHub Check: Test (python3.9, mariadb:5.5, 1, true, 3.9)
- GitHub Check: Test (python3.10, mariadb:5.5, 1, true, 3.10)
- GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (7)
src/sqlite3_to_mysql/cli.py (3)
132-139: New--mysql-table-prefixoption is wired cleanlyThe
-b/--mysql-table-prefixoption with a default of""and the callback is consistent with existing options, and the help text accurately documents the regex constraints and length limit. There are no mutual-exclusion clashes with other flags.
173-204: CLI signature update formysql_table_prefixkeeps type hints consistentAdding
mysql_table_prefix: strto thecliparameters matches the callback’s return type and keeps the signature explicit and typed. No issues from a Click or typing perspective.
231-260: Propagation ofmysql_table_prefixintoSQLite3toMySQLlooks correct, but suffix from issue #155 remains unimplementedPassing
mysql_table_prefix=mysql_table_prefixintoSQLite3toMySQLintegrates the new option into the transport layer cleanly, and the parameter ordering is consistent with the attributes structure.One thing to double-check against the linked issue: #155 mentions both a prefix and a suffix for converted table names. This PR implements only the prefix path; if suffix support is still planned, you might want to mirror this CLI wiring for a
--mysql-table-suffixflag in a follow‑up.src/sqlite3_to_mysql/transporter.py (4)
69-96: Centralising the table-prefix regex is a solid choiceDefining
MYSQL_TABLE_PREFIX_PATTERNonce at module level and exposing it viaTABLE_PREFIX_PATTERNon the class avoids divergent rules between CLI and transporter. The regex itself enforces the documented constraints (leading letter, alphanumeric/underscore, ≤32 chars) and is straightforward to follow.
352-357:_mysql_table_nameencapsulates prefixing and length limiting cleanlyEncapsulating prefix application and
safe_identifier_lengthin_mysql_table_nameis a nice way to keep call sites simple and ensure MySQL’s identifier length limit is respected. Usinggetattrwith a default guards against tests or partial construction using mocks.
1003-1017: Table truncation correctly honours the prefixed table name
_truncate_tablenow usesself._mysql_table_name(table_name)both in theINFORMATION_SCHEMA.TABLESlookup and theTRUNCATE TABLEstatement, and logs against the same name. This keeps truncation in sync with how tables are created.
1019-1085: Index metadata still uses SQLite names, but operations/logging reference the prefixed MySQL tableThe added
mysql_table_namevariable is used only for logging in the warning path, while index creation is delegated to_add_index, which re-computes the prefixed table name internally. That separation is fine: SQLite metadata uses original names, and MySQL DDL/logging use the prefixed ones.
This pull request adds support for specifying a prefix to prepend to all MySQL table names during SQLite-to-MySQL migrations. It introduces a new CLI option for the table prefix, validates the prefix format, and ensures that all table, index, and foreign key references throughout the migration process consistently use the prefixed names.
Key changes include:
CLI and Validation Enhancements:
--mysql-table-prefix(or-b) that allows users to specify a prefix for all MySQL table names. The prefix is validated to ensure it starts with a letter, contains only letters, numbers, or underscores, and is at most 32 characters long. [1] [2] [3]Core Migration Logic Updates:
SQLite3toMySQLclass to store and validate the table prefix, and introduced a_mysql_table_namemethod to generate prefixed table names. All relevant internal methods now use this method to ensure consistent naming. [1] [2] [3] [4]Table and Index Handling:
Foreign Key and Reference Consistency:
Data Transfer Adjustments:
Fixes #155