thinQL is a minimal execution specification for inline SQL generated by LLMs. It operates as an anti-ORM: raw SQL strings are executed without translation, query building, or hidden object mapping. The runtime provides only connection routing, execution dispatch, and deterministic result packaging. Structural alignment between SQL projections and application data types is enforced positionally at generation time, not validated or mapped at runtime.
All implementations must expose exactly six functions. No aliases, no umbrella wrappers, no dialect-specific variants.
| Function | Signature | Purpose |
|---|---|---|
use(db) |
use(context_handle) |
Binds subsequent operations to an active database connection or pool handle. |
fetch(sql, target) |
fetch(string, pointer/ref/handle) → (populated_target, error) |
Executes row-yielding statements (SELECT, etc.). Scans directly into the provided target. |
exec(sql) |
exec(string) → (metadata, error) |
Executes non-row-yielding statements (INSERT, UPDATE, DELETE, DDL, DCL). Returns fixed metadata. |
begin() |
begin() → error |
Opens an explicit transaction boundary. |
commit() |
commit() → error |
Commits active transaction. |
rollback() |
rollback() → error |
Rolls back active transaction. |
- Column declaration order in the SQL string must exactly match field declaration order in the target.
- The runtime does not inspect field names, parse struct tags, or perform name-based matching.
- Scanning is strictly positional: column 0 → field 0, column 1 → field 1, etc.
- Mismatches result in silent data corruption or driver scan failures. This is by design. Validation is out of scope.
fetchrequires a mutable target (pointer, reference, or pre-allocated handle).- The runtime constructs a positional pointer/destination array from the target's memory layout and passes it directly to the driver's native scanner.
- Multi-row results are handled by repeated allocation and appending, governed by language-specific memory conventions.
- No reflection-based type coercion is permitted. Driver type conversion rules apply directly.
- SQL
NULLmaps to the language's canonical absent value:- Go: pointer fields or
sql.NullXtypes - C:
NULLpointer or explicit validity flag per field - Lua:
nil
- Go: pointer fields or
- The runtime does not inject defaults or perform fallback conversions.
- Transactions are managed exclusively through
begin(),commit(), androllback(). - All
fetchandexeccalls route through the active transaction if one exists. - No auto-commit. No implicit session boundaries. No connection-pool transaction leasing.
begin()returns an error if a transaction is already active on the context.commit()androllback()return errors if no transaction is active.- Transaction state is tracked per context handle. Concurrency safety is implementation-defined but must prevent overlapping state mutations.
- Many databases issue implicit commits on DDL execution, terminating active transactions.
- The runtime does not intercept, warn, or override this behavior.
- This constraint is documented in the specification. LLM generation logic must account for it.
use(db)accepts*sql.DBor compatible interface.fetch(sql, target)accepts*Structor*[]Struct. Runtime usesrows.Columns()to build a[]anyslice of field addresses in declaration order, then callsrows.Scan().exec(sql)returnssql.Result+error. Callers invoke.RowsAffected()and.LastInsertId()directly.- Memory: heap-allocated results. GC handles lifecycle.
use(db)accepts opaque driver handle (sqlite3*,PGconn*, etc.).fetch(sql, target)acceptsvoid*to struct array or single struct. Runtime iterates columns by index, calls driver accessor functions (sqlite3_column_xxx,PQgetvalue), writes directly to struct memory offsets.exec(sql)returns fixed struct:typedef struct { int64_t rows_affected; int64_t last_insert_id; int status; } thinql_exec_result;
- Memory: caller-allocated buffers or runtime allocator with explicit
thinql_free()release rule. Implementation must document ownership model.
use(db)accepts connection userdata.fetch(sql, target)accepts table reference or template function. Returns array of tables keyed by positional index or LLM-defined keys. Consumed via iterator or direct loop.exec(sql)returns fixed table:{ rows_affected = n, last_id = n, status = "ok" }.- Memory: GC-managed. No manual release required.
- All functions return errors directly from the native driver.
- No wrapping, no retry logic, no semantic normalization.
- Error objects must preserve driver error codes, messages, and SQLSTATE where applicable.
execreturns a fixed, language-defined shape. No driver-specific variance is exposed.- Missing driver capabilities (e.g.,
LastInsertIdunsupported) return zero or negative sentinel values per language matrix. - No additional fields may be added without a major spec version bump.
- Schema inference, validation, or type checking
- SQL parsing, syntax highlighting, or query optimization
- Automatic relationship resolution or join generation
- Connection pooling, health checks, or failover routing
- Query parameter binding (placeholders are passed as raw SQL substrings or handled by driver conventions)
- ORM-style entity tracking, dirty checking, or cascade operations
- Guardrails, allowlists, or execution sandboxing
- Zero Abstraction Layer: The runtime must not interpret, modify, or optimize the SQL string. It is passed directly to the driver.
- Positional Scan Enforcement: Implementations must guarantee field-to-column alignment follows declaration order. Name-based matching is prohibited.
- Fixed Return Shapes:
execmetadata structures must be identical across driver backends within the same language repo. - State Isolation: Transaction state must be scoped to the context handle passed to
use(). No global or implicit transaction tracking. - Test Compliance: All implementations must pass positional scan tests, transaction state tests, and error propagation tests against at least two dialects.
- Versioning: Breaking changes to function signatures, return shapes, or scanning rules require a major version increment. Dialect-specific driver updates do not.