Technical Capabilities
Having trouble finding what you need?
Get in touch with us, so we can answer your specific questions directly.
Get In Touch

SQL$PRE (VX/SQL$PRE) – Rdb embedded SQL in COBOL, on OpenVMS x86 and Linux

Overview

SQL$PRE (VX/SQL$PRE) is Sector7's drop-in replacement for the Oracle Rdb embedded-SQL precompiler, running natively on OpenVMS x86. It takes the same command line, the same qualifiers and the same .SCO source, writes the same output files and returns the same success status and fatal severity. The DCL procedures that build your Rdb COBOL applications today build them on x86 (ACMS servers that commit through DECdtm add one qualifier, /XA_COMMIT), and the COBOL does not change. Underneath, the database becomes PostgreSQL, Microsoft SQL Server, MySQL, MariaDB or SQLite, with Oracle reached through SQL Relay.

SQL$PRE is how an Rdb shop moves to OpenVMS x86 and stays on OpenVMS: the same programs, the same SQLCA and SQLCODE handling, the same dictionary records, the same ACMS task definitions with DECdtm two-phase commit, and measured performance well ahead of Rdb on Itanium. The same precompiler also runs on Linux, so a later move off OpenVMS uses the same tool.

Same command line, same build, different database

SQL$PRE V7.3 compatibility is the contract: qualifiers, output names, $STATUS severity and the shape of the generated code. Install the x86 precompiler under the name SQL$PRE and the symbols your build procedures already define keep working; or point the one symbol at the Sector7 image.

Rdb on Alpha or Itanium

$ SCOB :== $SQL$PRE/COBOL
$ SCOB /COBOL /NOWARN /DEBUG -
      /OBJECT=AVERTZ_OBJ:VR_FIND_CU_PROC.OBJ -
      AVERTZ_SOURCE:VR_FIND_CU_PROC.SCO

SQL$PRE on OpenVMS x86

$ SCOB :== $VXSQL_ROOT:[OPENVMS.BIN]VXSQL.EXE
$ SCOB /COBOL /NOWARN /DEBUG /XA_COMMIT -
      /OBJECT=AVERTZ_OBJ:VR_FIND_CU_PROC.OBJ -
      AVERTZ_SOURCE:VR_FIND_CU_PROC.SCO
  • The SQL$PRE V7.3 qualifiers are accepted, including abbreviations: /COBOL, /[NO]ANSI_FORMAT, /LIST, /OBJECT, /[NO]MACHINE_CODE, /[NO]G_FLOAT, /FLOAT=, and the /SQLOPTIONS= vocabulary. Qualifiers meant for the COBOL compiler are passed through to it.
  • The same outputs: NAME.COB, NAME.OBJ, /LIST NAME.LIS, and SQL$KEEP_PREP_FILES.
  • The same success status, %X10000001, and the same fatal severity on failure, so existing .COM procedures do not change.
  • On OpenVMS x86 one qualifier adds function: /XA_COMMIT (short form /XA), for ACMS applications that commit through DECdtm.
One symbol changes in the build. SCOB now points at the Sector7 precompiler, and ACMS servers that commit through DECdtm add /XA_COMMIT. Nothing changes in the COBOL.

Built for Rdb COBOL

Generic SQL precompilers stop at C and C++. Rdb shops wrote COBOL. SQL$PRE precompiles VSI COBOL on x86, in fixed or free format, with the SQL$PRE semantics Rdb programs depend on: the SQLCA, the Rdb message vector, WHENEVER, cursors, dynamic SQL, and USING CONTEXT for ACMS. The same runtime also serves the FORTRAN, Pascal and C precompilers.

What the generated COBOL looks like

Real output from the AVERTZ x86 build, from Rdb embedded SQL precompiled exactly as written:

EXEC SQL DECLARE RSLIST_CURSOR CURSOR FOR
    SELECT R.RESERVATION_ID, R.CUSTOMER_ID,
           C.LAST_NAME, C.FIRST_NAME, ...
      FROM RESERVATIONS R, CUSTOMERS C, SITES S
     WHERE R.CUSTOMER_ID = C.CUSTOMER_ID
       AND ((R.RESERV_STATUS_FLAG = :C-ZERO) OR
            (R.RESERV_STATUS_FLAG = :C-ONE))
END-EXEC.

EXEC SQL FETCH RSLIST_CURSOR INTO
    :VR_RSLIST_ROW_WKSP.RESERVATION_ID:RL-IND-1,
    ...
    :VR_RSLIST_ROW_WKSP.VEHICLE_CHECKOUT_DATE:RL-IND-9
END-EXEC.

SQL$PRE turns it into ordinary COBOL that the VSI COBOL compiler builds:

01  SQ0002.
    02 FILLER PIC X(59) VALUE "SELECT R.RESERVATION_ID , R.CUS".
    02 FILLER PIC X(59) VALUE "... WHERE R.CUSTOMER_ID = C.CUS".
    02 FILLER PIC X(48) VALUE "... = $1 OR ... = $2 ) ORDER BY".

    CALL "S7RdbMsgVec" USING BY REFERENCE RDB$MESSAGE_VECTOR
    CALL "S7StartSQL"
    CALL "S7SetResultParams" USING
        BY VALUE 23  BY VALUE 18  BY VALUE -7  BY VALUE 0
        BY REFERENCE VEHICLE_CHECKOUT_DATE OF VR_RSLIST_ROW_WKSP
        BY REFERENCE RL-IND-9
    END-CALL
    CALL "S7CursorFetch" USING BY REFERENCE SQLCA
        BY REFERENCE S7-CSTR-0003  BY VALUE 1  BY VALUE 0
    END-CALL
    CALL "S7EndSQL"
    EVALUATE TRUE
        WHEN SQLCODE = 100  GO TO SQL-ARR-NOT-FOUND
        WHEN SQLCODE < 0    GO TO SQL-ERROR-HANDLER
    END-EVALUATE
  • The SQL text travels as a string constant, with :host variables rewritten to $n parameters.
  • Each host variable is bound with its type code, digits, scale and indicator. The quadword date arrives as PIC S9(11)V9(7) COMP (scale -7), and the runtime converts it whenever the column is a DATE, TIME or TIMESTAMP.
  • WHENEVER becomes an EVALUATE after each statement: no hidden control flow, nothing to maintain by hand.

Rdb extended SQL, not an ANSI subset

SQL$PRE was built from the Rdb grammar and the Rdb corpus, statement by statement, so it reads the SQL your programs actually contain:

  • Indicator variables, in both the juxtaposed and the INDICATOR form.
  • DECLARE ALIAS, with each alias mapped to a database through the connection file.
  • Cursors and PREPARE / EXECUTE, with dynamic SQL through SQL descriptors (DESCRIBE OUTPUT, GET / SET DESCRIPTOR) and the SQLDA.
  • Dictionary records: INCLUDE FROM DICTIONARY and COPY ... FROM DICTIONARY in COBOL, and the DICTIONARY directive in FORTRAN.
  • SQL module language procedures alongside the embedded SQL, through SQL$MOD (VX/SQL$MOD).
  • SET TRANSACTION READ ONLY / READ WRITE, RESERVING ... FOR SHARED | PROTECTED | EXCLUSIVE READ | WRITE, WAIT n, NOWAIT and isolation levels.
  • DECLARE TRANSACTION, CONNECT TO ... ALIAS and SET CONNECT.
  • EVALUATING ... AT VERB TIME clauses, accepted as written, with the target database's constraints doing the checking.
  • Cursors declared WITH HOLD.

Inside the precompiler

Every compile runs the same five stages, whatever the host language. Only the host compiler changes.

StageWhat happens
1. DCL front endThe SQL$PRE command line is read, and every qualifier and SQLOPTIONS value is parsed and validated against the V7.3 grammar.
2. EXEC SQL parseThe source is consolidated and each EXEC SQL statement is parsed; host variables and indicators are resolved.
3. Dictionary expansionDictionary references (INCLUDE FROM DICTIONARY and COPY FROM DICTIONARY in COBOL, DICTIONARY in FORTRAN) are walked through the dictionary; records become host declarations whose members bind as host variables.
4. Translate and bindRdb SQL is rewritten for the target database; :host variables become $1..$n parameters and result columns are bound to typed targets.
5. Generate and compileNative source is emitted with calls into the SQL$PRE runtime and the SQLCA declared for the host language (COBOL also gets the Rdb message vector), the VSI compiler is invoked, and the OBJ and LIS are produced.

The generated source is kept for audit, and a failed precompile leaves the source and the diagnostics in the output file, exactly as Rdb's SQL$PRE does.

The dictionary is the source of truth

COBOL's INCLUDE FROM DICTIONARY and FORTRAN's DICTIONARY directive go through the same dictionary protocol the VSI compilers use (CDD$SIGN_IN, CDD$FIND_NODE, CDD$GET_ATTS, CDD$GET_ENTITY_CELL), so a record arrives as the compiler would see it. In COBOL every field keeps its datatype, length, digits, scale, OCCURS and initial value, and a scaled longword is bound as a scaled numeric, not an integer. In FORTRAN the record becomes a DEC STRUCTURE, and the members of each RECORD of it bind as host variables. On OpenVMS x86 the dictionary is VX/CDD, Sector7's CDD for x86 and Linux, and VSI's VDD works through the same protocol. DECforms and ACMS use the same dictionary records, so the screen, the task workspace and the SQL host structure stay one definition.

One generated program, many databases

The generated code never knows which database it is talking to. It calls a small, stable runtime interface; the runtime is one shareable image per target, chosen at link time.

LayerWhat it does
Generated programCalls the runtime: connect, bind, execute, fetch, transaction and diagnostics calls.
SQL$PRE runtime (shareable image)Statement scope, parameter binding, type conversion, the SQLCA and message vector, and transaction handling.
Linked driverOn OpenVMS x86: PostgreSQL (libpq), Microsoft SQL Server (FreeTDS), MySQL and MariaDB (Connector/C), SQLite, and SQL Relay, which also reaches Oracle.
EXEC SQL DECLARE EXTERNAL ALIAS FILENAME
     'AVERTZ_DATABASE:VEHICLE_RENTALS' END-EXEC.

! VXSQL_DATABASE_CONNECT.INI, kept outside the source tree
VEHICLE_RENTALS = postgresql://dbhost:5432/avertz_demo?...
VEHICLE_HISTORY = postgresql://dbhost:5432/avertz_demo?...

The Rdb alias in your source stays as it is. A connection file maps each alias to a database for each environment, so credentials never enter the source or the build. Moving the same objects to another database is a relink against that database's runtime image.

OpenVMS data types in, SQL types out

Conversions happen in the runtime, at bind and at fetch, keyed on the host type and the column type. Nothing changes in the application.

OpenVMS host declarationSQL typeWhat the runtime does
Longword (PIC S9(9) COMP, INTEGER*4)INTEGERNative x86 byte order, width preserved.
Quadword integer (PIC S9(18) COMP, INTEGER*8)BIGINT8-byte binary, no floating point anywhere.
Scaled binary (PIC S9(7)V99 COMP)NUMERIC(9,2)Exact digit arithmetic places the decimal point: 3000 becomes 30.00. Money never touches floating point. Rdb INTEGER(2) columns migrate as NUMERIC(10,2).
Packed decimal (COMP-3)NUMERICDecoded digit by digit, sign nibble honoured, re-packed on fetch.
Character (PIC X(n), CHARACTER*n)CHAR / VARCHARFixed width preserved; varying-length groups supported.
OpenVMS quadword dateTIMESTAMP, DATE, TIME100-nanosecond ticks since 17-NOV-1858 converted to a SQL timestamp and back, keyed on the column type.
Indicator variableNULL-1 is NULL in and out; truncation is reported through SQLSTATE 01004 and the SQLWARN flags.
Your dates stay quadwords. The application keeps its 64-bit dates and SYS$GETTIM values; the database, and every report, JDBC client and BI tool that reads it, sees ordinary SQL timestamps. The migrated data is immediately usable outside OpenVMS.

Transactions with Rdb semantics

The precompiler carries the Rdb SET TRANSACTION text unchanged, and the runtime lowers it for the database you linked. On PostgreSQL, for example, RESERVING modes become table locks:

Rdb RESERVING modePostgreSQL lock
SHARED READno lock (readers never block)
SHARED WRITEROW EXCLUSIVE
PROTECTED READSHARE
PROTECTED WRITESHARE ROW EXCLUSIVE
EXCLUSIVE READEXCLUSIVE
EXCLUSIVE WRITEACCESS EXCLUSIVE
  • READ ONLY / READ WRITE and the isolation level are set on each transaction; WAIT n becomes that transaction's lock timeout, and NOWAIT is applied to the table locks that RESERVING takes.
  • DECLARE TRANSACTION is re-applied after every COMMIT and ROLLBACK, as Rdb does.
  • COMMIT and ROLLBACK close open cursors that are not WITH HOLD, as Rdb does.

The error handling you already wrote keeps working

Database errors are mapped to the Rdb SQLCODE values your handlers test, and to the RDB$MESSAGE_VECTOR conditions. An error handler written in 1991 still selects the right message.

Condition (PostgreSQL SQLSTATE)SQLCODERDB$MESSAGE_VECTOR status
No data (02000)100RDB$_STREAM_EOF
Unique violation (23505)-803RDB$_NO_DUP
Deadlock (40P01, 40001)-913RDB$_DEADLOCK
Lock not available (55P03)-1003RDB$_LOCK_CONFLICT
Integrity failure (23000, 23502, 23503, 23514)-1001RDB$_INTEG_FAIL
More than one row (21000)-811error path taken
Read-only transaction (25006)errorRDB$_READ_ONLY_TRANS

The SQLCA is filled on every call (SQLCODE, SQLSTATE, SQLERRMC). The message vector is published after every statement, and SQL$SIGNAL raises the condition through LIB$SIGNAL. The no-data code is configurable for shops that used a different convention.

XA two-phase commit through DECdtm

Under ACMS, the transaction boundary belongs to DECdtm, and it still does. SQL$PRE adds /XA_COMMIT: each ACMS procedure server binds its database connection to DECdtm as a resource manager. The task definition opens and ends the transaction as it always has, the COBOL joins it with USING CONTEXT, and DECdtm prepares and commits every branch.

ACMS / DECdtmWhat reaches PostgreSQL
BLOCK WITH TRANSACTION ($START_TRANS)BEGIN on each server's branch
Phase one of COMMIT TRANSACTION ($END_TRANS)PREPARE TRANSACTION on every branch
Phase twoCOMMIT PREPARED on every branch
ROLLBACK TRANSACTION, CANCEL TASK ($ABORT_TRANS)ROLLBACK or ROLLBACK PREPARED
Recovery after a failureA dedicated recovery process resolves in-doubt branches from pg_prepared_xacts
  • The whole DECdtm transaction id is carried into the PostgreSQL transaction name, checksummed, so a DBA can see the DECdtm transaction in pg_prepared_xacts and recovery can rebuild the exact XA id.
  • Measured in the AVERTZ acceptance run: both branches prepared before either committed, 8 milliseconds from the first PREPARE to the last COMMIT PREPARED across two server processes. PostgreSQL's log and DECdtm's own log agree.
  • The XA runtime fails closed: it never falls back to autocommit, writes outside a transaction context are refused at precompile time and at run time, and any change to a session's settings rolls the branch back before prepare.

Proven on AVERTZ

AVERTZ is the vehicle-rental installation verification program HP shipped with ACMS: every OpenVMS transaction-processing component in one application. Sector7 built it from scratch and ran it on OpenVMS x86 against PostgreSQL, from HP's original 1991 source with four procedures adapted for DECdtm XA.

ComponentIn AVERTZ
ACMS applicationOne EXC, five procedure servers, eight tasks, queued and composite tasks
DECforms24x80 panels for reserve, checkout, check-in, customer and vehicle lists
Dictionary23 workspace records shared by ACMS, DECforms and the COBOL
COBOL18 embedded-SQL procedures precompiled with SQL$PRE /XA_COMMIT, 25 USING CONTEXT statements
DatabasesThe two Rdb databases became two schemas in one PostgreSQL database, so one DECdtm transaction still spans two resource managers

HP's task definitions, its VR_FORM screens and its business logic carry over. Sector7 added a reservation-list task and form built the same way, and a DECforms menu agent. The build is one command of thirteen gated steps, and the run reserves a car through DECforms with a two-phase commit across both databases.

Performance on OpenVMS x86

Measured, not estimated. The same read-only workload ran on an Itanium system against native Oracle Rdb, and on OpenVMS x86 through SQL$PRE (VX/SQL$PRE) against PostgreSQL. Same 8,192 input records, the same seven workloads, 57,344 queries per cycle. A complete cycle takes 373 seconds on ia64 Rdb and 9.9 seconds on x86: 37.8 times faster.

Complete-query time: ia64/Rdb and OpenVMS x86

Milliseconds per complete query for each workload, median of six block averages.

ia64: native Oracle RdbOpenVMS x86: SQL$PRE (VX/SQL$PRE) to PostgreSQL
Lookup, 32-byte payload 4.69× faster
0.6873 ms
0.1465 ms
Lookup, 256-byte payload 1.79× faster
0.2633 ms
0.1472 ms
Lookup, 1,024-byte payload 1.82× faster
0.2748 ms
0.1511 ms
Range, 64 orders 23.26× faster
4.6107 ms
0.1982 ms
Invoice, 3-table join 105.74× faster
17.6498 ms
0.1669 ms
Invoice, 5-table join 93.33× faster
17.4067 ms
0.1865 ms
Correlated subquery 23.93× faster
4.6008 ms
0.1922 ms
05101520
Milliseconds per complete query (shorter is faster)
  • Read-only workload. Rdb is configured with 4,096 process buffers; PostgreSQL uses 128 MiB shared_buffers. These are different cache mechanisms.
  • PostgreSQL prepared execution is enabled, with plan_cache_mode=auto.
  • OpenVMS x86 runs as a KVM guest on the RH8X host, using virtio to reach PostgreSQL on that host.
  • Transactions, including transaction completion, are included. Connection setup, warm-up and reporting are excluded.
  • No RH9 VM or standalone 2M scan is included.
  • Each workload uses the same 8,192 input records on all platforms; each cycle completes all seven workloads, totalling 57,344 queries.
  • Bars show the median of six block averages (block elapsed time divided by 8,192). They are not individual-query percentiles.

Speedup per workload

How many times faster each workload runs on OpenVMS x86 than on ia64 Rdb. Joins gain the most.

Lookup, 32-byte payload
4.69×
Lookup, 256-byte payload
1.79×
Lookup, 1,024-byte payload
1.82×
Range, 64 orders
23.26×
Invoice, 3-table join
105.74×
Invoice, 5-table join
93.33×
Correlated subquery
23.93×
0306090120
Times faster on OpenVMS x86 (ia64 Rdb time divided by VX/SQL$PRE time)

Complete 57,344-query cycles

All six measured cycles, in seconds. Every x86 cycle took 9.561 to 10.457 s; every ia64 Rdb cycle took 372.550 to 373.583 s.

ia64: native Oracle RdbOpenVMS x86: SQL$PRE (VX/SQL$PRE) to PostgreSQL
Cycle 1 37.48× faster
373.238 s
9.957 s
Cycle 2 37.95× faster
372.550 s
9.816 s
Cycle 3 35.73× faster
373.583 s
10.457 s
Cycle 4 37.61× faster
372.926 s
9.915 s
Cycle 5 38.89× faster
372.983 s
9.591 s
Cycle 6 38.97× faster
372.575 s
9.561 s
Median cycle 37.80× faster
372.955 s
9.866 s
0100200300400
Seconds per cycle of 57,344 queries

The figures

Workloadia64 Rdb (ms per query)OpenVMS x86, VX/SQL$PRE (ms per query)x86 speedup
Lookup, 32-byte payload0.68730.14654.69×
Lookup, 256-byte payload0.26330.14721.79×
Lookup, 1,024-byte payload0.27480.15111.82×
Range, 64 orders4.61070.198223.26×
Invoice, 3-table join17.64980.1669105.74×
Invoice, 5-table join17.40670.186593.33×
Correlated subquery4.60080.192223.93×
Cycle (57,344 queries)ia64 Rdb (s)OpenVMS x86, VX/SQL$PRE (s)
1373.2389.957
2372.5509.816
3373.58310.457
4372.9269.915
5372.9839.591
6372.5759.561
Median cycle372.9559.866
All six cycles2,237.85559.297

The same tool on Linux

The precompiler and the runtime also run natively on Linux, for off-platform builds or for a later move off OpenVMS, where Oracle and ODBC data sources are reachable directly as well. The same source, the same SQL and the same runtime calls are used on both, so the platform can be chosen, and changed, without touching the embedded SQL.

VSI Boot Camp 2026 presentation

The full session from VSI's OpenVMS Boot Camp 2026: how SQL$PRE works, XA two-phase commit with DECdtm, the AVERTZ build on OpenVMS x86, SQL$MOD, and the VX/SQL$PRE back end both compilers share, in 59 slides.

Download the presentation (PDF, 59 slides)

Frequently Asked Questions

Curious about how Sector7 can facilitate your application migration? Explore our FAQs for expert insights.

Do I have to change my COBOL source, EXEC SQL or SQLCODE checks?

No. SQL$PRE is a drop-in replacement for Rdb's SQL$PRE on OpenVMS x86. Your .SCO source, EXEC SQL statements, dictionary includes and SQLCODE branches stay as they are. The SQLCA, the Rdb SQLCODE values and the primary RDB$MESSAGE_VECTOR condition are set as Rdb sets them, so the error paths you already wrote keep working.

Do my DCL build procedures change?

At most one symbol, plus /XA_COMMIT for ACMS servers that commit through DECdtm. SQL$PRE accepts the SQL$PRE V7.3 qualifiers, writes the same NAME.COB, NAME.OBJ and NAME.LIS files and returns the same success status and fatal severity. Install it under the name SQL$PRE, or point the one symbol your procedures use (SCOB, for example) at the Sector7 image.

Which databases can my programs use on OpenVMS x86?

PostgreSQL, Microsoft SQL Server, MySQL and MariaDB, and SQLite, through a runtime image chosen at link time; SQL Relay also reaches Oracle. Your Rdb alias names stay in the source and a connection file maps each one to a database, so credentials never enter the source or the build.

Does it work with ACMS and DECdtm transactions?

Yes. With /XA_COMMIT each COBOL procedure server binds its database connection to DECdtm as a resource manager. The task definition opens and ends the transaction as before, the COBOL joins it with USING CONTEXT, and DECdtm prepares and commits every branch. It was proven on AVERTZ, HP's ACMS verification application, built and run on OpenVMS x86 with HP's business logic and task definitions unchanged.

What happens to packed decimal and OpenVMS quadword dates?

Packed decimal and scaled binary fields become SQL NUMERIC with exact digit arithmetic, so money never touches floating point. Quadword dates become SQL TIMESTAMP, DATE or TIME. The application keeps its own data types; the database, and every tool that reads it, sees standard SQL types.

How are INCLUDE FROM DICTIONARY record includes handled?

Through the same dictionary protocol the VSI compilers use, so each record arrives with its datatype, length, scale, OCCURS and initial value. On OpenVMS x86 the dictionary is VX/CDD, and VSI's VDD works through the same protocol.

How fast is it?

In the measured comparison on this page, a complete cycle of 57,344 queries took 9.9 seconds on OpenVMS x86 with SQL$PRE and PostgreSQL, against 373 seconds on Itanium with native Oracle Rdb: 37.8 times faster. Multi-table joins ran up to 105.7 times faster.

Can I later move the same application to Linux?

Yes. The precompiler and runtime also run natively on Linux, with the same source and the same runtime calls, so the platform can be chosen, and changed, without touching the embedded SQL.

Transform Your Legacy Software Today!

Get In Touch
Unlock the potential of your legacy software with our expert migration services.