VX/SQL-MODULE - SQLMOD to Embedded SQL
Overview
VX/SQL-MODULE regenerates Oracle Rdb SQL Module Language (.sqlmod) modules as C so they run against a modern database while preserving the exact procedure-call interface. Rdb's SQL$MOD model keeps the SQL in a module and lets the host program call its procedures as ordinary external routines; VX/SQL-MODULE keeps that extern "C" interface intact, so callers written in Fortran, COBOL, C or C++ keep the same calling sequence.
The generated modules link the same back-end-neutral VX/SQL runtime as embedded SQL, so a SQLMOD-based application can target PostgreSQL, Oracle, SQL Server, MySQL/MariaDB, SQLite or any ODBC source by configuration rather than by rebuilding. Modules are emitted either as embedded SQL for the ecpg toolchain or as pure C that calls the runtime directly.
<!-- Webflow embed (min). Source: sql-module-page-technical/sqlmod-tech-body-embed-dark.html → python3 website/embeds/minify_webflow_embed.py … -->
<div class="s7-tech-embed" data-vxsqlmodd-body-embed="1" data-technical-mega-embed="1" lang="en"><h2 id="module-model">The SQL module-language model</h2><p>
SQL Module Language is one of the three ways Rdb applications embed SQL. Instead of scattering
<code>EXEC SQL</code> through the host program, the SQL lives in a separate <code>.sqlmod</code>
module: each database operation is a named <code>PROCEDURE</code> with a typed parameter list, and
the host program calls those procedures as ordinary external routines. The module is the contract
between application code and the database, and it is exactly this contract that VX/SQL-MODULE
preserves.
</p><div class="callout"><strong>Why the interface matters.</strong> Because the calling program only ever sees a set of
external procedures with a fixed signature, a migrated module can change its database back end
completely while the Fortran, COBOL, C or C++ caller keeps the same <code>CALL</code> sequence and
is not rebuilt for the interface change.
</div><h6>Module header directives</h6><p>
A module opens with a header that names it, sets the SQL dialect and host language, and declares
the database alias. VX/SQL-MODULE reads these to drive type mapping and naming in the generated
code:
</p>
<pre><span class="kw">MODULE</span> ACCT_INQUIRY_MOD
<span class="kw">DIALECT</span> SQL92
<span class="kw">LANGUAGE</span> C
<span class="kw">AUTHORIZATION</span> BANK_USER
<span class="kw">ALIAS</span> RDB$DBHANDLE
<span class="kw">PARAMETER COLONS</span>
<span class="kw">DECLARE ALIAS FOR FILENAME</span> banking_accounts
<span class="kw">PROCEDURE</span> SET_TRANS
(SQLCODE);
<span class="kw">SET TRANSACTION READ WRITE</span>;
</pre>
<p><code>DIALECT</code> selects the SQL level (SQLV40, SQL89, SQL92 or MIA) and <code>LANGUAGE</code>
selects the host-language conventions (Ada, BASIC, C, COBOL, Fortran, Pascal, PL/I or general). A
line beginning with <code>--</code> is a comment.
</p><h6>Procedures and reserved status parameters</h6><p>
Each procedure declares a parameter list that may begin with one reserved status keyword, which
becomes the way the caller reads the SQL result:
</p><div class="kw-grid"><div>SQLCODE</div><div>SQLSTATE</div><div>SQLCA</div><div>SQLDA</div><div>SQLDA2</div></div><p>
A leading <code>SQLCODE</code> becomes an <code>int *</code> out-parameter on the generated
function; every other parameter is a host variable written as <code>:name TYPE</code> and is bound
into the SQL statement. The rest of the procedure body is the SQL itself: DML, transaction control,
cursors, compound blocks, or dynamic SQL.
</p><h2 id="translation-pipeline">The SQLMOD to embedded SQL translation pipeline</h2><p>
VX/SQL-MODULE is a self-contained C++ translator (<code>vxsqlmod</code>), not a runtime service. It
reads one <code>.sqlmod</code> file and writes a C header plus one implementation file. It is a
classic front-end / back-end compiler: a lexer and parser build a module AST, and an emitter lowers
that AST to C, applying Rdb-to-target dialect rewrites along the way.
</p><div class="table-wrapper"><table><thead><tr><th>Stage</th><th>Component</th><th>Role</th></tr></thead><tbody><tr><td>Lex</td><td>Lexer</td><td>Tokenises the <code>.sqlmod</code> source and classifies keywords.</td></tr><tr><td>Parse</td><td>Parser + expression handler</td><td>Builds the <code>Module</code> AST: header, procedures, parameter lists, SQL statements, and module-scope declarations.</td></tr><tr><td>Resolve</td><td>CDD runtime bridge</td><td>Loads <code>libvxcdd</code> at run time and resolves Domain-typed and record parameters to real C typedefs through the CDD dictionary.</td></tr><tr><td>Emit</td><td>C / ESQL emitter</td><td>Emits the <code>.h</code>, the <code>.esql</code> or <code>.psql</code> body, and the <code>.pgh</code> sidecar; contains all Rdb-to-Postgres dialect rewrites.</td></tr><tr><td>Emit</td><td>Compound emitter</td><td>Lowers <code>BEGIN [ATOMIC] ... END</code> compound statements and <code>FOR ... DO</code> loops.</td></tr><tr><td>Diagnose</td><td>Diagnostics + CLI driver</td><td>Reports parse and translation errors with <code>file:line:col</code> context and owns the exit-code contract.</td></tr></tbody></table></div><h6>Compile-time flow</h6><p>
Translation runs offline, once per estate. One module in produces a header, an implementation body,
and (in embedded-SQL mode) a parameter-header sidecar:</p><style>.s7-tech-embed .sqlm-flow {margin: 1.5rem 0;padding: 16px;border: 1px solid var(--s7t-border);border-radius: 10px;background: rgba(255, 255, 255, 0.01);}.s7-tech-embed .sqlm-flow-phase,.s7-tech-embed .sqlm-flow-label {font-family: var(--s7t-mono);color: var(--s7t-accent);font-size: 0.76em;font-weight: 700;letter-spacing: 0.08em;text-transform: uppercase;}.s7-tech-embed .sqlm-flow-phase {margin: 0 0 10px;}.s7-tech-embed .sqlm-flow-chain,.s7-tech-embed .sqlm-flow-branches {display: grid;gap: 10px;}.s7-tech-embed .sqlm-flow-chain {grid-template-columns: repeat(4, minmax(0, 1fr));}.s7-tech-embed .sqlm-flow-branches {grid-template-columns: repeat(3, minmax(0, 1fr));margin-top: 10px;}.s7-tech-embed .sqlm-flow-card {min-width: 0;padding: 15px;border-top: 3px solid var(--s7t-accent);border-radius: 6px;background: var(--s7t-surface2);color: var(--s7t-text);}.s7-tech-embed .sqlm-flow-side-output {border-top-color: var(--s7t-note-bd);background: var(--s7t-note-bg);}.s7-tech-embed .sqlm-flow-card .sqlm-flow-label,.s7-tech-embed .sqlm-flow-card strong,.s7-tech-embed .sqlm-flow-card span {display: block;}.s7-tech-embed .sqlm-flow-card .sqlm-flow-label {margin-bottom: 10px;}.s7-tech-embed .sqlm-flow-card strong {margin-bottom: 4px;color: var(--s7t-text);}.s7-tech-embed .sqlm-flow-card span:not(.sqlm-flow-label) {color: var(--s7t-muted);font-size: 0.9em;line-height: 1.45;}@media (max-width: 800px) {.s7-tech-embed .sqlm-flow-chain,.s7-tech-embed .sqlm-flow-branches {grid-template-columns: 1fr;}}</style><div class="sqlm-flow" aria-label="VX/SQL-MODULE compile-time flow"><div class="sqlm-flow-phase">Compile time</div><div class="sqlm-flow-chain"><div class="sqlm-flow-card"><strong><code>module.sqlmod</code></strong><span>Input SQL module source</span></div><div class="sqlm-flow-card"><strong>Lex</strong><span>Tokenises source and classifies keywords.</span></div><div class="sqlm-flow-card"><strong>Parse and resolve</strong><span>Builds the AST and resolves CDD Domain and record types.</span></div><div class="sqlm-flow-card"><strong>Emit</strong><span>Lowers the AST into the selected C output path.</span></div></div><div class="sqlm-flow-branches" aria-label="Generated output branches"><div class="sqlm-flow-card sqlm-flow-side-output"><span class="sqlm-flow-label">Shared output</span><strong><code>module.h</code></strong><span>Header containing <code>extern "C"</code> prototypes</span></div><div class="sqlm-flow-card"><span class="sqlm-flow-label">Embedded SQL branch</span><strong><code>module.esql</code></strong><span><code>EXEC SQL</code> C passes through <code>ecpg</code>, then <code>cc</code>. This mode also emits <code>module.pgh</code>.</span></div><div class="sqlm-flow-card"><span class="sqlm-flow-label">Direct C branch</span><strong><code>module.psql</code></strong><span>Direct runtime calls pass straight to <code>cc</code>.</span></div></div></div><h6>Run-time flow</h6><p>
At run time the generated module is just linked C. The host program calls a module procedure, the
procedure binds its host variables, executes against the configured back end through the VX/SQL
runtime, and maps the result status back to an Rdb <code>SQLCODE</code> before returning:</p><div class="sqlm-flow" aria-label="VX/SQL-MODULE runtime flow"><div class="sqlm-flow-phase">Runtime</div><div class="sqlm-flow-chain"><div class="sqlm-flow-card"><strong>Host program</strong><span>Calls <code>module_proc(&sqlcode, args...)</code>.</span></div><div class="sqlm-flow-card"><strong>Generated C</strong><span>Binds the procedure's host variables.</span></div><div class="sqlm-flow-card"><strong>VX/SQL runtime</strong><span>Executes through the configured database back end.</span></div><div class="sqlm-flow-card sqlm-flow-side-output"><strong>Return to caller</strong><span>Maps result status to Rdb <code>SQLCODE</code> and returns it to the host program.</span></div></div></div><div class="callout"><strong>The translator does not link a database.</strong> <code>vxsqlmod</code> itself links no
database client; only the <em>generated</em> code links the VX/SQL runtime. The back end is chosen
when the application runs, not when the module is translated.
</div><h2 id="output-flavours">Two output flavours: direct API and embedded SQL</h2><p>
VX/SQL-MODULE offers both lowering strategies a migration might want, selected by a single flag.
Both are generated from the same <code>.sqlmod</code> source and link the same runtime, so one
flavour can validate the other.
</p><div class="table-wrapper"><table><thead><tr><th>Flavour</th><th>Flag</th><th>Body file</th><th>Toolchain</th></tr></thead><tbody><tr><td>Embedded SQL (default)</td><td><code>-m esql</code></td><td><code>.esql</code> (+ <code>.pgh</code>)</td><td>C containing <code>EXEC SQL</code>, processed by a second <code>ecpg</code> pass, then compiled.</td></tr><tr><td>Direct API</td><td><code>-m psql</code></td><td><code>.psql</code></td><td>Pure C that calls the VX/SQL runtime directly; compiled in one step with a normal C compiler and no embedded-SQL pre-compiler.</td></tr></tbody></table></div><div class="callout"><strong>Reaching Oracle.</strong> Oracle is reached through the runtime's Oracle OCI driver.
VX/SQL-MODULE does not depend on Oracle Pro*C, so the Pro*C pre-compiler toolchain is not required.
</div><h6>Direct-API output (<code>-m psql</code>)</h6><p>
Given a simple insert procedure declared in the module:</p>
<pre><span class="kw">PROCEDURE</span> INSERT_ACCOUNT
(SQLCODE,
:P_ACCOUNT_ID CHAR(5),
:P_LAST_NAME CHAR(14),
:P_FIRST_NAME CHAR(10),
:P_BALANCE INTEGER);
<span class="kw">INSERT INTO</span> ACCOUNTS (ACCOUNT_ID, LAST_NAME, FIRST_NAME, BALANCE)
<span class="kw">VALUES</span> (:P_ACCOUNT_ID, :P_LAST_NAME, :P_FIRST_NAME, :P_BALANCE);
</pre>
<p>
the direct-API emitter produces pure C. The <code>SQLCODE</code> status becomes an
<code>int *</code> out-parameter, each host variable becomes a pointer parameter, Rdb
<code>:name</code> placeholders are rewritten to positional <code>$1, $2, ...</code>, and the
statement runs through the runtime's <code>S7ESQL*</code> calls:
</p>
<pre>int INSERT_ACCOUNT(
int *_sqlcode,
char *_P_ACCOUNT_ID, char *_P_LAST_NAME,
char *_P_FIRST_NAME, int *_P_BALANCE)
{
char P_ACCOUNT_ID[5], P_LAST_NAME[14], P_FIRST_NAME[10];
int P_BALANCE;
memcpy(P_ACCOUNT_ID, _P_ACCOUNT_ID, sizeof(P_ACCOUNT_ID));
<span class="cmt">/* ... copy remaining host vars ... */</span>
P_BALANCE = *_P_BALANCE;
struct sqlca_t sqlca = sqlmod_sqlca_init;
S7ESQLStartSQL();
S7ESQLSetSQLParams(SQLMOD_HVAR_ALPHANUMERIC, (int)sizeof(P_ACCOUNT_ID), 0, 0u, (void*)P_ACCOUNT_ID, NULL);
<span class="cmt">/* ... bind remaining params ... */</span>
S7ESQLSetSQLParams(SQLMOD_HVAR_SIGNED_BINARY, (int)sizeof(P_BALANCE), 0, 0u, (void*)&P_BALANCE, NULL);
S7ESQLExecParams(&sqlca, NULL, 0,
(char*)"INSERT INTO ACCOUNTS (ACCOUNT_ID, LAST_NAME, FIRST_NAME, BALANCE) VALUES ($1,$2,$3,$4)", 4);
S7ESQLEndSQL();
*_sqlcode = vxrt_postgres_to_rdb(sqlca.sqlcode);
return *_sqlcode;
}
</pre>
<h6>Embedded-SQL output (<code>-m esql</code>)</h6><p>
The same procedure lowered as embedded SQL keeps the statement readable and preserves the
<code>:name</code> host-variable references, wrapped in an <code>EXEC SQL</code> declare section for
<code>ecpg</code>:</p>
<pre>int INSERT_ACCOUNT(int *_sqlcode, char *_P_ACCOUNT_ID, <span class="cmt">/* ... */</span>)
{
EXEC SQL BEGIN DECLARE SECTION;
char P_ACCOUNT_ID[5];
<span class="cmt">/* ... remaining host vars ... */</span>
int P_BALANCE;
EXEC SQL END DECLARE SECTION;
memcpy(P_ACCOUNT_ID, _P_ACCOUNT_ID, sizeof(P_ACCOUNT_ID));
<span class="cmt">/* ... copy remaining host vars ... */</span>
EXEC SQL
INSERT INTO ACCOUNTS (ACCOUNT_ID, LAST_NAME, FIRST_NAME, BALANCE)
VALUES (:P_ACCOUNT_ID, :P_LAST_NAME, :P_FIRST_NAME, :P_BALANCE);
*_sqlcode = vxrt_postgres_to_rdb(sqlca.sqlcode);
return *_sqlcode;
}
</pre>
<p>
Both flavours end each procedure with the identical <code>vxrt_postgres_to_rdb(sqlca.sqlcode)</code>
status-mapping tail. That shared tail is what "same runtime, one flavour validates the other" means
in practice: the two outputs are behaviourally equivalent by construction.
</p><h2 id="parameter-mapping">Procedure and host-parameter mapping</h2><p>
The core of the translation is turning a SQLMOD procedure signature into a C function signature that
callers can link unchanged, and binding each host variable to the SQL statement with the right type
handling. VX/SQL-MODULE maps the full range of Rdb SQLMOD parameter types, not just the common
scalars.
</p><h6>Host-variable and column data types</h6><div class="table-wrapper"><table><thead><tr><th>Group</th><th>Types handled</th></tr></thead><tbody><tr><td>Numeric</td><td><code>TINYINT</code>, <code>SMALLINT</code>, <code>INTEGER</code>, <code>BIGINT</code>, <code>REAL</code>, <code>FLOAT</code>, <code>DOUBLE PRECISION</code>, <code>DECIMAL</code>, <code>NUMERIC</code></td></tr><tr><td>Character</td><td><code>CHAR</code>, <code>VARCHAR</code>, <code>LONG VARCHAR</code>, <code>NCHAR</code>, <code>NCHAR VARYING</code></td></tr><tr><td>Date / time</td><td><code>DATE ANSI</code>, <code>DATE VMS</code>, <code>DATE</code>, <code>TIME</code>, <code>TIMESTAMP</code>, <code>INTERVAL</code></td></tr><tr><td>Large / structured</td><td><code>LIST OF BYTE VARYING</code>, <code>Domain</code> (resolved through CDD)</td></tr></tbody></table></div><p>
Types that do not exist natively on the target are mapped to the nearest standard form: for example
Rdb <code>TINYINT</code> is promoted to <code>SMALLINT</code> where the back end has no one-byte
integer, and fields whose type varies by context are carried as raw bytes so no data is lost.
</p><h6>CDD record parameters</h6><p>
A <code>RECORD ... END RECORD</code> parameter, optionally sourced from a CDD dictionary path,
becomes a C struct and is bound field by field, so a <code>SELECT ... INTO :record</code> populates
every column. Domain-typed parameters resolve through CDD to real C typedefs, and VMS CDD data-type
definitions can be extracted into C headers so the generated code matches the canonical record
layout. Without CDD resolution, Domains fall back to an opaque pointer and individual fields are not
reachable, so record-based procedures are translated with CDD enabled.
</p><div class="callout"><strong>VMS quadword dates.</strong> Rdb <code>DATE VMS</code> parameters keep their VMS quadword
form in the application while the runtime converts them to and from SQL <code>TIMESTAMP</code>.
Dates are stored as normal timestamps in the target database, so other tools can read them, while
the application continues to send and receive VMS quadwords with no code change.
</div><h6>Indicators, cursors and transactions</h6><p>
The translator handles indicator variables, including the Rdb <code>INDICATOR ARRAY OF n</code>
record-indicator form; multi-statement procedures; static cursors
(<code>DECLARE</code> / <code>OPEN</code> / <code>FETCH ... INTO</code> / <code>CLOSE</code>,
including <code>WHERE CURRENT OF</code>); <code>SET TRANSACTION</code>, <code>COMMIT</code> and
<code>ROLLBACK</code>; compound <code>BEGIN [ATOMIC] ... END</code> blocks and <code>FOR ... DO</code>
loops; and full dynamic SQL (<code>PREPARE</code>, <code>DESCRIBE</code>, and
<code>OPEN</code> / <code>FETCH ... USING DESCRIPTOR</code>).
</p><div class="callout"><strong>Rdb error codes preserved.</strong> VX/SQL-MODULE provides an Rdb-compatible SQLCA and
maps Rdb <code>SQLCODE</code> and <code>SQLSTATE</code>, so procedures that inspect
<code>sqlca.sqlcode</code> behave as they did under Rdb.
</div><h2 id="runtime-databases">Runtime and supported databases</h2><p>
The generated modules call the same pluggable VX/SQL runtime that VX/SQL embedded SQL uses. That
runtime provides the <code>S7ESQL*</code> statement API for direct-API output and a set of shared
<code>vxrt_*</code> helpers used by both flavours, and it is where the target database is actually
selected.
</p><h6>Runtime entry points</h6><div class="table-wrapper"><table><thead><tr><th>Routine</th><th>Purpose</th></tr></thead><tbody><tr><td><code>S7ESQLStartSQL</code> / <code>S7ESQLEndSQL</code></td><td>Open and close a statement scope.</td></tr><tr><td><code>S7ESQLSetSQLParams</code></td><td>Bind an input host variable by type code, size and indicator.</td></tr><tr><td><code>S7ESQLExecParams</code></td><td>Execute a positional-parameter statement.</td></tr><tr><td><code>S7ESQLSetResultParams</code> / <code>S7ESQLExecSelectIntoOne</code></td><td>Register output host variables and run a single-row <code>SELECT ... INTO</code>.</td></tr><tr><td><code>S7ESQLCursorDeclare</code> / <code>S7ESQLCursorOpen</code> / <code>S7ESQLCursorFetchOne</code> / <code>S7ESQLCursorClose</code></td><td>Static cursor lifecycle.</td></tr><tr><td><code>S7ESQLPrepareStatement</code></td><td>Dynamic-SQL prepare.</td></tr><tr><td><code>vxrt_postgres_to_rdb</code></td><td>Map a back-end status to the Rdb <code>SQLCODE</code> the caller expects.</td></tr><tr><td><code>vxrt_db_open</code> / <code>vxrt_db_connect</code> / <code>vxrt_db_disconnect</code></td><td>Connection lifecycle for <code>ATTACH</code>, <code>CONNECT</code> and <code>DISCONNECT</code>.</td></tr><tr><td><code>vxrt_chrcpy</code> / <code>vxrt_trim_rhs</code></td><td>Language-aware character copy and fixed-width <code>CHAR</code> trimming.</td></tr></tbody></table></div><h6>Supported databases</h6><p>
Because the back end is chosen at run time by configuration, the same generated modules move between
databases without being rebuilt:
</p><div class="table-wrapper"><table><thead><tr><th>Target</th><th>Access</th><th>Status</th></tr></thead><tbody><tr><td>PostgreSQL</td><td>Native driver</td><td><span class="ac-live">reference, most thoroughly tested</span></td></tr><tr><td>MySQL / MariaDB</td><td>Native driver</td><td><span class="ac-live">validated to PostgreSQL parity on the regression suite</span></td></tr><tr><td>Microsoft SQL Server</td><td>ODBC (unixODBC / FreeTDS)</td><td><span class="ac-live">live</span></td></tr><tr><td>Any ODBC data source</td><td>ODBC</td><td><span class="ac-live">live</span></td></tr><tr><td>Oracle</td><td>Oracle OCI client</td><td><span class="ac-live">live</span></td></tr><tr><td>SQLite</td><td>Embedded</td><td><span class="ac-live">useful for offline development and CI</span></td></tr></tbody></table></div><h6>Performance and validation</h6><ul><li>Bulk and array fetch cut network round-trips on high-volume cursors, with native server-side cursors on the PostgreSQL reference driver.</li><li>An Rdb-compatible SQLCA and Rdb <code>SQLCODE</code> / <code>SQLSTATE</code> mapping keep status-inspection logic working unchanged.</li><li>An automated unit-test harness is generated for each SQLMOD procedure, for side-by-side validation of the original module against the migrated one.</li></ul><h6>Offloading database workloads from OpenVMS</h6><p>
VX/SQL-MODULE lets an OpenVMS application keep its SQLMOD calls while the database itself runs on a
modern back end, on OpenVMS x86, Linux, or elsewhere. Database work moves off Rdb, which reduces
load on legacy systems and extends their useful life, without changing the application's calling
sequence. With Oracle Rdb reaching end of life in December 2027 and no port to x86 OpenVMS,
this gives SQLMOD-based applications a supported path onto modern platforms and open back ends.
</p><div class="s7-tech-embed__video" style="position:relative;padding-bottom:56.25%;height:0;margin-top:24px;"><iframe src="https://www.youtube.com/embed/yhHIyVRYkKY"
title="Sector7 Automated OpenVMS Rdb to Oracle/Postgres Database Transition"
style="position:absolute;inset:0;width:100%;height:100%"
loading="lazy" frameborder="0" allowfullscreen></iframe></div><h2 id="compatibility">Compatibility and status</h2><p>
VX/SQL-MODULE is developed in phases, and each capability is tracked against golden fixtures and
customer regression corpora that must pass at 100 percent. The table below summarises what the
translator handles today.
</p><div class="table-wrapper"><table><thead><tr><th>Capability</th><th>Status</th></tr></thead><tbody><tr><td>Module header and procedure prototypes</td><td><span class="ac-live">live</span></td></tr><tr><td>Single-statement procedures: <code>SELECT INTO</code>, <code>INSERT</code>, <code>UPDATE</code>, <code>DELETE</code>, transaction control, indicators</td><td><span class="ac-live">live</span></td></tr><tr><td>Static cursors: <code>DECLARE</code>, <code>OPEN [USING]</code>, <code>FETCH ... INTO</code>, <code>CLOSE</code>, <code>WHERE CURRENT OF</code></td><td><span class="ac-live">live</span></td></tr><tr><td>Baseline alignment: <code>RESERVING</code> strip, <code>ATTACH</code> to connect, prepare re-guard, lazy DB open, close guard</td><td><span class="ac-live">live</span></td></tr><tr><td>Full dynamic SQL: <code>PREPARE</code>, <code>DESCRIBE</code>, <code>OPEN</code> / <code>FETCH ... USING DESCRIPTOR</code></td><td><span class="ac-live">live</span></td></tr><tr><td>Compound <code>BEGIN [ATOMIC] ... END</code> and <code>FOR ... DO</code> loops</td><td><span class="ac-live">live</span></td></tr><tr><td>Scrollable, holdable and <code>LIST</code> cursors</td><td><span class="ac-v1">v1 soon</span></td></tr><tr><td>Extended SQLDA type codes (<code>REAL</code>, <code>DOUBLE</code>, <code>DECIMAL</code>, <code>TIMESTAMP</code>, <code>INTERVAL</code>, <code>LIST</code>)</td><td><span class="ac-v2">v2</span></td></tr></tbody></table></div><h6>Rdb-to-target dialect rewrites</h6><p>
The emitter applies a fixed set of source-to-source rewrites so Rdb-dialect SQL becomes acceptable
to the target. These include null and conditional functions (<code>NVL</code>, <code>DECODE</code>),
date handling (<code>SYSDATE</code>, <code>EXTRACT</code>, <code>DATE VMS</code> / <code>ANSI</code>
qualifier removal), the Oracle outer-join <code>(+)</code> operator, concatenation and casting,
<code>STARTING WITH</code>, sequence <code>NEXTVAL</code>, <code>DELETE t</code> to
<code>DELETE FROM t</code>, <code>RESERVING ... FOR SHARED</code> stripping, cursor mode and
<code>FOR UPDATE OF</code> handling, and schema qualifier rewriting. Long statements are re-wrapped
at clause boundaries. Functions with no direct target equivalent are backed by installable SQL
shim functions supplied with the toolset.
</p><div class="callout"><strong>Command line.</strong> The translator binary is <code>vxsqlmod</code>. Embedded SQL
(<code>-m esql</code>) is the default output; direct-API C (<code>-m psql</code>) is selected
explicitly. This is distinct from the <code>vxsql</code> embedded-SQL preprocessor used by the
COBOL and Fortran members of the VX/SQL toolset.
</div><h2 id="quickref">Quick reference</h2><h6>Command line</h6>
<pre>usage: vxsqlmod [-o OUTDIR] [-b BASENAME] [-m psql|esql]
[--cdd PATH] [--cdd-types FILE] [--cdd-probe NAME]
[--trace]
INPUT.sqlmod
<span class="cmt"># Embedded SQL (default), with CDD type resolution:</span>
vxsqlmod -m esql --cdd /path/cdd.db -o build/ acct_inquiry.sqlmod
<span class="cmt"># -> build/acct_inquiry.h + .esql + .pgh (then: ecpg -> cc)</span>
<span class="cmt"># Direct-API C (no pre-compiler):</span>
vxsqlmod -m psql -o build/ acct_inquiry.sqlmod
<span class="cmt"># -> build/acct_inquiry.h + .psql (then: cc)</span>
</pre>
<h6>Flags</h6><div class="table-wrapper"><table><thead><tr><th>Flag</th><th>Meaning</th></tr></thead><tbody><tr><td><code>-m esql|psql</code></td><td>Output flavour. Default <code>esql</code>.</td></tr><tr><td><code>-o OUTDIR</code></td><td>Output directory (default: current directory).</td></tr><tr><td><code>-b BASENAME</code></td><td>Override output basename (default: stem of the input).</td></tr><tr><td><code>--cdd PATH</code></td><td>Open the CDD dictionary at <code>PATH</code> and resolve Domain parameters to real C typedefs.</td></tr><tr><td><code>--cdd-types FILE</code></td><td>Load a static CDD typedef registry, consulted before <code>--cdd</code>.</td></tr><tr><td><code>--cdd-probe NAME</code></td><td>Diagnostic: extract and print one CDD record definition.</td></tr><tr><td><code>--trace</code></td><td>Emit optional trace hooks around each statement.</td></tr></tbody></table></div><h6>Exit codes</h6><div class="table-wrapper"><table><thead><tr><th>Code</th><th>Meaning</th></tr></thead><tbody><tr><td><code>0</code></td><td>Translation succeeded.</td></tr><tr><td><code>1</code></td><td>Parse or translation error.</td></tr><tr><td><code>2</code></td><td>Bad command line (no input, unknown flag).</td></tr><tr><td><code>3</code></td><td>CDD load or open failure.</td></tr><tr><td><code>4</code></td><td>CDD extract failed for the probed record.</td></tr></tbody></table></div><h6>SQL statement verbs handled</h6><div class="kw-grid"><div>SELECT INTO</div><div>INSERT</div><div>UPDATE</div><div>DELETE</div><div>SET TRANSACTION</div><div>COMMIT</div><div>ROLLBACK</div><div>SAVEPOINT</div><div>OPEN CURSOR</div><div>FETCH</div><div>CLOSE CURSOR</div><div>COMPOUND</div><div>ATTACH</div><div>CONNECT</div><div>DISCONNECT</div><div>SET CONNECT</div><div>PREPARE</div><div>DESCRIBE</div><div>EXECUTE</div><div>EXECUTE IMMEDIATE</div><div>CALL</div><div>DDL</div></div><h6>Host-variable type codes emitted</h6><div class="kw-grid"><div>SQLMOD_HVAR_ALPHANUMERIC</div><div>SQLMOD_HVAR_SIGNED_BINARY</div><div>SQLMOD_HVAR_FLOAT</div><div>SQLMOD_HVAR_SIGNED_PD</div></div><h6>Related tools</h6><ul><li><a href="/technical/vx-sql-cobol-with-embedded-sql-to-pro-c-or-ecpg">VX/SQL-COBOL</a> and <a href="/technical/vx-sql-fortran-with-embedded-sql-to-pro-c">VX/SQL-FORTRAN</a> handle embedded SQL in COBOL and Fortran callers on the same VX/SQL runtime.</li><li><a href="/technical/vx-rdml-convert-rdml-to-embedded-sql">VX/RDML</a> converts Rdb RDML to embedded SQL, often part of the same Rdb estate as SQLMOD.</li><li><a href="/technical/vx-cdd-vms-cdd">VX/CDD</a> supplies the dictionary extraction that Domain and record-parameter resolution depends on.</li><li><a href="/technical/api-sql-database-interface">SQL$ (API)</a> is the database-interface API layer these generated modules build on.</li></ul></div>