Developer & Tech
Writing Regex and SQL With AI Without Getting Burned
By Jim Vernon, Editor, AI Intelligence International · Published 31 March 2026 · Reviewed against our editorial standards · About the author
Regular expressions and SQL share an awkward property: generation is very good at both, and human verification by reading is very bad at both. A subtly wrong pattern or query looks identical to a correct one.
This article covers the verification steps that make generated regex and SQL safe to use, and the specific failure modes worth knowing.
Key takeaways
- Never verify a regex by reading it: Reading a non-trivial pattern and concluding it is correct is unreliable even for experienced developers.
- Regex failure modes worth knowing: Catastrophic backtracking: nested quantifiers that run in exponential time on certain inputs.
- SQL: correctness and cost are separate checks: A generated query can return exactly the right rows and take four minutes doing it.
- The joins and nulls problem: The most common generated SQL error is a join that silently drops or duplicates rows — an inner join where a left join was needed, or a one-to-many join inflating an aggregate.
Never verify a regex by reading it
Reading a non-trivial pattern and concluding it is correct is unreliable even for experienced developers. The only real verification is running it against cases.
Write the cases before generating: five that must match, five that must not, and three edge cases you are unsure about. Then test.
The must-not cases are the ones people skip and the ones that catch over-permissive patterns.
Regex failure modes worth knowing
Catastrophic backtracking: nested quantifiers that run in exponential time on certain inputs. Generated patterns contain these regularly and they only manifest under adversarial or unlucky input.
Unanchored patterns that match a substring when you wanted the whole string — a frequent source of validation holes.
Character class assumptions that break on non-ASCII input, which is nearly always a bug in anything handling real user data.
SQL: correctness and cost are separate checks
A generated query can return exactly the right rows and take four minutes doing it. Both need checking and they are different activities.
Read the execution plan for anything that will run in production. Sequential scans on large tables and unexpected nested loops are the usual findings.
Test on realistic data volumes. A query that is instant on a thousand rows tells you nothing about its behaviour on ten million.
The joins and nulls problem
The most common generated SQL error is a join that silently drops or duplicates rows — an inner join where a left join was needed, or a one-to-many join inflating an aggregate.
Check row counts before and after every join while developing. A count that changes unexpectedly is the entire bug, visible in seconds.
Null handling in aggregates and comparisons is the second most common. Generated queries frequently assume no nulls in columns that permit them.
Never interpolate, always parameterise
Generated SQL embedded in application code sometimes builds strings with user input. This is the classic injection vulnerability and it still appears regularly.
Require parameterised queries without exception, and treat any generated string concatenation into SQL as an automatic rejection in review.
The same applies to dynamic identifiers. If a table or column name comes from input, it must be validated against an allowlist, never interpolated.
Destructive statements need a rehearsal
Any generated UPDATE or DELETE should first be run as a SELECT with the identical WHERE clause, and the row count checked against expectation.
Wrap in a transaction and inspect before committing where your database supports it.
This costs thirty seconds and is the difference between a mistake and an incident. It is the single highest-value habit in this article.
Worked example: two generated artefacts
A validation regex for internal reference codes. Read as correct by two people. Testing against the must-not list showed it matched any string containing a valid code, because it was unanchored — so a pasted sentence passed validation.
A reporting query joining orders, customers and line items. Returned plausible revenue figures that were roughly forty per cent too high.
Row counting at each join step found it immediately: the line-items join multiplied order rows, and the sum over the joined set double-counted order-level shipping.
Both defects took under five minutes to find with the right check and would have been invisible to any amount of careful reading.
A worked example: the query that was almost right
A generated query to count active users joined the events table and filtered on a status column. It ran, returned a plausible number, and was wrong: the join multiplied rows for users with several events, and the count was inflated by roughly a third.
The bug survived because the output looked reasonable. The check that caught it was trivial — run the same query against a five-row fixture where the correct answer is known by hand.
Make that fixture step routine for anything that will inform a decision. Generated SQL is best treated as a first draft by a fast colleague who has never seen your schema.
Safety rails that take a minute each
For SQL: read the query aloud in plain English before running it, execute against a read replica or a limited role, wrap anything destructive in a transaction you can roll back, and always check the row count against a rough expectation.
For regex: ask for the expression plus an explanation of each group, then test it against a list that deliberately includes near-misses and empty input. Watch for nested quantifiers, which are the usual source of catastrophic backtracking on hostile input.
Never paste production data into a prompt to illustrate a pattern. Describe the shape of the data, or use invented rows with the same structure.
Frequently asked questions
How do I test a regex quickly?
Keep a list of must-match and must-not-match strings and run them programmatically rather than in a browser tool. Making it a unit test means the pattern stays correct when someone edits it later.
What is catastrophic backtracking?
A pattern structure — typically nested or adjacent quantifiers over overlapping character sets — that makes matching time grow exponentially with input length. It can hang a process on a single crafted string.
Is generated SQL safe to run in production?
After reading the execution plan, testing on realistic volumes, and rehearsing any destructive statement as a SELECT first. Without those steps, no.
Why do generated aggregates come out too high?
Almost always a one-to-many join inflating rows before the aggregate. Counting rows at each join stage during development finds it immediately.
Is generated SQL safe against injection?
Not inherently. Insist on parameterised queries and reject any generated code that concatenates user input into a statement.