Overview
MySQL is one of the source dialects 3XCode's conversion pipeline recognizes natively, represented internally as the mysql value of the pipeline's SQLDialect enum, alongside tsql (SQL Server), plsql (Oracle), plpgsql (PostgreSQL), ansi (generic ANSI SQL), and spark_sql.
When you run 3xcode pyspark convert against a .sql file written in MySQL's dialect, the Discovery phase classifies it as mysql, inventories every stored procedure, function, view, and trigger it contains, and hands that inventory to Planning, which decides conversion order and pulls in only the MySQL-relevant knowledge (cursor and handler patterns, date function differences, NULL semantics, and so on) needed to convert it correctly.
How MySQL Is Detected
Detection happens in two separate layers during the Discovery phase, and neither one requires you to tell 3XCode what dialect a file is in.
Dialect Classification (LLM)
Claude reads the file during Discovery and classifies it into the SQLDialect enum, resolving to mysql for MySQL-flavored procedural SQL. A field validator normalizes variant spellings from the model's own output so classification stays consistent run to run.
Platform Fingerprinting (deterministic)
A separate, regex-only pass scores the file against syntax markers for 10 vendor platforms, including MySQL, with zero LLM cost. It returns the winning platform, a confidence label, and the exact markers that fired, so platform detection is fully explainable rather than a black box.
Every generated PySpark file gets a one-line header comment naming the detected source platform, confidence level, and matched markers, so you can always see how a given .py output was classified. Discovery also builds a full object inventory for the file: name, type, exact line range, parameters, cross-object references, and flags for cursors, dynamic SQL, and transactions, which downstream phases use to plan and convert.
What Gets Converted
The Planning phase topologically sorts discovered objects and converts them in dependency order: views and standalone functions first, then procedures, then triggers, so a procedure that references a view always sees that view's converted signature rather than a guess.
Stored Procedures
MySQL procedures (including the DELIMITER-wrapped CREATE PROCEDURE blocks and IN / OUT / INOUT parameters typical of the dialect) are converted into PySpark modules with private step/helper functions and a run_pipeline(spark, params) orchestrator that preserves the procedure's logical flow.
Views & Functions
Converted first in the dependency order, since procedures and triggers that reference them need real, converted signatures, not placeholders, to convert correctly.
Triggers
Inventoried and converted with their referenced tables and cross-object dependencies resolved, following the same Views → Functions → Procedures → Triggers precedence.
Cursors & Handlers
Detected via a has_cursor flag during Discovery (including the DECLARE ... CURSOR FOR ... / DECLARE CONTINUE HANDLER FOR NOT FOUND pattern common in MySQL procedures) and flagged for the conversion agent to rewrite as native PySpark window functions rather than row-by-row Python loops, since Python UDF loops are dramatically slower than native F.xxx operations at scale.
Known Behavioral Differences
3XCode's validation and auto-fix phases check generated PySpark against a knowledge base of known behavioral gaps. The most relevant ones for MySQL sources:
MySQL → PySpark gotchas the pipeline checks for
| Construct | Gotcha | Handling |
|---|---|---|
| Date/time functions | Date and time function names and semantics don’t map 1:1 between MySQL and PySpark. A naive translation can silently change results. | Flagged during Validation; targeted by Auto-Fix when detected. |
| Cursors | MySQL cursors (DECLARE ... CURSOR FOR ... with a NOT FOUND handler) have no direct PySpark equivalent. Row-by-row Python loops are 50–100x slower than native operations. | Discovery sets has_cursor; conversion is instructed to rewrite as window functions where possible, otherwise flagged for manual review. |
| Dynamic SQL (PREPARE / EXECUTE) | No safe automatic transform exists for dynamically constructed SQL text. | Classified as a manual-review item, never auto-fixed. |
| Transactions (START TRANSACTION / COMMIT / ROLLBACK) | MySQL transaction control has no direct PySpark equivalent. | Discovery sets has_transaction; classified as a manual-review item. |
| Upserts (INSERT ... ON DUPLICATE KEY UPDATE) | MySQL’s upsert syntax has no single native PySpark equivalent. | Classified as a manual-review item, typically rewritten as a Delta MERGE INTO or filter-and-union pattern by hand. |
| NULL semantics | COUNT(*) vs COUNT(col) and NULL ordering in ORDER BY can behave differently than in PySpark. | Checked during Validation’s NULL-semantics review. |
| String comparisons | Spark is case-sensitive by default, which can differ from MySQL’s default (often case-insensitive) collation behavior. | Checked during Validation. |
| Decimal arithmetic | Precision can be lost across certain arithmetic operations when types are mapped. | Checked during Validation; flagged as a TODO if unresolved. |
Issues the pipeline can't safely auto-fix (cursors requiring a rewrite, dynamic SQL, upsert logic, and transaction blocks) are surfaced as prioritized, developer-facing action items after conversion, each with prescriptive guidance on how to resolve it by hand.
Converting a MySQL File
No flag is needed to tell 3XCode a file is MySQL: dialect and platform are detected automatically during Discovery. Just point the pyspark agent at your file or directory:
# Convert a single MySQL script 3xcode pyspark convert stored_procs.sql # Dry-run: discovery + planning only, no conversion 3xcode pyspark analyze stored_procs.sql # Convert every .sql file in a directory (bulk mode) 3xcode pyspark convert --dir ./sql/ --session "mysql-migration" -w 4 # --session sets a name; find the actual session ID before resuming 3xcode session list # Resume an interrupted bulk session (use the ID from session list, not the --session name) 3xcode pyspark convert --resume <session-id-from-list>
After conversion, check <stem>_audit.md in your output directory for the per-file confidence/completion grade and the list of items that need manual review: cursors, dynamic SQL, and upsert logic in particular are common MySQL constructs that land there rather than being silently auto-converted.
FAQ
Do I need to specify that my file is MySQL?
No. Dialect classification and platform fingerprinting both run automatically during the Discovery phase. There is no --dialect flag to set.
Does 3XCode handle DELIMITER-wrapped procedure blocks correctly?
Yes. Discovery reads the full file, including DELIMITER $$ blocks, and inventories each procedure, function, view, and trigger with its exact line boundaries before any conversion happens.
What happens to cursors and dynamic SQL that can't be auto-converted?
They're never silently dropped or guessed at. Auto-Fix classifies them as manual-review items with a revert-on-regression safety net, and they appear in the audit report's developer action items with specific guidance on how to rewrite them by hand.
Is my MySQL source code sent to the 3XDE backend?
No. Source SQL is never sent to the 3XDE backend: the CLI talks to your configured LLM provider directly for conversion. The backend only handles auth, licensing, and provider-key metadata.