IBM DB2 to HeliosDB Migration Guide¶
Version: 1.0 Last Updated: January 2026 Compatibility Target: IBM DB2 LUW 10.5, 11.1, 11.5
Table of Contents¶
- Introduction
- DRDA Wire Protocol Compatibility
- Pre-Migration Assessment
- Connection String Migration
- Data Type Mapping
- SQL Dialect Differences
- Stored Procedure Migration
- DB2 EXPORT/IMPORT to HeliosDB COPY
- Application Connectivity
- Performance Considerations
- Troubleshooting Common Issues
- Post-Migration Validation
1. Introduction¶
1.1 Why Migrate from DB2 to HeliosDB?¶
Organizations are increasingly migrating from IBM DB2 to HeliosDB for several compelling reasons:
Cost Savings¶
| Cost Factor | IBM DB2 | HeliosDB | Savings |
|---|---|---|---|
| Processor License (Enterprise) | $32,500/core | Open pricing | 55-75% |
| Annual Support (SWMA) | 20% of license | Included | 100% |
| pureScale/HADR | Additional license | Built-in | 100% |
| Partitioning Feature | $15,000/core | Included | 100% |
| Advanced Compression | $12,000/core | Included | 100% |
| Database Encryption | $10,000/core | Included | 100% |
Typical 4-year TCO Reduction: 60-80%
Multi-Model Support¶
HeliosDB provides native support for multiple data models through a single platform:
- Relational SQL: Full DB2 SQL compatibility
- Document/JSON: MongoDB-compatible document storage
- Key-Value: Redis-compatible operations
- Time-Series: Native time-series optimizations
- Graph: Cypher query language support
- Vector: AI/ML embeddings with similarity search
Modern Architecture Advantages¶
| Capability | IBM DB2 | HeliosDB |
|---|---|---|
| Cloud-Native | Partial | Full Kubernetes support |
| Multi-Protocol | DB2 only | 9+ protocols |
| Auto-Scaling | Manual | Automatic |
| Self-Healing | Manual intervention | AI-driven autonomous |
| ML Integration | External tools | Native in-database ML |
| HTAP | Separate workloads | Unified workload |
1.2 Migration Goals¶
This guide helps you achieve:
- Zero data loss during migration
- Minimal downtime through parallel operation strategies
- Application compatibility with existing DB2 clients via DRDA protocol
- Performance parity or improvement post-migration
- Reduced operational complexity through HeliosDB automation
2. DRDA Wire Protocol Compatibility¶
2.1 DRDA Protocol Support¶
HeliosDB implements the Distributed Relational Database Architecture (DRDA) protocol, enabling seamless connectivity from DB2 clients:
| DRDA Level | Coverage | Features |
|---|---|---|
| Level 3 | 100% | Basic operations, EXCSAT, ACCRDB |
| Level 4 | 100% | Extended features, cursors |
| Level 5 | 90% | Advanced features |
2.2 Connection Parameters¶
| Parameter | DB2 Default | HeliosDB Default | Notes |
|---|---|---|---|
| Port | 50000 | 50000 | DRDA port |
| Database | - | heliosdb | Database name |
| Authentication | Password | Password, Kerberos | Multiple options |
| Encryption | SSL/TLS | SSL/TLS | Full encryption support |
2.3 Supported DRDA Commands¶
| Command | Status | Description |
|---|---|---|
| EXCSAT | Supported | Exchange server attributes |
| EXCSATRD | Supported | Exchange server attributes reply |
| ACCRDB | Supported | Access database |
| ACCRDBRM | Supported | Access reply message |
| SECCHK | Supported | Security check |
| SECCHKRM | Supported | Security reply |
| PRPSQLSTT | Supported | Prepare SQL statement |
| EXCSQLSTT | Supported | Execute SQL statement |
| OPNQRY | Supported | Open query |
| CNTQRY | Supported | Continue query |
| CLSQRY | Supported | Close query |
| SQLSTT | Supported | SQL statement text |
| COMMIT | Supported | Commit transaction |
| ROLLBACK | Supported | Rollback transaction |
2.4 Wire Protocol Compatibility¶
Default Port: 50000
Protocol: DRDA (Distributed Relational Database Architecture)
Wire Format: DRDA Level 5 compatible
Character Set: UTF-8, EBCDIC supported
Supported DB2 Drivers:
| Driver | Minimum Version | Status |
|---|---|---|
| IBM DB2 Driver for JDBC | 11.5+ | Full compatibility |
| JDBC Type 4 | 4.x | Full compatibility |
| IBM DB2 ODBC | 11.x | Full compatibility |
| ibm_db (Python) | 3.x | Full compatibility |
| IBM.Data.DB2 (.NET) | 11.x | Full compatibility |
| IBM.Data.DB2.Core (.NET Core) | 3.x | Full compatibility |
3. Pre-Migration Assessment¶
3.1 Database Inventory¶
Before migration, perform a comprehensive inventory of your DB2 environment.
Schema Analysis Script¶
-- Database size summary
SELECT
TABSCHEMA AS schema_name,
TABNAME AS table_name,
NPAGES * 4 / 1024 AS size_mb,
CARD AS row_count
FROM SYSCAT.TABLES
WHERE TABSCHEMA NOT LIKE 'SYS%'
AND TYPE = 'T'
ORDER BY NPAGES DESC
FETCH FIRST 50 ROWS ONLY;
-- Schema object counts
SELECT
TABSCHEMA,
COUNT(CASE WHEN TYPE = 'T' THEN 1 END) AS tables,
COUNT(CASE WHEN TYPE = 'V' THEN 1 END) AS views,
COUNT(CASE WHEN TYPE = 'A' THEN 1 END) AS aliases
FROM SYSCAT.TABLES
WHERE TABSCHEMA NOT LIKE 'SYS%'
GROUP BY TABSCHEMA
ORDER BY tables DESC;
-- Index summary
SELECT
INDSCHEMA,
COUNT(*) AS index_count,
SUM(NLEAF * 4 / 1024) AS total_size_mb
FROM SYSCAT.INDEXES
WHERE INDSCHEMA NOT LIKE 'SYS%'
GROUP BY INDSCHEMA
ORDER BY index_count DESC;
3.2 Stored Procedure Analysis¶
Analyze your SQL PL codebase for migration complexity:
-- Count routine objects by type
SELECT
ROUTINESCHEMA,
ROUTINETYPE,
COUNT(*) AS routine_count,
SUM(CASE WHEN VALID = 'Y' THEN 1 ELSE 0 END) AS valid_count,
SUM(CASE WHEN VALID = 'N' THEN 1 ELSE 0 END) AS invalid_count
FROM SYSCAT.ROUTINES
WHERE ROUTINESCHEMA NOT LIKE 'SYS%'
AND LANGUAGE = 'SQL'
GROUP BY ROUTINESCHEMA, ROUTINETYPE
ORDER BY routine_count DESC;
-- Procedure source code length
SELECT
ROUTINESCHEMA,
ROUTINENAME,
ROUTINETYPE,
LENGTH(TEXT) AS source_length
FROM SYSCAT.ROUTINES
WHERE ROUTINESCHEMA NOT LIKE 'SYS%'
AND TEXT IS NOT NULL
ORDER BY source_length DESC
FETCH FIRST 20 ROWS ONLY;
-- External routine dependencies
SELECT
ROUTINESCHEMA,
ROUTINENAME,
LANGUAGE,
EXTERNAL_NAME
FROM SYSCAT.ROUTINES
WHERE ROUTINESCHEMA NOT LIKE 'SYS%'
AND LANGUAGE IN ('C', 'JAVA', 'CLR')
ORDER BY ROUTINESCHEMA, ROUTINENAME;
3.3 Feature Usage Inventory¶
-- Check for DB2-specific features
-- MQT (Materialized Query Tables)
SELECT TABSCHEMA, TABNAME, REFRESH
FROM SYSCAT.TABLES
WHERE TYPE = 'S' -- Summary table
AND TABSCHEMA NOT LIKE 'SYS%';
-- Range partitioned tables
SELECT TABSCHEMA, TABNAME, DATAPARTITIONKEYSEQ
FROM SYSCAT.DATAPARTITIONEXPRESSION
WHERE TABSCHEMA NOT LIKE 'SYS%';
-- Check for XML columns
SELECT TABSCHEMA, TABNAME, COLNAME
FROM SYSCAT.COLUMNS
WHERE TYPENAME = 'XML'
AND TABSCHEMA NOT LIKE 'SYS%';
-- User-defined types
SELECT TYPESCHEMA, TYPENAME, METATYPE, SOURCENAME
FROM SYSCAT.DATATYPES
WHERE TYPESCHEMA NOT LIKE 'SYS%';
-- Sequences
SELECT SEQSCHEMA, SEQNAME, START, INCREMENT, CACHE
FROM SYSCAT.SEQUENCES
WHERE SEQSCHEMA NOT LIKE 'SYS%';
3.4 Application Dependencies¶
Document all applications connecting to DB2:
-- Active application snapshots
SELECT
APPLICATION_NAME,
CLIENT_USERID,
CLIENT_WRKSTNNAME,
CLIENT_APPLNAME,
CLIENT_PROTOCOL,
COUNT(*) AS connection_count
FROM SYSIBMADM.SNAPAPPL_INFO
GROUP BY APPLICATION_NAME, CLIENT_USERID, CLIENT_WRKSTNNAME,
CLIENT_APPLNAME, CLIENT_PROTOCOL
ORDER BY connection_count DESC;
3.5 Migration Complexity Score¶
Calculate your migration complexity:
| Factor | Points | Your Score |
|---|---|---|
| Tables < 50 | 1 | |
| Tables 50-200 | 2 | |
| Tables > 200 | 3 | |
| SQL Procedures < 50 | 1 | |
| SQL Procedures 50-200 | 2 | |
| SQL Procedures > 200 | 3 | |
| No external routines (C/Java) | 0 | |
| Uses external routines | 3 | |
| No pureScale/HADR | 0 | |
| Uses pureScale | 2 | |
| No XML columns | 0 | |
| Uses XML extensively | 2 |
Total Score Interpretation: - 1-4: Simple migration (1-2 weeks) - 5-8: Medium complexity (2-6 weeks) - 9+: Complex migration (6+ weeks)
4. Connection String Migration¶
4.1 DB2 CLP to HeliosDB¶
DB2 Command Line Processor:
# DB2 CLP connection
db2 connect to MYDB user db2admin using password
# HeliosDB via DRDA (identical syntax)
db2 connect to heliosdb user admin using password
4.2 Catalog Configuration¶
DB2 Node and Database Catalog:
# DB2: Catalog remote node
db2 catalog tcpip node HELIOS_NODE remote heliosdb-server server 50000
db2 catalog database heliosdb as HELIOSDB at node HELIOS_NODE
# Connect using catalog alias
db2 connect to HELIOSDB user admin using password
db2cli.ini Configuration:
[heliosdb]
Database=heliosdb
Protocol=TCPIP
Hostname=heliosdb-server
ServiceName=50000
UID=admin
PWD=password
CurrentSchema=myschema
4.3 JDBC Connection Strings¶
DB2 JDBC Type 4:
// DB2 connection
String db2Url = "jdbc:db2://db2-server:50000/MYDB";
// HeliosDB connection (same driver works)
String heliosUrl = "jdbc:db2://heliosdb-server:50000/heliosdb";
// With connection properties
String heliosUrlFull = "jdbc:db2://heliosdb-server:50000/heliosdb:" +
"currentSchema=myschema;" +
"securityMechanism=3;" + // Clear text password
"sslConnection=true;";
4.4 ODBC DSN Configuration¶
Windows ODBC (odbc.ini):
[HeliosDB_DSN]
Description=HeliosDB via DRDA
Driver=IBM DB2 ODBC DRIVER
Database=heliosdb
Hostname=heliosdb-server
Port=50000
Protocol=TCPIP
UID=admin
PWD=password
Linux unixODBC (odbcinst.ini):
[IBM DB2 ODBC DRIVER]
Description=IBM DB2 ODBC Driver
Driver=/opt/ibm/db2/V11.5/lib64/libdb2o.so
[HeliosDB]
Driver=IBM DB2 ODBC DRIVER
Database=heliosdb
Hostname=heliosdb-server
Port=50000
Protocol=TCPIP
5. Data Type Mapping¶
5.1 Numeric Types¶
| DB2 Type | HeliosDB Type | Notes |
|---|---|---|
| SMALLINT | SMALLINT | 2-byte integer, direct mapping |
| INTEGER | INTEGER | 4-byte integer, direct mapping |
| BIGINT | BIGINT | 8-byte integer, direct mapping |
| DECIMAL(p,s) | DECIMAL(p,s) | Fixed precision, direct mapping |
| NUMERIC(p,s) | NUMERIC(p,s) | Same as DECIMAL |
| REAL | REAL | 4-byte float |
| DOUBLE | DOUBLE | 8-byte float |
| DECFLOAT(16) | DECFLOAT(16) | IEEE 754-2008 decimal |
| DECFLOAT(34) | DECFLOAT(34) | Extended decimal float |
5.2 Character Types¶
| DB2 Type | HeliosDB Type | Notes |
|---|---|---|
| CHAR(n) | CHAR(n) | Fixed length, max 254 |
| VARCHAR(n) | VARCHAR(n) | Variable length, max 32672 |
| LONG VARCHAR | VARCHAR(32700) | Deprecated, use VARCHAR |
| CLOB(n) | CLOB(n) | Character LOB, up to 2GB |
| GRAPHIC(n) | CHAR(n) | Double-byte characters |
| VARGRAPHIC(n) | VARCHAR(n) | Variable double-byte |
| DBCLOB(n) | CLOB(n) | Double-byte CLOB |
5.3 Binary Types¶
| DB2 Type | HeliosDB Type | Notes |
|---|---|---|
| CHAR(n) FOR BIT DATA | BINARY(n) | Fixed binary |
| VARCHAR(n) FOR BIT DATA | VARBINARY(n) | Variable binary |
| BLOB(n) | BLOB(n) | Binary LOB, up to 2GB |
| BINARY(n) | BINARY(n) | DB2 11.1+ |
| VARBINARY(n) | VARBINARY(n) | DB2 11.1+ |
5.4 Date/Time Types¶
| DB2 Type | HeliosDB Type | Notes |
|---|---|---|
| DATE | DATE | Calendar date |
| TIME | TIME | Time of day |
| TIMESTAMP | TIMESTAMP | Date and time |
| TIMESTAMP(p) | TIMESTAMP(p) | Fractional seconds precision |
5.5 Special Types¶
| DB2 Type | HeliosDB Type | Notes |
|---|---|---|
| BOOLEAN | BOOLEAN | DB2 11.1+ |
| XML | JSONB | Convert to JSON |
| ROW type | RECORD | Composite types |
| ARRAY | ARRAY | Collection type |
5.6 Data Type Conversion Script¶
-- Generate column type conversion report
SELECT
c.TABSCHEMA,
c.TABNAME,
c.COLNAME,
c.TYPENAME AS db2_type,
c.LENGTH,
c.SCALE,
CASE c.TYPENAME
WHEN 'LONG VARCHAR' THEN 'VARCHAR(32700)'
WHEN 'GRAPHIC' THEN 'CHAR(' || c.LENGTH/2 || ')'
WHEN 'VARGRAPHIC' THEN 'VARCHAR(' || c.LENGTH/2 || ')'
WHEN 'DBCLOB' THEN 'CLOB'
WHEN 'XML' THEN 'JSONB'
ELSE c.TYPENAME
END AS helios_type
FROM SYSCAT.COLUMNS c
WHERE c.TABSCHEMA NOT LIKE 'SYS%'
AND c.TYPENAME IN ('LONG VARCHAR', 'GRAPHIC', 'VARGRAPHIC', 'DBCLOB', 'XML')
ORDER BY c.TABSCHEMA, c.TABNAME, c.COLNO;
6. SQL Dialect Differences¶
6.1 Pagination and Row Limiting¶
DB2 Syntax (fully supported in HeliosDB):
-- FETCH FIRST N ROWS ONLY
SELECT * FROM employees
ORDER BY hire_date DESC
FETCH FIRST 10 ROWS ONLY;
-- OFFSET with FETCH
SELECT * FROM employees
ORDER BY emp_id
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
-- FETCH with PERCENT
SELECT * FROM employees
ORDER BY salary DESC
FETCH FIRST 10 PERCENT ROWS ONLY;
6.2 Isolation Levels¶
DB2 Lock Hints (supported):
-- Uncommitted read
SELECT * FROM employees WITH UR;
-- Cursor stability
SELECT * FROM employees WITH CS;
-- Read stability
SELECT * FROM employees WITH RS;
-- Repeatable read
SELECT * FROM employees WITH RR;
6.3 Special Registers¶
| DB2 Register | HeliosDB Equivalent | Notes |
|---|---|---|
| CURRENT DATE | CURRENT DATE | Direct support |
| CURRENT TIME | CURRENT TIME | Direct support |
| CURRENT TIMESTAMP | CURRENT TIMESTAMP | Direct support |
| CURRENT USER | CURRENT_USER | Standard SQL |
| CURRENT SCHEMA | CURRENT_SCHEMA | Direct support |
| CURRENT PATH | CURRENT_PATH | Direct support |
Example:
-- Both work identically
SELECT CURRENT DATE, CURRENT TIME, CURRENT TIMESTAMP FROM SYSIBM.SYSDUMMY1;
-- HeliosDB alternative (no SYSDUMMY1 needed)
SELECT CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP;
6.4 MERGE Statement¶
DB2 MERGE (fully supported):
MERGE INTO target_table t
USING source_table s
ON t.id = s.id
WHEN MATCHED THEN
UPDATE SET
t.name = s.name,
t.updated_at = CURRENT TIMESTAMP
WHEN NOT MATCHED THEN
INSERT (id, name, created_at)
VALUES (s.id, s.name, CURRENT TIMESTAMP);
6.5 Recursive CTEs¶
DB2 Recursive Query (fully supported):
WITH org_hierarchy (emp_id, emp_name, manager_id, level) AS (
-- Anchor member
SELECT emp_id, emp_name, manager_id, 1
FROM employees
WHERE manager_id IS NULL
UNION ALL
-- Recursive member
SELECT e.emp_id, e.emp_name, e.manager_id, h.level + 1
FROM employees e
JOIN org_hierarchy h ON e.manager_id = h.emp_id
)
SELECT * FROM org_hierarchy
ORDER BY level, emp_name;
6.6 OLAP Functions¶
DB2 Window Functions (fully supported):
SELECT
emp_id,
department_id,
salary,
ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rank_in_dept,
SUM(salary) OVER (PARTITION BY department_id) AS dept_total,
AVG(salary) OVER (ORDER BY hire_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg
FROM employees;
6.7 Identity Columns¶
DB2 Identity (fully supported):
-- DB2 identity column
CREATE TABLE orders (
order_id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY
(START WITH 1 INCREMENT BY 1),
order_date DATE,
amount DECIMAL(10,2)
);
-- HeliosDB (identical syntax supported)
CREATE TABLE orders (
order_id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY
(START WITH 1 INCREMENT BY 1),
order_date DATE,
amount DECIMAL(10,2)
);
6.8 Sequence Objects¶
-- Create sequence (identical syntax)
CREATE SEQUENCE order_seq
AS INTEGER
START WITH 1000
INCREMENT BY 1
MINVALUE 1
MAXVALUE 999999999
CYCLE
CACHE 100;
-- Use sequence
INSERT INTO orders (order_id, order_date)
VALUES (NEXT VALUE FOR order_seq, CURRENT DATE);
-- Query current value
SELECT PREVIOUS VALUE FOR order_seq FROM SYSIBM.SYSDUMMY1;
6.9 DB2-Specific Functions Mapping¶
| DB2 Function | HeliosDB Function | Notes |
|---|---|---|
| DAYS(date) | DAYS(date) | Days since 0001-01-01 |
| MIDNIGHT_SECONDS(time) | MIDNIGHT_SECONDS(time) | Seconds since midnight |
| TIMESTAMPDIFF(interval, t1, t2) | TIMESTAMPDIFF(interval, t1, t2) | Time difference |
| VARCHAR_FORMAT(ts, fmt) | TO_CHAR(ts, fmt) | Date formatting |
| TIMESTAMP_FORMAT(str, fmt) | TO_TIMESTAMP(str, fmt) | String to timestamp |
| RAISE_ERROR(code, msg) | SIGNAL SQLSTATE | Error signaling |
| COALESCE(a, b, c) | COALESCE(a, b, c) | First non-null |
| NULLIF(a, b) | NULLIF(a, b) | Null if equal |
| VALUE(a, b) | COALESCE(a, b) | DB2 alias for COALESCE |
| POSSTR(str, search) | POSITION(search IN str) | Find position |
| SUBSTR(str, pos, len) | SUBSTR(str, pos, len) | Substring |
| STRIP(str) | TRIM(str) | Remove whitespace |
| DIGITS(num) | LPAD(num::text, n, '0') | Number to string |
7. Stored Procedure Migration¶
7.1 SQL Procedure Compatibility¶
HeliosDB provides 85% compatibility with DB2 SQL PL procedures:
Basic Procedure Structure¶
-- DB2 SQL Procedure (fully supported)
CREATE OR REPLACE PROCEDURE update_salary (
IN p_emp_id INTEGER,
IN p_increase DECIMAL(5,2),
OUT p_new_salary DECIMAL(10,2)
)
LANGUAGE SQL
BEGIN
DECLARE v_current_salary DECIMAL(10,2);
SELECT salary INTO v_current_salary
FROM employees
WHERE emp_id = p_emp_id;
SET p_new_salary = v_current_salary * (1 + p_increase / 100);
UPDATE employees
SET salary = p_new_salary
WHERE emp_id = p_emp_id;
END
7.2 Control Flow Statements¶
CREATE OR REPLACE PROCEDURE process_order (
IN p_order_id INTEGER,
OUT p_status VARCHAR(50)
)
LANGUAGE SQL
BEGIN
DECLARE v_total DECIMAL(12,2);
DECLARE v_customer_type VARCHAR(20);
-- IF-THEN-ELSEIF-ELSE
SELECT total_amount, customer_type
INTO v_total, v_customer_type
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE o.order_id = p_order_id;
IF v_total > 10000 THEN
SET p_status = 'HIGH_VALUE';
ELSEIF v_total > 1000 THEN
SET p_status = 'MEDIUM_VALUE';
ELSE
SET p_status = 'LOW_VALUE';
END IF;
-- CASE statement
SET p_status = p_status || ' - ' ||
CASE v_customer_type
WHEN 'PREMIUM' THEN 'PRIORITY'
WHEN 'STANDARD' THEN 'NORMAL'
ELSE 'BASIC'
END;
END
7.3 Cursor Operations¶
CREATE OR REPLACE PROCEDURE process_pending_orders ()
LANGUAGE SQL
BEGIN
DECLARE v_order_id INTEGER;
DECLARE v_amount DECIMAL(12,2);
DECLARE v_end_of_cursor INTEGER DEFAULT 0;
-- Declare cursor
DECLARE order_cursor CURSOR FOR
SELECT order_id, total_amount
FROM orders
WHERE status = 'PENDING'
ORDER BY created_at;
-- Handler for end of cursor
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET v_end_of_cursor = 1;
OPEN order_cursor;
fetch_loop: LOOP
FETCH order_cursor INTO v_order_id, v_amount;
IF v_end_of_cursor = 1 THEN
LEAVE fetch_loop;
END IF;
-- Process order
UPDATE orders
SET status = 'PROCESSING',
processed_at = CURRENT TIMESTAMP
WHERE order_id = v_order_id;
END LOOP fetch_loop;
CLOSE order_cursor;
END
7.4 Exception Handling¶
CREATE OR REPLACE PROCEDURE transfer_funds (
IN p_from_account INTEGER,
IN p_to_account INTEGER,
IN p_amount DECIMAL(12,2),
OUT p_result VARCHAR(100)
)
LANGUAGE SQL
BEGIN
DECLARE v_balance DECIMAL(12,2);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SET p_result = 'ERROR: Transaction failed - ' || SQLERRM;
END;
DECLARE EXIT HANDLER FOR SQLSTATE '45001'
BEGIN
ROLLBACK;
SET p_result = 'ERROR: Insufficient funds';
END;
-- Check balance
SELECT balance INTO v_balance
FROM accounts
WHERE account_id = p_from_account;
IF v_balance < p_amount THEN
SIGNAL SQLSTATE '45001';
END IF;
-- Perform transfer
UPDATE accounts SET balance = balance - p_amount
WHERE account_id = p_from_account;
UPDATE accounts SET balance = balance + p_amount
WHERE account_id = p_to_account;
COMMIT;
SET p_result = 'SUCCESS: Transferred ' || p_amount;
END
7.5 User-Defined Functions¶
-- Scalar function
CREATE OR REPLACE FUNCTION calculate_tax (
p_amount DECIMAL(12,2),
p_rate DECIMAL(5,2)
)
RETURNS DECIMAL(12,2)
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
BEGIN
RETURN p_amount * (p_rate / 100);
END
-- Table function
CREATE OR REPLACE FUNCTION get_department_employees (
p_dept_id INTEGER
)
RETURNS TABLE (
emp_id INTEGER,
emp_name VARCHAR(100),
salary DECIMAL(10,2)
)
LANGUAGE SQL
READS SQL DATA
BEGIN
RETURN
SELECT emp_id, emp_name, salary
FROM employees
WHERE department_id = p_dept_id;
END
7.6 Triggers¶
-- BEFORE trigger
CREATE OR REPLACE TRIGGER emp_before_insert
BEFORE INSERT ON employees
REFERENCING NEW AS n
FOR EACH ROW
BEGIN ATOMIC
SET n.created_at = CURRENT TIMESTAMP;
SET n.updated_at = CURRENT TIMESTAMP;
SET n.emp_name = UPPER(n.emp_name);
END
-- AFTER trigger
CREATE OR REPLACE TRIGGER emp_audit_trigger
AFTER UPDATE ON employees
REFERENCING OLD AS o NEW AS n
FOR EACH ROW
BEGIN ATOMIC
INSERT INTO employee_audit (
emp_id, action, old_salary, new_salary, changed_at, changed_by
) VALUES (
n.emp_id, 'UPDATE', o.salary, n.salary, CURRENT TIMESTAMP, CURRENT USER
);
END
-- Statement trigger
CREATE OR REPLACE TRIGGER orders_batch_trigger
AFTER INSERT ON orders
REFERENCING NEW TABLE AS inserted
FOR EACH STATEMENT
BEGIN ATOMIC
INSERT INTO order_statistics (batch_date, order_count, total_amount)
SELECT CURRENT DATE, COUNT(*), SUM(amount)
FROM inserted;
END
7.7 External Procedure Conversion¶
DB2 External Procedures (C, Java, CLR) require conversion to SQL procedures or HeliosDB extensions:
-- DB2 external procedure (Java)
CREATE PROCEDURE java_proc (IN p_input VARCHAR(100))
EXTERNAL NAME 'com.example.MyClass.myMethod'
LANGUAGE JAVA
PARAMETER STYLE JAVA;
-- HeliosDB conversion: SQL procedure or extension
CREATE OR REPLACE PROCEDURE converted_proc (IN p_input VARCHAR(100))
LANGUAGE SQL
BEGIN
-- Re-implement logic in SQL
-- Or use HeliosDB extension framework
END
8. DB2 EXPORT/IMPORT to HeliosDB COPY¶
8.1 Basic Data Export from DB2¶
DB2 EXPORT Command:
# Export to IXF format (preserves types)
db2 "EXPORT TO employees.ixf OF IXF
SELECT * FROM employees"
# Export to DEL format (CSV-like)
db2 "EXPORT TO employees.csv OF DEL
MODIFIED BY COLDEL, CHARDEL\"\" DECPT.
SELECT * FROM employees"
# Export with column headers
db2 "EXPORT TO employees.csv OF DEL
MODIFIED BY NOCHARDEL COLHDRS
SELECT * FROM employees"
8.2 HeliosDB COPY Command¶
Import CSV to HeliosDB:
-- Basic COPY from CSV
COPY employees FROM '/path/to/employees.csv'
WITH (FORMAT csv, HEADER true);
-- With options
COPY employees FROM '/path/to/employees.csv'
WITH (
FORMAT csv,
HEADER true,
DELIMITER ',',
NULL '',
QUOTE '"',
ESCAPE '\\'
);
-- COPY specific columns
COPY employees (emp_id, emp_name, department_id, salary)
FROM '/path/to/employees.csv'
WITH (FORMAT csv, HEADER true);
8.3 Large Table Migration Strategy¶
Step 1: Export from DB2 with partitioning:
#!/bin/bash
# Export large table in chunks
TABLE="large_orders"
CHUNK_SIZE=1000000
for i in $(seq 0 9); do
db2 "EXPORT TO ${TABLE}_part${i}.csv OF DEL
MODIFIED BY NOCHARDEL
SELECT * FROM ${TABLE}
WHERE MOD(order_id, 10) = ${i}"
done
Step 2: Parallel import to HeliosDB:
-- Create staging table
CREATE TABLE orders_staging (LIKE orders INCLUDING ALL);
-- Parallel COPY (run concurrently)
COPY orders_staging FROM '/path/to/large_orders_part0.csv' WITH (FORMAT csv);
COPY orders_staging FROM '/path/to/large_orders_part1.csv' WITH (FORMAT csv);
-- ... continue for all parts
-- Swap tables
ALTER TABLE orders RENAME TO orders_old;
ALTER TABLE orders_staging RENAME TO orders;
DROP TABLE orders_old;
8.4 LOB Data Migration¶
DB2 LOB Export:
# Export with LOBs to separate files
db2 "EXPORT TO documents.csv OF DEL
LOBS TO /lob_data/
LOBFILE documents
MODIFIED BY LOBSINFILE
SELECT doc_id, doc_content FROM documents"
HeliosDB LOB Import:
-- Create table with LOB column
CREATE TABLE documents (
doc_id INTEGER PRIMARY KEY,
doc_content BYTEA
);
-- Import using pg_read_binary_file or application code
-- For large LOBs, use client-side import
8.5 Migration Validation Script¶
-- Generate row count comparison queries
SELECT
'SELECT ''' || TABNAME || ''' AS table_name, COUNT(*) AS row_count FROM ' ||
TABSCHEMA || '.' || TABNAME || ';'
FROM SYSCAT.TABLES
WHERE TABSCHEMA = 'MYSCHEMA'
AND TYPE = 'T'
ORDER BY TABNAME;
9. Application Connectivity¶
9.1 Java (JDBC) Configuration¶
Maven Dependency:
<dependency>
<groupId>com.ibm.db2</groupId>
<artifactId>jcc</artifactId>
<version>11.5.8.0</version>
</dependency>
Connection Example:
import java.sql.*;
import com.ibm.db2.jcc.DB2SimpleDataSource;
public class HeliosDBConnection {
public static void main(String[] args) throws SQLException {
// Simple connection
String url = "jdbc:db2://heliosdb-server:50000/heliosdb";
Connection conn = DriverManager.getConnection(url, "admin", "password");
// Using DataSource with connection pool
DB2SimpleDataSource ds = new DB2SimpleDataSource();
ds.setDatabaseName("heliosdb");
ds.setServerName("heliosdb-server");
ds.setPortNumber(50000);
ds.setUser("admin");
ds.setPassword("password");
ds.setCurrentSchema("myschema");
// SSL/TLS connection
ds.setSslConnection(true);
ds.setSslCertLocation("/path/to/cert.pem");
Connection pooledConn = ds.getConnection();
// Execute query
try (Statement stmt = pooledConn.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT * FROM employees FETCH FIRST 10 ROWS ONLY")) {
while (rs.next()) {
System.out.println(rs.getString("emp_name"));
}
}
}
}
Spring Boot Configuration:
# application.yml
spring:
datasource:
url: jdbc:db2://heliosdb-server:50000/heliosdb
username: admin
password: password
driver-class-name: com.ibm.db2.jcc.DB2Driver
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
9.2 Python (ibm_db) Configuration¶
Installation:
Connection Example:
import ibm_db
import ibm_db_dbi
# Direct connection
conn_string = (
"DATABASE=heliosdb;"
"HOSTNAME=heliosdb-server;"
"PORT=50000;"
"PROTOCOL=TCPIP;"
"UID=admin;"
"PWD=password;"
)
# ibm_db connection
ibm_db_conn = ibm_db.connect(conn_string, "", "")
# Execute query
stmt = ibm_db.exec_immediate(ibm_db_conn,
"SELECT * FROM employees FETCH FIRST 10 ROWS ONLY")
while ibm_db.fetch_row(stmt):
print(ibm_db.result(stmt, "EMP_NAME"))
ibm_db.close(ibm_db_conn)
# Using ibm_db_dbi (DB-API 2.0 compatible)
conn = ibm_db_dbi.connect(conn_string, "", "")
cursor = conn.cursor()
cursor.execute("SELECT emp_id, emp_name, salary FROM employees WHERE dept_id = ?", (10,))
for row in cursor.fetchall():
print(f"{row['EMP_ID']}: {row['EMP_NAME']}")
cursor.close()
conn.close()
SQLAlchemy Integration:
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
# Connection URL
engine = create_engine(
"ibm_db_sa://admin:password@heliosdb-server:50000/heliosdb",
pool_size=10,
max_overflow=20,
pool_pre_ping=True
)
Session = sessionmaker(bind=engine)
session = Session()
# Execute query
result = session.execute(text("SELECT * FROM employees FETCH FIRST 10 ROWS ONLY"))
for row in result:
print(row)
session.close()
9.3 .NET Configuration¶
NuGet Package:
Connection Example:
using IBM.Data.DB2.Core;
using System;
class Program
{
static void Main()
{
string connString = @"
Server=heliosdb-server:50000;
Database=heliosdb;
UID=admin;
PWD=password;
CurrentSchema=myschema;";
using (DB2Connection conn = new DB2Connection(connString))
{
conn.Open();
using (DB2Command cmd = conn.CreateCommand())
{
cmd.CommandText = @"
SELECT emp_id, emp_name, salary
FROM employees
WHERE department_id = @deptId
FETCH FIRST 10 ROWS ONLY";
cmd.Parameters.Add("@deptId", DB2Type.Integer).Value = 10;
using (DB2DataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine($"{reader["emp_id"]}: {reader["emp_name"]}");
}
}
}
}
}
}
Entity Framework Core:
// DbContext configuration
public class AppDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseDb2("Server=heliosdb-server:50000;Database=heliosdb;UID=admin;PWD=password");
}
}
9.4 Node.js Configuration¶
Installation:
Connection Example:
const ibmdb = require('ibm_db');
const connString =
"DATABASE=heliosdb;" +
"HOSTNAME=heliosdb-server;" +
"PORT=50000;" +
"PROTOCOL=TCPIP;" +
"UID=admin;" +
"PWD=password;";
// Async connection
ibmdb.open(connString, (err, conn) => {
if (err) {
console.error('Connection failed:', err);
return;
}
conn.query("SELECT * FROM employees FETCH FIRST 10 ROWS ONLY", (err, data) => {
if (err) {
console.error('Query failed:', err);
} else {
console.log(data);
}
conn.close(() => {
console.log('Connection closed');
});
});
});
// Using promises
async function queryEmployees() {
const conn = await ibmdb.open(connString);
try {
const result = await conn.query(
"SELECT emp_id, emp_name, salary FROM employees WHERE dept_id = ?",
[10]
);
return result;
} finally {
await conn.close();
}
}
10. Performance Considerations¶
10.1 Query Optimization Hints¶
DB2 Optimization Hints (supported):
-- Optimize for N rows
SELECT * FROM orders
WHERE customer_id = 123
OPTIMIZE FOR 1 ROW;
-- Optimize for all rows
SELECT * FROM orders
WHERE status = 'PENDING'
OPTIMIZE FOR ALL ROWS;
-- Force index usage
SELECT * FROM employees
WHERE department_id = 10
-- HeliosDB uses similar hint syntax
10.2 Statistics Collection¶
-- DB2 RUNSTATS equivalent in HeliosDB
ANALYZE employees;
-- Analyze specific columns
ANALYZE employees (department_id, salary);
-- Analyze with sampling (for large tables)
ANALYZE employees TABLESAMPLE SYSTEM (10);
-- View statistics
SELECT
schemaname,
tablename,
n_live_tup,
n_dead_tup,
last_analyze
FROM pg_stat_user_tables
WHERE tablename = 'employees';
10.3 Index Migration Best Practices¶
-- Identify key indexes from DB2
SELECT
INDSCHEMA,
INDNAME,
TABSCHEMA,
TABNAME,
COLNAMES,
UNIQUERULE,
INDEXTYPE
FROM SYSCAT.INDEXES
WHERE TABSCHEMA NOT LIKE 'SYS%'
ORDER BY NLEAF DESC
FETCH FIRST 20 ROWS ONLY;
-- Create equivalent indexes in HeliosDB
CREATE INDEX idx_emp_dept ON employees (department_id);
CREATE UNIQUE INDEX idx_emp_email ON employees (email);
-- Partial indexes (HeliosDB enhancement)
CREATE INDEX idx_active_orders ON orders (customer_id, order_date)
WHERE status = 'ACTIVE';
10.4 Connection Pooling¶
HikariCP Configuration (Java):
# Recommended pool settings
spring:
datasource:
hikari:
maximum-pool-size: 50
minimum-idle: 10
idle-timeout: 300000
max-lifetime: 1200000
connection-timeout: 30000
validation-timeout: 5000
leak-detection-threshold: 60000
10.5 Batch Operations¶
// Java batch insert
try (Connection conn = dataSource.getConnection()) {
conn.setAutoCommit(false);
String sql = "INSERT INTO orders (order_id, customer_id, amount) VALUES (?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
for (Order order : orders) {
pstmt.setInt(1, order.getId());
pstmt.setInt(2, order.getCustomerId());
pstmt.setBigDecimal(3, order.getAmount());
pstmt.addBatch();
if (batchCount++ % 1000 == 0) {
pstmt.executeBatch();
}
}
pstmt.executeBatch();
}
conn.commit();
}
10.6 HeliosDB Performance Features¶
| Feature | Description | Benefit |
|---|---|---|
| Auto-Indexing | ML-based index recommendations | 30-50% query improvement |
| Adaptive Execution | Runtime plan optimization | Handles data skew |
| Parallel Query | Automatic parallelization | Linear scaling |
| Result Caching | Multi-tier caching | 10-100x for repeated queries |
| Predicate Pushdown | Filter at storage layer | 3-10x faster scans |
11. Troubleshooting Common Issues¶
11.1 Connection Issues¶
Error: SQL30081N (Communication Error)¶
Cause: Network connectivity or firewall issues
Solution:
# Verify network connectivity
telnet heliosdb-server 50000
ping heliosdb-server
# Check firewall
iptables -L -n | grep 50000
# Verify HeliosDB DRDA listener
heliosdb status --protocol drda
Error: SQL1403N (Authentication Failed)¶
Cause: Invalid credentials or authentication method mismatch
Solution:
# Test connection with different auth methods
db2 "CONNECT TO heliosdb USER admin USING 'password'"
# Check authentication configuration
cat /etc/heliosdb/heliosdb.toml | grep -A5 "\[drda\]"
11.2 SQL Syntax Issues¶
Error: SQL0206N (Column Not Found)¶
Cause: Case sensitivity differences
Solution:
-- DB2 is case-insensitive by default
-- HeliosDB may require exact case or double quotes
-- If column created as uppercase
SELECT "EMPLOYEE_NAME" FROM employees;
-- Or use case-insensitive schema setting
SET search_path TO myschema;
Error: SQL0204N (Object Not Found)¶
Cause: Schema not in search path
Solution:
-- Set current schema
SET CURRENT SCHEMA = myschema;
-- Or use fully qualified names
SELECT * FROM myschema.employees;
-- Check available schemas
SELECT schema_name FROM information_schema.schemata;
11.3 Data Type Issues¶
Error: SQL0420N (Character Conversion Error)¶
Cause: Character set mismatch
Solution:
# Verify database character set
db2 "SELECT CODEPAGE FROM SYSCAT.DATATYPES WHERE TYPENAME = 'VARCHAR'"
# HeliosDB uses UTF-8
# Convert data during export if needed
db2 "EXPORT TO data.csv OF DEL MODIFIED BY CODEPAGE=1208 ..."
Error: SQL0802N (Arithmetic Overflow)¶
Cause: Numeric precision differences
Solution:
-- Check column definitions
SELECT COLNAME, TYPENAME, LENGTH, SCALE
FROM SYSCAT.COLUMNS
WHERE TABNAME = 'MYTABLE';
-- Adjust column precision in HeliosDB
ALTER TABLE mytable ALTER COLUMN amount TYPE DECIMAL(15,2);
11.4 Performance Issues¶
Slow Query After Migration¶
Cause: Missing statistics or indexes
Solution:
-- Analyze all tables
ANALYZE;
-- Check for missing indexes
EXPLAIN ANALYZE SELECT ... ;
-- Review index recommendations
SELECT * FROM heliosdb_index_advisor WHERE table_name = 'orders';
High Memory Usage¶
Cause: Large result sets or inefficient queries
Solution:
-- Use pagination
SELECT * FROM large_table
FETCH FIRST 1000 ROWS ONLY;
-- Enable result streaming (in application)
statement.setFetchSize(1000);
11.5 Error Code Mapping¶
| DB2 SQLCODE | Description | HeliosDB Equivalent |
|---|---|---|
| SQL0803N | Duplicate key | 23505 (unique_violation) |
| SQL0530N | FK constraint violation | 23503 (foreign_key_violation) |
| SQL0545N | Check constraint violation | 23514 (check_violation) |
| SQL0911N | Deadlock or timeout | 40P01 (deadlock_detected) |
| SQL0913N | Deadlock rollback | 40001 (serialization_failure) |
| SQL0204N | Object not found | 42P01 (undefined_table) |
| SQL0206N | Column not found | 42703 (undefined_column) |
| SQL0100 | No data found | 02000 (no_data) |
| SQL0104N | Syntax error | 42601 (syntax_error) |
12. Post-Migration Validation¶
12.1 Data Integrity Validation¶
Row Count Verification¶
-- DB2: Generate row counts
SELECT
TABSCHEMA || '.' || TABNAME AS table_name,
CARD AS row_count
FROM SYSCAT.TABLES
WHERE TABSCHEMA = 'MYSCHEMA'
AND TYPE = 'T'
ORDER BY TABNAME;
-- HeliosDB: Compare row counts
SELECT
schemaname || '.' || relname AS table_name,
n_live_tup AS row_count
FROM pg_stat_user_tables
WHERE schemaname = 'myschema'
ORDER BY relname;
Checksum Validation¶
-- Sample checksum query
SELECT
COUNT(*) AS row_count,
SUM(CAST(emp_id AS BIGINT)) AS id_sum,
SUM(CAST(salary AS DECIMAL(20,2))) AS salary_sum
FROM employees;
12.2 Functional Validation¶
Stored Procedure Testing¶
-- Create test tracking table
CREATE TABLE migration_tests (
test_id SERIAL PRIMARY KEY,
test_name VARCHAR(200),
test_type VARCHAR(50),
db2_result TEXT,
helios_result TEXT,
status VARCHAR(20),
tested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Test procedure execution
DO $$
DECLARE
v_result TEXT;
BEGIN
CALL my_procedure(123, v_result);
INSERT INTO migration_tests (test_name, test_type, helios_result, status)
VALUES ('my_procedure', 'PROCEDURE', v_result,
CASE WHEN v_result = 'expected' THEN 'PASS' ELSE 'FAIL' END);
END $$;
12.3 Application Validation Checklist¶
| Category | Validation Item | Status |
|---|---|---|
| Connectivity | All applications connect successfully | [ ] |
| Connectivity | Connection pooling works | [ ] |
| Connectivity | SSL/TLS encryption enabled | [ ] |
| Data | Row counts match | [ ] |
| Data | Checksums match | [ ] |
| Data | Sample data spot checks | [ ] |
| Schema | All tables created | [ ] |
| Schema | All indexes created | [ ] |
| Schema | All constraints active | [ ] |
| Schema | All sequences created | [ ] |
| Procedures | All procedures compile | [ ] |
| Procedures | Procedures return correct values | [ ] |
| Triggers | Triggers fire correctly | [ ] |
| Security | Users created | [ ] |
| Security | Grants applied | [ ] |
| Performance | Key queries perform acceptably | [ ] |
| Application | CRUD operations work | [ ] |
| Application | Transactions commit/rollback | [ ] |
12.4 Performance Baseline Comparison¶
-- Capture query execution times
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT
c.customer_name,
COUNT(o.order_id) AS order_count,
SUM(o.amount) AS total_amount
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_date >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY c.customer_name
ORDER BY total_amount DESC
FETCH FIRST 100 ROWS ONLY;
12.5 Rollback Plan¶
In case issues are discovered post-migration:
Quick Rollback Steps¶
- Stop application writes to HeliosDB
- Redirect connections back to DB2
- Sync any delta data (if dual-write was enabled)
- Verify DB2 operations
- Investigate and resolve HeliosDB issues
- Re-attempt migration when ready
Appendix A: Quick Reference Card¶
Essential Commands¶
# Connect via DB2 CLP
db2 connect to heliosdb user admin using password
# Execute query
db2 "SELECT * FROM employees FETCH FIRST 10 ROWS ONLY"
# Check connection status
db2 "SELECT CURRENT SERVER FROM SYSIBM.SYSDUMMY1"
Connection Parameters¶
| Parameter | Default | Description |
|---|---|---|
| Port | 50000 | DRDA port |
| Database | heliosdb | Database name |
| Protocol | TCPIP | Connection protocol |
Configuration Files¶
| File | Location | Purpose |
|---|---|---|
| db2cli.ini | ~/sqllib/cfg/ | CLI configuration |
| db2dsdriver.cfg | ~/sqllib/cfg/ | Data source config |
| heliosdb.toml | /etc/heliosdb/ | Server configuration |
Appendix B: Migration Timeline Template¶
| Week | Phase | Activities |
|---|---|---|
| 1 | Assessment | Inventory, complexity analysis |
| 2 | Planning | Design migration strategy, test plan |
| 3-4 | Schema Migration | Export DDL, translate, create in HeliosDB |
| 5-6 | Data Migration | Initial data load, verify |
| 7-8 | Procedure Migration | Convert SQL PL procedures, functions |
| 9 | Testing | Functional testing, performance testing |
| 10 | Parallel Run | Dual-write, validate |
| 11 | Cutover | Switch primary to HeliosDB |
| 12 | Stabilization | Monitor, optimize, close out |
Related Documentation: - DRDA Protocol Configuration - DRDA Compatibility Reference - DRDA SQL Examples - General Migration Guide
Document History: - v1.0 (January 2026): Initial comprehensive guide