Skip to content
PYD ENTERPRISES

Migration guide

VSAM to PostgreSQL: keys, encodings and record layouts done right

A VSAM file has no schema of its own: the schema is the copybook, the keys are in IDCAMS, and the rules are in every program that reads it. This guide shows how to assemble all three into PostgreSQL DDL and data contracts.

VSAMPostgreSQL
DIFFICULTY
High
OUTPUT
SQL DDL
SYNTAX TRAPS
6 covered
WORKFLOW
6 steps

By Pranav Kulkarni, Head of Language Engineering · Updated 15 Oct 2026

Technical syntax challenges

Where VSAM migrations go wrong.

01

KSDS keys are byte ranges

KEYS(12 0) in the IDCAMS DEFINE says the key is 12 bytes at offset 0. It becomes the primary key only after the copybook tells you which field sits there and whether programs build it from several fields (branch plus account), in which case the target may want a composite key.

02

EBCDIC to UTF-8 and collation

Character data must be converted with the right code page (CCSID 037, 1047, 273 and others differ for brackets and national characters). EBCDIC also sorts lowercase before uppercase before digits; ASCII and UTF-8 sort digits first. Any program that browses with STARTBR and READNEXT and stops at a key boundary can return different rows after migration.

03

Packed and binary fields must not be converted as text

COMP-3 and COMP fields are binary. A bulk EBCDIC-to-ASCII translation of the whole record corrupts them. Each field needs its own conversion: packed decimal to NUMERIC(p,s), binary halfwords to SMALLINT, zoned decimal sign nibbles decoded.

04

Alternate indexes and paths

An AIX defined with NONUNIQUEKEY and accessed through a PATH is a secondary index. With UNIQUEKEY it is a uniqueness constraint the business may rely on. Both must be carried into the DDL deliberately.

05

OCCURS DEPENDING ON and REDEFINES

Variable-length records with OCCURS 0 TO 3 TIMES DEPENDING ON become child tables. REDEFINES variants become either separate tables keyed by a discriminator or nullable columns with a check constraint; the choice depends on how programs use them.

06

Sentinel values

LOW-VALUES and HIGH-VALUES keys, zero dates (00000000) and all-nines fields often mean 'none' or 'end of file'. They should become NULLs or explicit flags, and every one should be confirmed with the business.

Extraction workflow

6 steps from source to signed-off spec.

The sequence a PYD ENTERPRISES Discovery Scan runs for this stack. Every output links back to source file and line range.

  1. 1

    Collect IDCAMS definitions and copybooks

    Export DEFINE CLUSTER, DEFINE AIX and DEFINE PATH statements with the copybooks and the programs that open each dataset.

  2. 2

    Resolve the record layout byte by byte

    PYD ENTERPRISES computes offsets, lengths and usages for every field, including REDEFINES and ODO, and checks them against RECORDSIZE.

  3. 3

    Map keys and indexes to fields

    KEYS offsets for the base cluster and each AIX are matched to copybook fields, producing primary key, unique and secondary index candidates.

  4. 4

    Analyze program access patterns

    Every READ, WRITE, REWRITE, DELETE, STARTBR and READNEXT on the file is traced, so key-order dependencies and generic key browses are listed with source lines.

  5. 5

    Generate DDL and field-level conversion specs

    PostgreSQL DDL, JSON Schema data contracts and a per-field conversion spec (code page, packed, zoned, binary, sentinel handling) are exported for the data engineering team.

  6. 6

    Reconcile with generated fixtures

    Record-level fixtures with expected converted values support row-count and checksum reconciliation between the VSAM unload and the PostgreSQL load.

Legacy in, specification out

The source, and what PYD ENTERPRISES extracts from it.

Left: the VSAM construct as it sits in production. Right: the reviewed artifact your PostgreSQL engineers build against. PYD ENTERPRISES produces the spec and the tests; your team writes the service.

LEGACY SOURCE

CUSTREC.cpyCOBOL
1 * IDCAMS: DEFINE CLUSTER (NAME(PRD.CUST.KSDS) INDEXED -
2 * KEYS(12 0) RECORDSIZE(58 103))
3 * IDCAMS: DEFINE AIX (NAME(PRD.CUST.AIX1) KEYS(30 12) -
4 * NONUNIQUEKEY)
5 01 CUST-REC.
6 05 CUST-ID PIC X(12).
7 05 CUST-NAME PIC X(30).
8 05 CUST-TYPE PIC X(01).
9 88 CUST-RETAIL VALUE 'R'.
10 88 CUST-COMMERCIAL VALUE 'C'.
11 05 CUST-CREDIT-LIMIT PIC S9(9)V99 COMP-3.
12 05 CUST-OPEN-DATE PIC 9(08).
13 05 CUST-PHONE-COUNT PIC 9(01).
14 05 CUST-PHONE PIC X(15)
15 OCCURS 0 TO 3 TIMES
16 DEPENDING ON CUST-PHONE-COUNT.

EXTRACTED ARTIFACT

customer.ddl.sqlSQL
1-- from PRD.CUST.KSDS, CUSTREC.cpy (58 to 103 bytes)
2CREATE TABLE customer (
3 cust_id CHAR(12) PRIMARY KEY,
4 cust_name VARCHAR(30) NOT NULL,
5 cust_type CHAR(1) NOT NULL CHECK (cust_type IN ('R', 'C')),
6 credit_limit NUMERIC(11,2) NOT NULL,
7 open_date DATE
8);
9-- AIX1 KEYS(30 12) NONUNIQUEKEY
10CREATE INDEX customer_name_ix ON customer (cust_name);
11-- OCCURS 0 TO 3 DEPENDING ON CUST-PHONE-COUNT
12CREATE TABLE customer_phone (
13 cust_id CHAR(12) NOT NULL REFERENCES customer (cust_id),
14 seq SMALLINT NOT NULL CHECK (seq BETWEEN 1 AND 3),
15 phone VARCHAR(15) NOT NULL,
16 PRIMARY KEY (cust_id, seq)
17);
18-- review: open_date 00000000 loads as NULL (12 programs test it)
19-- review: credit_limit S9(9)V99 COMP-3, 6 bytes, sign nibble C/D/F

Architectural best practices

Build the PostgreSQL side to the spec, not to the old shape.

  • Convert each field by its usage, never the whole record with one code page table.
  • Choose the PostgreSQL collation for key columns deliberately and test every program that depends on browse order.
  • Turn sentinel values into NULLs or explicit status columns only after the business confirms what each one means.
  • Keep the VSAM key as a unique constraint even if the new model adds a surrogate key, so existing identifiers stay valid.
  • Reconcile every load with record counts and per-field checksums produced from the same conversion spec.

Data migration is a code problem

It is tempting to treat VSAM migration as unload, convert, load. The hard part is that the meaning of each byte is defined by programs: which REDEFINES variant applies, what a zero date means, which records a browse loop expects to see in which order. PYD ENTERPRISES reads those programs to produce the conversion spec, so data engineers are not reverse-engineering semantics from hex dumps.

The outputs are DDL, JSON Schema contracts and a field-level conversion spec, each linked to the copybook lines and the program statements that justify it. Your team runs the actual unload and load with the tools you already use; PYD ENTERPRISES does not move data.

Signed numbers in the wild

Packed decimal stores the sign in the low nibble of the last byte: C positive, D negative and F unsigned. Zoned decimal (PIC S9(5) DISPLAY) stores it in the zone of the last byte, so a negative 12345 is F1 F2 F3 F4 D5, which displays as 1234N in EBCDIC. Converters that treat zoned fields as text produce letters where numbers should be. The conversion spec lists every signed field with its usage so each one is decoded correctly.

FAQ

VSAM to PostgreSQL questions

Does PYD ENTERPRISES perform the data migration?

No. It produces the DDL, data contracts and a field-level conversion spec, plus reconciliation fixtures. Your data engineers run the unload and load with your own tooling.

How does it handle ESDS and RRDS files?

ESDS records are addressed by RBA and RRDS by relative record number. PYD ENTERPRISES flags programs that store RBAs or slot numbers, since those references need a surrogate key in the relational model.

Which EBCDIC code pages are supported?

Common single-byte CCSIDs such as 037, 500, 1047, 273 and 285 are supported per dataset or per field, and DBCS fields are flagged for explicit handling.

Get the spec for your VSAM estate.

Request a codebase scan and review extracted rules, contracts and fixtures for your own VSAM estate, inside your VPC.