The Classroom Mismatch
Every developer's best projects begin with a moment of genuine, personal frustration. Not a manufactured problem statement written for a hackathon submission — a real one, something that hits you in the middle of a classroom and makes you think: why is this so broken? For Sayan Dutta, that moment arrived during a database lecture in his first semester at IIT Patna.
The story actually starts earlier. Back during the Diploma years in Kolkata — and even further, in the pandemic self-study phase in Beldanga — Sayan had taught himself MySQL. It was the obvious starting point: free, well-documented, universally recommended for beginners, with thousands of tutorials. He had built functional projects using it — the Pathology Admin Panel ran on MySQL. He knew the syntax. He was comfortable. He had a mental model of how databases worked, and that model was shaped entirely by MySQL's conventions.
Then he walked into a classroom at IIT Patna and the professor opened a session on Oracle Database.
VARCHAR(255) and INT are the everyday tools. In Oracle, the same column might need VARCHAR2 — a type that doesn't exist in MySQL. AUTO_INCREMENT in MySQL becomes a SEQUENCE + TRIGGER dance in Oracle. Date handling is completely different. String concatenation works differently. Even semicolons behave differently in SQL*Plus. Everything Sayan knew was suddenly wrong in a new context.This was not a small adjustment. It felt like being told that everything you had learned about driving was valid — except the steering wheel is now on the opposite side, the pedals are swapped, and half the road signs mean different things. The knowledge was real. But the environment had shifted underneath it without warning.
I knew SQL. Then I walked into Oracle class and I didn't know anything anymore.
— Sayan Dutta, on the moment TerSQL was bornThe Exploration Spiral
A less curious student would have simply learned Oracle alongside MySQL, memorised the differences, and moved on. Sayan did something more dangerous: he started asking why. Why did these databases make different choices? What was each one actually optimised for? What else was out there?
The exploration that followed was not structured. It was the kind of rabbit-hole diving that happens when a naturally curious engineer gets unsettled — opening tabs at 11pm, following one concept to another, reading documentation for databases he had never touched before. And that path eventually led him to MongoDB.
MongoDB was a different species entirely. No tables. No rows. No JOIN.
Instead: collections, documents, BSON — a JSON-like structure where
each record could have a completely different shape. Sayan spent several evenings
poking at it, running queries in the Mongo shell, understanding the document model.
It was intellectually exciting. But it also meant learning yet another query language —
db.collection.find() instead of SELECT * FROM. Another
syntax. Another mental model. Another set of conventions to unlearn and relearn.
The discovery loop continued. PostgreSQL came next — a relational database like MySQL but with stronger typing, richer extension support, better standards compliance, and a development community that treated it as the "serious" open-source alternative. Sayan tested it, connected to it, ran queries. And immediately ran into the same wall as Oracle: subtly different syntax, different type names, different behaviours for edge cases he had already mentally resolved using MySQL conventions.
LIMIT in MySQL became FETCH FIRST n ROWS ONLY in Oracle.
GROUP_CONCAT in MySQL became STRING_AGG in PostgreSQL.
Boolean literals that worked in one system didn't in another.
The deeper he went, the more fragmented the landscape looked.
| Operation | MySQL | Oracle | PostgreSQL | MongoDB |
|---|---|---|---|---|
| Auto-increment ID | AUTO_INCREMENT |
SEQUENCE + TRIGGER |
SERIAL / GENERATED |
ObjectId (auto) |
| String type | VARCHAR(n) |
VARCHAR2(n) |
VARCHAR(n) |
String (schema-free) |
| Limit rows | LIMIT n |
FETCH FIRST n ROWS |
LIMIT n |
.limit(n) |
| Concat strings | CONCAT(a, b) |
a || b |
a || b or CONCAT |
$concat: [a, b] |
| Current timestamp | NOW() |
SYSDATE |
NOW() |
new Date() |
| Query style | SQL | SQL (PL/SQL) | SQL (PL/pgSQL) | Document API / MQL |
The Real Question
By the time Sayan had put meaningful time into MySQL, Oracle, MongoDB, and PostgreSQL, a specific frustration had crystallised into a specific question. Not just "why are these different?" — that had a known answer: history, design philosophy, vendor decisions. The question that mattered was sharper: how many different database syntaxes should a second-year CS student be expected to carry in their head at once?
Think about what that actually means in practice. A student in a typical Indian engineering curriculum encounters MySQL in their web development course, Oracle in their formal DBMS course (often the university standard), and MongoDB in any modern full-stack or cloud elective. That's three different query languages, three different connection patterns, three different error messages, and three different ways to think about the same fundamental operation: store data, retrieve data, update data.
The obvious naive solution — "just build a new database" — was immediately ruled out. The market already had hundreds of databases. Adding another would not just fail to solve the problem, it would become part of it. Nobody would switch to a brand-new, untested database built by a student just to get a unified interface. The existing systems — MySQL, PostgreSQL, MongoDB — had real ecosystems, real production deployments, real community trust built over decades. Competing with them was not the answer.
The answer had to be different. Not a replacement for existing databases — but a unified layer on top of them. Something that let you connect to whichever database your project, your professor, or your client required, and interact with it using a consistent, intuitive interface. You bring your database. TerSQL brings the experience.
Don't replace the databases. Replace the friction between them.
— the design philosophy behind TerSQLThe NLP Decision
Centralising the connection layer was the first half of the architecture. But there was a second problem that needed solving — one that lived even one level above the syntax: intent. When a developer types "show me all users", they don't want to think about whether they're connected to MySQL or PostgreSQL. They want to see the data. The translation from human intent to valid SQL should not be the developer's burden.
The market's answer to this problem in 2024–2025 was AI. ChatGPT. Claude. Gemini. Dozens of SQL AI tools had emerged, all promising to translate natural language into database queries. Sayan evaluated them carefully — and found the same fundamental flaw in every one: they required an external API call. Your query left your machine. Your schema details got sent to a cloud server. A student in a college lab querying a local MySQL instance had to pipe their database structure through the internet to get an AI response, then wait for the round trip.
The offline NLP engine in TerSQL is built on a layered regex-to-SQL rule system inside
Core.py and NLP.py. Common developer shorthands — the kinds
of things you'd type in frustration without looking up syntax — get mapped to valid
SQL automatically. "show table" becomes SHOW TABLES;
"select * users" becomes SELECT * FROM users;
"desc orders" becomes DESCRIBE orders;
These are not guesses. They are deterministic rules, compiled from the actual patterns
of how developers abbreviate SQL when they're thinking faster than they're typing.
# Deterministic regex-to-SQL translation rules # No external API. No latency. No cost. Runs fully offline. SQL_FIXES = { # Common abbreviations developers actually type r"^show\s+database[s]?;?$": "SHOW DATABASES;", r"^show\s+table[s]?;?$": "SHOW TABLES;", r"^desc\s+([^;\s]+);?$": r"DESCRIBE \1;", r"^select\s+\*\s+([^;\s]+);?$": r"SELECT * FROM \1;", r"^select\s+from\s+([^;\s]+);?$": r"SELECT * FROM \1;", r"^truncate\s+([^;\s]+);?$": r"TRUNCATE \1;", # Natural language shorthands r"^show\s+me\s+(.+)$": r"SELECT * FROM \1;", r"^list\s+(.+)$": r"SELECT * FROM \1;", r"^count\s+(.+)$": r"SELECT COUNT(*) FROM \1;", } def apply_nlp(raw: str) -> str: cleaned = raw.strip().lower() for pattern, replacement in SQL_FIXES.items(): if re.match(pattern, cleaned, re.IGNORECASE): return re.sub(pattern, replacement, cleaned, flags=re.IGNORECASE) return raw # pass through unchanged if no rule matches
The decision to keep NLP entirely local was not just a technical choice — it was a statement about what TerSQL was for. This was not a product for engineers at funded startups with API budgets. It was for students in college labs, developers in offline environments, and anyone who needed database access to be fast, private, and free. The constraint became the feature.
Why TerSQL Uses No LLM API
This is the question people ask most when they first see TerSQL's NLP layer. The honest answer is: using an LLM API was the first thing Sayan considered — and the first thing he ruled out. Not because it was technically hard. Because it was fundamentally wrong for what TerSQL is supposed to be. Here is the full reasoning.
The diagram makes the case visually — but let's break down the three specific reasons Sayan rejected LLM APIs from TerSQL's architecture, in the order he thought through them.
When you connect TerSQL to a real database — your college project, your client's local MySQL, your company's internal PostgreSQL — that database has a schema. Table names. Column names. Relationships. Possibly even sample values if the NLP layer needs context to disambiguate.
Every tool that uses an LLM API for SQL generation has to send at least part of that schema to the LLM provider's servers as context. That means your database structure — which may contain patient names, student records, financial tables, internal project names, or proprietary business logic encoded in column naming conventions — is now visible to OpenAI, Anthropic, or Google's infrastructure. Even if those providers don't actively store or train on it today, you have no guarantee of that tomorrow. You have no visibility into what happens to that data on their end. You are trusting a third party with information that was never meant to leave your machine.
LLM APIs are billed per token. Every time you type "show me orders from last week" and the tool sends that to a cloud model along with your schema context, you are spending money. At low volumes, it feels trivial. At the scale of a developer running dozens of exploratory queries per session across weeks of development, those tokens accumulate.
More importantly: the cost provides zero additional value for the kinds
of queries TerSQL's NLP layer handles. The patterns that developers
abbreviate — show table, desc users,
select * orders — are not ambiguous. They are common, predictable,
structurally simple. You do not need a 70-billion-parameter language model to
understand that "show me users" means
SELECT * FROM users;. A well-written regex rule resolves that
in under a millisecond with perfect determinism, zero cost, and zero latency.
Paying for GPT-4 to do this is like hiring a doctor to open a door.
TerSQL was built for students. Students work in college computer labs. College computer labs frequently have unreliable internet, filtered networks, or no external connectivity at all. A database CLI that requires an API call to function is not a real offline tool — it is a cloud-dependent service wearing a terminal's clothing.
Consider the actual environments TerSQL is designed to serve: a student in a lab running a local MySQL instance during a DBMS practical. A developer on a train working on a project with no mobile signal. A sysadmin on an air-gapped production server. A backend engineer in a network zone that blocks external API calls by policy. In every one of these situations, an LLM-API-dependent tool simply stops working. The NLP layer fails. The developer is left worse off than if they had just typed raw SQL from the beginning.
The query you type to explore your data should never leave your machine. That's not a feature. That's a minimum standard.
— Sayan Dutta, on TerSQL's no-API design decisionBuilding the Architecture
With the core idea clear — a unified, NLP-powered, offline CLI over multiple real databases — the architecture needed to be modular enough to support adding new databases without rewriting the core engine. Sayan designed TerSQL around a plugin system from the beginning, knowing that MySQL, PostgreSQL, and MongoDB were just the first three.
The project is structured across four primary modules: TerSQL.py handles
the REPL loop and user input parsing. Core.py manages query processing,
safety checks, and the NLP rule engine. NLP.py contains the regex rule
tables and intent detection logic. And plugins/base.py defines the
abstract BaseDB interface that every database driver must implement.
Adding a new database — say, Redis or SQLite — means creating a single file in
plugins/ that subclasses BaseDB and implementing
four methods. The rest of TerSQL continues to work unchanged.
# The complete interface a new database driver must implement. # Four methods. That's all it takes to add a new database to TerSQL. from plugins.base import BaseDB, QueryResult, register_plugin @register_plugin("redis") class RedisPlugin(BaseDB): def connect(self, **kwargs) -> None: """Establish the database connection.""" pass def execute(self, query: str) -> QueryResult: """Execute a query and return a normalised QueryResult.""" pass def tables(self) -> list[str]: """Return a list of collections / tables / keyspaces.""" pass def schema(self, table: str) -> QueryResult: """Return the schema / structure for a given table.""" pass
The timeline from idea to v0.0.1 was compressed. Sayan was simultaneously managing IIT Patna coursework, two other team projects, and a paid freelance engagement. TerSQL was built in focused sessions — late evenings, weekend mornings — the same discipline of parallel work he had practised since the pandemic years in Beldanga. Version 0.0.1 shipped with MySQL support, the REPL, smart completion, query history, and safe mode. Version 0.0.2 added PostgreSQL and MongoDB plugins, rewrote the NLP engine, and introduced the full dot-command reference system.
What TerSQL Actually Does
TerSQL is not a toy project. It is a production-minded CLI with a deliberately comprehensive feature set — because a tool that developers actually reach for in daily work needs to handle the edge cases, not just the happy path.
What Comes Next
TerSQL at v0.0.2 is a working tool with real features and a coherent architecture. But it is genuinely early. Sayan's roadmap — built from real usage feedback and from his own continued experience using TerSQL as a daily development tool — points in several clear directions.
pip install tersql — that installs the core engine and lets users add database plugins as optional extras. This is how a developer tool becomes a community tool.The student who had four databases and no unified tool built the tool — so the next student doesn't have to choose.
— on TerSQL's founding philosophyUse TerSQL / Contribute
TerSQL is open source under the MIT license. You can clone it, use it, extend it, and contribute to it. Sayan is also available for collaboration, internship opportunities, and freelance full-stack and AI engineering work.