Access VMS database - native databases

Content:

  1. Introduction
  2. Rdb
    1. Background
    2. C
      1. Embedded SQL (VMS)
      2. Module (VMS)
      3. ODBC (WIN)
      4. SQL Services (VMS,WIN,NIX)
    3. Pascal
      1. Embedded SQL (VMS)
      2. Module (VMS)
      3. SQLDB + ODBC (WIN)
    4. Fortran
      1. Embedded SQL (VMS)
      2. Module (VMS)
    5. Cobol
      1. Embedded SQL (VMS)
      2. Module (VMS)
    6. JVM languages
      1. JDBC - native driver (VMS)
      2. JDBC - thin driver (VMS,WIN,NIX)
      3. JPA - native driver (VMS)
      4. JPA - thin driver (VMS,WIN,NIX)
      5. DB API 2.0 - native driver (VMS)
      6. DB API 2.0 - thin driver (VMS,WIN,NIX)
    7. .NET languages
      1. ADO.NET (WIN,NIX)
      2. ODBC (WIN)
      3. EF (WIN,NIX)
    8. Python
      1. DB API 2.0 (VMS)
      2. RDB (VMS)
      3. Jython options
    9. PHP
      1. ODBC (WIN)
      2. PDO + ODBC (WIN)
    10. VBS
      1. ODBC (WIN)
  3. MySQL
    1. Background
    2. C
      1. libmysql (VMS,WIN,NIX)
      2. ODBC (WIN)
    3. Pascal
      1. pmysql + libmysql (VMS)
      2. SQLDB (WIN,NIX)
      3. SQLDB + ODBC (WIN)
    4. JVM languages
      1. JDBC (VMS,WIN,NIX)
      2. JPA (VMS,WIN,NIX)
      3. DB API 2.0 (VMS,WIN,NIX)
    5. .NET languages
      1. ADO.NET (WIN,NIX)
      2. ODBC (WIN,NIX)
      3. EF (WIN,NIX)
    6. Python
      1. DB API 2.0 (WIN,NIX)
      2. Jython options
    7. PHP
      1. mysqli (VMS,WIN,NIX)
      2. PDO + mysql (VMS,WIN,NIX)
      3. ODBC (WIN)
      4. PDO + ODBC (WIN)
    8. VBS
      1. ODBC (WIN)
  4. SQLite
    1. Background
    2. C
      1. Standard C API (VMS)
    3. Pascal
      1. psqlite + standard C API (VMS)
    4. JVM languages
      1. JDBC (VMS)
      2. DB API 2.0 (VMS)
    5. Python
      1. DB API 2.0 (VMS)
      2. Jython options
    6. PHP
      1. sqlite3 (VMS)
      2. pdo + sqlite3 (VMS)
  5. Mimer
    1. Background
    2. C
      1. Embedded SQL (VMS,WIN.NIX)
      2. ODBC (WIN)
    3. Pascal
      1. SQLDB + ODBC (WIN)
    4. Fortran
      1. Embedded SQL (VMS)
    5. Cobol
      1. Embedded SQL (VMS)
    6. JVM languages
      1. JDBC - local (VMS)
      2. JDBC - network (VMS,WIN,NIX)
    7. .NET languages
      1. ADO.NET (WIN,NIX)
      2. ODBC (WIN)
    8. PHP
      1. ODBC (WIN)
      2. PDO + ODBC (WIN)
    9. VBS
      1. ODBC (WIN)
  6. Index-Sequential files

Introduction:

The purpose of this article is to show how to access a database residing on VMS from both VMS and other systems.

The example used is extremely trivial. Just the SQL query:

SELECT f1,f2 FROM t1

and there will be no error handling at all.

But there will be links to other articles showing more details on the database API aspect (SQL updates, parameters, error handling etc.).

All technologies will be marked with supported platforms:

VMS
OpenVMS
WIN
Windows
NIX
Linux, various Unix and macOS

There is also a lot of repeated code between examples, but the intention is to make individual sections complete without referring to code in other sections.

This article only covers native databases. For JVM databases see here.

Comparison of content in 2 articles:

Native databases

Database VMS client non-VMS client
Rdb C - embedded SQL
C - module
C - SQL services
Pascal - embedded SQL
Pascal - module
Fortran - embedded SQL
Fortran - module
Cobol - embedded SQL
Cobol - module
Java - JDBC
Java - JPA
Jython - DB API 2.0 + JDBC
Python - DB API 2.0
Python - RDB
C - ODBC
C - SQL services
Pascal - SQLDB + ODBC
Java - JDBC
Java - JPA
Jython - DB API 2.0 + JDBC
C# - ADO.NET
C# - ODBC
C# - EF
PHP - ODBC
PHP - PDO + ODBC
VBS - ODBC
MySQL C - libmysql
Pascal - pmysql + libmysql
Java - JDBC
Java - JPA
Jython - DB API 2.0 + JDBC
PHP - mysqli
PHP - PDO + mysqli
C - libmysql
C - ODBC
Pascal - SQLDB
SQLDB + ODBC
Java - JDBC
Java - JPA
Jython - DB API 2.0 + JDBC
C# - ADO.NET
C# - ODBC
C# - EF
Python - DB API 2.0
PHP - mysqli
PHP - PDO + mysqli
PHP - ODBC
PHP - PDO + ODBC
VBS - ODBC
SQLite C - standard API
Pascal - psqlite + standard API
Java - JDBC
Java - JPA
Jython - DB API 2.0 + JDBC
PHP - sqlite3
PHP - PDO + sqlite3
(N/A)
Mimer C - embedded SQL
Fortran - embedded SQL
Cobol - embedded SQL
Java - JDBC
C - ODBC
Pascal - SQLDB + ODBC
C# - ADO.NET
C# - ODBC
PHP - ODBC
PHP - PDO + ODBC
VBS - ODBC

JVM databases

Database VMS client non-VMS client
HSQLDB Java - JDBC
Jython - DB API 2.0 + JDBC
PHP - JDBC bridge
C - ODBC
Pascal - SQLDB + ODBC
Java - JDBC
Jython - DB API 2.0 + JDBC
Python - DB API 2.0 + JayDeBeApi
PHP - ODBC
PHP - PDO + ODBC
PHP - JDBC bridge
H2 Java - JDBC
Jython - DB API 2.0 + JDBC
PHP - JDBC bridge
Java - JDBC
Jython - DB API 2.0 + JDBC
Python - DB API 2.0 + JayDeBeApi
PHP - JDBC bridge
Derby Java - JDBC
Jython - DB API 2.0 + JDBC
PHP - JDBC bridge
Java - JDBC
Jython - DB API 2.0 + JDBC
Python - DB API 2.0 + JayDeBeApi
PHP - JDBC bridge

For more complex examples see Access VMS database - API comparison.

Rdb:

Background:

Rdb is probably the most widely used relational database on VMS.

It was introduced by Digital back in 1984. It was sold to Oracle in 1994. It is so far VMS only (it was ported to Windows NT but that version was never released).

Rdb has a somewhat unusual database server architecture where different types of client applications connect in different ways:

Rdb architecture

C:

Embedded SQL (VMS):

Rdb supports traditional embedded SQL for a large number of programming languages including C.

The precompiler gets installed with the Rdb installation.

rdb1.sc:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

EXEC SQL INCLUDE SQLCA;
/* these are uppercase in Rdb */
#define sqlca SQLCA
#define sqlcode SQLCODE

int main()
{
    EXEC SQL BEGIN DECLARE SECTION;
    char con[256];
    char f2[51];
    long int f1;
    EXEC SQL END DECLARE SECTION;
    printf("Rdb from C (embedded)\n");
    strcpy(con, "FILENAME disk4:[rdb]test");
    EXEC SQL CONNECT TO :con;
    EXEC SQL DECLARE curs CURSOR FOR SELECT f1,f2 FROM t1;
    EXEC SQL OPEN curs;
    for(;;)
    {
        EXEC SQL FETCH curs INTO :f1, :f2;
        if(sqlca.sqlcode != 0) break;
        printf("%d %s\n", f1, f2);
    }
    EXEC SQL CLOSE curs;
    return 0;
}

Build and run - VMS:

$ def/nolog sql$database disk4:[rdb]test
$ sqlpre /cc /sqloptions=connect rdb1
$ link rdb1 + sys$library:sql$user73/libr
$ run rdb1

Module (VMS):

Rdb also comes with the ability to compile SQL modules to native code that can be linked into applications.

The module compiler gets installed with the Rdb installation.

rdb2c.sqlmod:

MODULE rdb2c
LANGUAGE C
PARAMETER COLONS

DECLARE ALIAS FOR FILENAME disk4:[rdb]test

DECLARE curs CURSOR FOR SELECT f1,f2 FROM t1

PROCEDURE CURSOR_OPEN
    SQLCODE;
    OPEN curs;

PROCEDURE CURSOR_FETCH
    SQLCODE,
    :f1 INTEGER,
    :f2 CHAR(50);
    FETCH curs INTO :f1, :f2;

PROCEDURE CURSOR_CLOSE
    SQLCODE;
    CLOSE curs;

rdb2.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void cursor_open(int *sqlcode);
void cursor_fetch(int *sqlcode, long int *f1, char *f2);
void cursor_close(int *sqlcode);


int main()
{
    char f2[51];
    long int f1;
    int sqlcode;
    printf("Rdb from C (module)\n");
    cursor_open(&sqlcode);
    for(;;)
    {
        cursor_fetch(&sqlcode, &f1, f2);
        if(sqlcode != 0) break;
        printf("%d %s\n", f1, f2);
    }
    cursor_close(&sqlcode);
    return 0;
}

Build and run:

$ def/nolog sql$database disk4:[rdb]test
$ sqlmod rdb2c
$ cc rdb2
$ link rdb2 + rdb2c + sys$library:sql$user73/libr
$ run rdb2

ODBC (WIN):

Oracle provides an ODBC driver for Rdb that needs to be installed.

Standard ODBC API. For details on ODBC API including SQL updates, parameters and error handling see here.

The example assumes a DSN has been defined in ODBC manager.

It seems to require MS VC++ as I could not get it to work with GCC.

rdb2.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <windows.h>
#include <sql.h>
#include <sqlext.h>

#define F2_MAX_LEN 50

static const char *dsn = "ARNE1_RDB";
static const char *un = "arne";
static const char *pw = "hemmeligt";

int main()
{
    SQLHENV env;
    SQLHDBC con;
    SQLHSTMT stmt;
    long int f1;
    char *sqlstr, f2[F2_MAX_LEN + 1];
    SQLLEN lenf2;
    int stat;
    printf("Rdb from C (ODBC)\n");
    stat = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
    stat = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
    stat = SQLAllocHandle(SQL_HANDLE_DBC, env, &con);
    stat = SQLConnect(con, (SQLCHAR *)dsn, (SQLSMALLINT)strlen(dsn),
                           (SQLCHAR *)un, (SQLSMALLINT)strlen(un),
                           (SQLCHAR *)pw, (SQLSMALLINT)strlen(pw));
    sqlstr = "SELECT f1,f2 FROM t1";
    stat = SQLAllocHandle(SQL_HANDLE_STMT, con, &stmt);
    stat = SQLExecDirect(stmt, (SQLCHAR *)sqlstr, strlen(sqlstr));
    stat = SQLBindCol(stmt, 1, SQL_C_LONG, &f1, 0, NULL);
    stat = SQLBindCol(stmt, 2, SQL_C_CHAR, f2, sizeof(f2), &lenf2);
    for(;;)
    {
        stat = SQLFetch(stmt);
        if((stat != SQL_SUCCESS) && (stat != SQL_SUCCESS_WITH_INFO)) break;
        f2[lenf2] = 0;
        printf("%ld %s\n", f1, f2);
    }
    SQLCloseCursor(stmt);
    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
    SQLDisconnect(con);
    SQLFreeHandle(SQL_HANDLE_DBC, con);
    SQLFreeHandle(SQL_HANDLE_ENV, env);
    return 0;
}

Build and run - Windows:

cl rdb2.c odbc32.lib
rdb2

SQL Services (VMS,WIN,NIX):

Rdb SQL Services also has a custom client API.

For details on this API including SQL updates, parameters and error handling see here.

rdb3.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sqlsrv.h>

#define F2_MAX_LEN 50

static char *srv = "arne1.vajhoej.dk";
static char *un = "arne";
static char *pw = "hemmeligt";

int main()
{
    ASSOCIATE_ID con;
    ASSOCIATE_STR coninf;
    long int stmt;
    SQLDA_ID param_sqlda;
    SQLDA_ID select_sqlda;
    long int f1;
    char *sqlstr, *qnam, f2[F2_MAX_LEN + 1];
    long int stat;
    short int nullval;
    char buf[1000];
    unsigned short int buflen;
    printf("Rdb from C (SQLSRV)\n");
    memset(&coninf, 0, sizeof(coninf));
    coninf.VERSION = SQLSRV_V730;
    coninf.xpttyp = SQLSRV_XPT_TCPIP ;
    stat = sqlsrv_associate(srv, un, pw, NULL, NULL, 0, 0, NULL, &coninf, &con);
    stat = sqlsrv_execute_immediate(con, 0, "ATTACH 'FILENAME disk4:[rdb]test'");
    sqlstr = "SELECT f1,f2 FROM t1";
    select_sqlda = NULL;
    param_sqlda = NULL;
    stat = sqlsrv_prepare(con, 0, sqlstr, &stmt, &param_sqlda, &select_sqlda);
    stat = sqlsrv_allocate_sqlda_data(con, select_sqlda);
    qnam = "Q1";
    stat = sqlsrv_open_cursor(con, qnam, stmt, param_sqlda);
    for(;;)
    {
        stat = sqlsrv_fetch(con, qnam, 0, 0, select_sqlda);
        if(stat != SQL_SUCCESS) break;
        stat = sqlsrv_sqlda_get_data(select_sqlda, 0, 0, (CHARPTR)&buf[0], sizeof(buf), &nullval, &buflen);
        f1 = atoi(buf);
        stat = sqlsrv_sqlda_get_data(select_sqlda, 1, 0, (CHARPTR)&buf[0], sizeof(buf), &nullval, &buflen);
        strcpy(f2, buf + 2);
        printf("%ld %s\n", f1, f2);
    }
    sqlsrv_close_cursor(con, qnam); 
    sqlsrv_free_sqlda_data(con, select_sqlda);
    sqlsrv_release_statement(con, 1, &stmt);
    sqlsrv_release(con, NULL);
    return 0;
}

Build and run - VMS:

$ cc rdb3
$ link rdb3 + sys$library:sqlsrv$api/opt
$ run rdb3
$ exit

Build and run - Windows:

cl /I"%SQLSRV%" rdb3.c "%SQLSRV%\SQSAPI64.LIB"
rdb3

Build and run - Linux:

gcc -I. rdb3.c libsqs.a -o rdb3
./rdb3

Pascal:

Embedded SQL (VMS):

Rdb supports traditional embedded SQL for a large number of programming languages including Pascal.

The precompiler gets installed with the Rdb installation.

rdb1.spa:

program rdb1(input, output);

EXEC SQL INCLUDE SQLCA;

EXEC SQL DECLARE curs CURSOR FOR SELECT f1,f2 FROM t1;

var
   EXEC SQL BEGIN DECLARE SECTION;
   con : varying [255] of char;
   f1 : integer;
   f2 : varying [50] of char;
   EXEC SQL END DECLARE SECTION;
   done : boolean;

begin
   writeln('Rdb from Pascal (embedded)');
   con := 'FILENAME disk4:[rdb]test';
   EXEC SQL CONNECT TO :con;
   EXEC SQL OPEN curs;
   done := false;
   while not done do begin
       EXEC SQL FETCH curs INTO :f1, :f2;
       if sqlca.sqlcode = 0 then begin
          writeln(f1, ' ', f2);
       end else begin
          done := true;
      end;
   end;
   EXEC SQL CLOSE curs;
end.

Build and run - VMS:

$ def/nolog sql$database disk4:[rdb]test
$ sqlpre /pas /sqloptions=connect rdb1
$ link rdb1 + sys$library:sql$user73/libr
$ run rdb1

Module (VMS):

Rdb also comes with the ability to compile SQL modules to native code that can be linked into applications.

The module compiler gets installed with the Rdb installation.

rdb2p.sqlmod:

MODULE rdb2p
LANGUAGE PASCAL
PARAMETER COLONS

DECLARE ALIAS FOR FILENAME disk4:[rdb]test

DECLARE curs CURSOR FOR SELECT f1,f2 FROM t1

PROCEDURE CURSOR_OPEN
    SQLCODE;
    OPEN curs;

PROCEDURE CURSOR_FETCH
    SQLCODE,
    :f1 INTEGER,
    :f2 VARCHAR(50);
    FETCH curs INTO :f1, :f2;

PROCEDURE CURSOR_CLOSE
    SQLCODE;
    CLOSE curs;

rdb2.pas:

program rdb2(input, output);

type
   var50str = varying [50] of char;

procedure cursor_open(var sqlcode : integer); external;
procedure cursor_fetch(var sqlcode : integer; var f1 : integer; var f2 : var50str); external;
procedure cursor_close(var sqlcode : integer); external;

var
   sqlcode : integer;
   f1 : integer;
   f2 : var50str;
   done : boolean;

begin
   writeln('Rdb from Pascal (module)');
   cursor_open(sqlcode);
   done := false;
   while not done do begin
       cursor_fetch(sqlcode, f1, f2);
       if sqlcode = 0 then begin
          writeln(f1, ' ', f2);
       end else begin
          done := true;
      end;
   end;
   cursor_close(sqlcode);
end.

Build and run - VMS:

$ def/nolog sql$database disk4:[rdb]test
$ sqlmod rdb2p
$ pas rdb2
$ link rdb2 + rdb2p + sys$library:sql$user73/libr
$ run rdb2

SQLDB + ODBC (WIN):

FPC comes with SQLDB unit for database access. SQLDB supports ODBC.

Oracle provides an ODBC driver for Rdb.

For details on SQLDB API including SQL updates, parameters and error handling see here.

The example assumes a DSN has been defined in ODBC manager.

rdb2.pas:

program rdb2(input, output);

uses
  SQLDB, ODBCConn;

var
  con : TSQLConnection;
  tx : TSQLTransaction;
  q : TSQLQuery;
  f1 : integer;
  f2 : string;

begin
  writeln('Rdb from Pascal (SQLDB, ODBC)');
  con := TODBCConnection.Create(nil);
  con.DatabaseName := 'ARNE1_RDB';
  con.UserName := 'arne';
  con.Password := 'hemmeligt';
  con.Open;
  tx := TSQLTransaction.Create(nil);
  con.Transaction := tx;
  q := TSQLQuery.Create(nil);
  q.DataBase := con;
  q.SQL.Text := 'SELECT f1,f2 FROM t1';
  q.Open;
  while not q.EOF do begin
    f1 := q.FieldByName('f1').AsInteger;
    f2 := q.FieldByName('f2').AsString;
    writeln(f1, ' ', f2);
    q.Next;
  end;
  q.Close;
  q.Free;
  con.Close;
  con.Free;
end.

Build and run - Windows:

fpc rdb2.pas
rdb2

Fortran:

Embedded SQL (VMS):

Rdb supports traditional embedded SQL for a large number of programming languages including Fortran.

The precompiler gets installed with the Rdb installation.

rdb1.sfo:

      PROGRAM RDB1
      EXEC SQL INCLUDE SQLCA
      EXEC SQL DECLARE curs CURSOR FOR SELECT f1,f2 FROM t1
      EXEC SQL BEGIN DECLARE SECTION
      CHARACTER*255 CON
      INTEGER*4 F1
      CHARACTER*50 F2
      EXEC SQL END DECLARE SECTION
      WRITE(*,*) 'Rdb from Fortran(embedded)'
      CON = 'FILENAME disk4:[rdb]test'
      EXEC SQL CONNECT TO :CON
      EXEC SQL OPEN curs
100   EXEC SQL FETCH curs INTO :f1, :f2
      IF(SQLCOD.EQ.0) THEN
        WRITE(*,*) F1, ' ', F2
        GOTO 100
      ENDIF
      EXEC SQL CLOSE curs
      END

Build and run - VMS:

$ def/nolog sql$database disk4:[rdb]test
$ sqlpre /for /sqloptions=connect rdb1
$ link rdb1 + sys$library:sql$user73/libr
$ run rdb1

Module (VMS):

Rdb also comes with the ability to compile SQL modules to native code that can be linked into applications.

The module compiler gets installed with the Rdb installation.

rdb2f.sqlmod:

MODULE rdb2f
LANGUAGE FORTRAN
PARAMETER COLONS

DECLARE ALIAS FOR FILENAME disk4:[rdb]test

DECLARE curs CURSOR FOR SELECT f1,f2 FROM t1

PROCEDURE CURSOR_OPEN
    SQLCODE;
    OPEN curs;

PROCEDURE CURSOR_FETCH
    SQLCODE,
    :f1 INTEGER,
    :f2 CHAR(50);
    FETCH curs INTO :f1, :f2;

PROCEDURE CURSOR_CLOSE
    SQLCODE;
    CLOSE curs;

rdb2.for:

      PROGRAM RDB2
      EXTERNAL CURSOR_OPEN, CURSOR_FETCH, CURSOR_CLOSE
      INTEGER*4 SQLCOD,F1
      CHARACTER*50 F2
      WRITE(*,*) 'Rdb for Fortran (module)'
      CALL CURSOR_OPEN(SQLCOD)
100   CALL CURSOR_FETCH(SQLCOD, F1, F2)
      IF(SQLCOD.EQ.0) THEN
        WRITE(*,*) F1, ' ', F2
        GOTO 100
      ENDIF
      CALL CURSOR_CLOSE(SQLCOD)
      END

Build and run - VMS:

$ def/nolog sql$database disk4:[rdb]test
$ sqlmod rdb2f
$ for rdb2
$ link rdb2 + rdb2f + sys$library:sql$user73/libr
$ run rdb2

Cobol:

Embedded SQL (VMS):

Rdb supports traditional embedded SQL for a large number of programming languages including Cobol.

The precompiler gets installed with the Rdb installation.

rdb1.sco:

IDENTIFICATION DIVISION.
PROGRAM-ID. RDB1.

ENVIRONMENT DIVISION.

DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL INCLUDE SQLCA END-EXEC.
01 CON PIC X(255).
01 F1 PIC 9(9) DISPLAY.
01 F2 PIC X(50).
EXEC SQL DECLARE curs CURSOR FOR SELECT f1,f2 FROM t1 END-EXEC.

PROCEDURE DIVISION.
MAIN-PARAGRAPH.
    DISPLAY "Rdb from Cobol (embedded)"
    MOVE "FILENAME disk4:[rdb]test" TO CON
    EXEC SQL CONNECT TO :CON END-EXEC
    EXEC SQL OPEN curs END-EXEC
    MOVE 0 TO SQLCODE
    PERFORM UNTIL NOT SQLCODE = 0
        EXEC SQL FETCH curs INTO :f1, :f2 END-EXEC
        IF SQLCODE = 0 THEN
            DISPLAY F1 " " F2
        END-IF
    END-PERFORM
    EXEC SQL CLOSE curs END-EXEC
    STOP RUN.

Build and run - VMS:

$ def/nolog sql$database disk4:[rdb]test
$ sqlpre /cob /sqloptions=connect rdb1
$ link rdb1 + sys$library:sql$user73/libr
$ run rdb1

Module (VMS):

Rdb also comes with the ability to compile SQL modules to native code that can be linked into applications.

The module compiler gets installed with the Rdb installation.

rdb2b.sqlmod:

MODULE rdb2b
LANGUAGE COBOL
PARAMETER COLONS

DECLARE ALIAS FOR FILENAME disk4:[rdb]test

DECLARE curs CURSOR FOR SELECT f1,f2 FROM t1

PROCEDURE CURSOR_OPEN
    SQLCODE;
    OPEN curs;

PROCEDURE CURSOR_FETCH
    SQLCODE,
    :f1 INTEGER,
    :f2 CHAR(50);
    FETCH curs INTO :f1, :f2;

PROCEDURE CURSOR_CLOSE
    SQLCODE;
    CLOSE curs;

rdb2.cob:

IDENTIFICATION DIVISION.
PROGRAM-ID. RDB2.

ENVIRONMENT DIVISION.

DATA DIVISION.
WORKING-STORAGE SECTION.
01 SQLCODE PIC S9(9) COMP.
01 TEMPF1 PIC 9(9) COMP.
01 F1 PIC 9(9) DISPLAY.
01 F2 PIC X(50).

PROCEDURE DIVISION.
MAIN-PARAGRAPH.
    DISPLAY "Rdb from Cobol (module)"
    CALL "CURSOR_OPEN" USING SQLCODE
    MOVE 0 TO SQLCODE
    PERFORM UNTIL NOT SQLCODE = 0
        CALL "CURSOR_FETCH" USING SQLCODE, TEMPF1, F2
        IF SQLCODE = 0 THEN
            MOVE TEMPF1 TO F1
            DISPLAY F1 " " F2
        END-IF
    END-PERFORM
    CALL "CURSOR_CLOSE" USING SQLCODE
    STOP RUN.

Build and run - VMS:

$ def/nolog sql$database disk4:[rdb]test
$ sqlmod rdb2b
$ cob rdb2
$ link rdb2 + rdb2b + sys$library:sql$user73/libr
$ run rdb2

JVM languages:

JDBC - native driver (VMS):

JDBC is Java basic database API.

Oracle provides two JDBC drivers for Rdb:

Here we will look at native driver.

For details on JDBC API including SQL updates and parameters see here.

rdb1.java:

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;

public class Rdb1 {
    public static void main(String[] args) throws Exception {
        System.out.println("Rdb from Java (JDBC, native)");
        Class.forName("oracle.rdb.jdbc.rdbNative.Driver");
        Connection con = DriverManager.getConnection("jdbc:rdbNative:disk4:[rdb]test");
        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT f1,f2 FROM t1");
        while(rs.next()) {
            int f1 = rs.getInt(1);
            String f2 = rs.getString(2);
            System.out.println(f1 + " " + f2);
        }
        rs.close();
        stmt.close();
        con.close();
    }
}

Build and run - VMS:

$ javac Rdb1.java
$ java -cp .:rdbnativev5.jar "Rdb1"

jrdb1.py:

from java.lang import Class
from java.sql import DriverManager

from oracle.rdb.jdbc.rdbNative import Driver # replaces Class.forName('oracle.rdb.jdbc.rdbNative.Driver')

print('Rdb from JVM Python (JDBC, native)')
con = DriverManager.getConnection('jdbc:rdbNative:disk4:[rdb]test')
stmt = con.createStatement()
rs = stmt.executeQuery('SELECT f1,f2 FROM t1')
while rs.next():
    f1 = rs.getInt(1)
    f2 = rs.getString(2)
    print(str(f1) + ' ' + f2)
rs.close()
stmt.close()
con.close()

jrdb1.js:

importClass(Packages.java.lang.Class);
importClass(Packages.java.sql.DriverManager);

print("Rdb from JVM JavaScript (JDBC, native)")
new Packages.oracle.rdb.jdbc.rdbNative.Driver(); //replaces Class.forName("oracle.rdb.jdbc.rdbNative.Driver");
con = DriverManager.getConnection("jdbc:rdbNative:disk4:[rdb]test");
stmt = con.createStatement();
rs = stmt.executeQuery("SELECT f1,f2 FROM t1");
while(rs.next()) {
    f1 = rs.getInt(1);
    f2 = rs.getString(2);
    print(f1 + " " + f2);
}
rs.close();
stmt.close();
con.close();

JDBC - thin driver (VMS,WIN,NIX):

JDBC is Java basic database API.

Oracle provides two JDBC drivers for Rdb:

Here we will look at thin driver.

For details on JDBC API including SQL updates and parameters see here.

Rdb2.java:

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;

public class Rdb2 {
    public static void main(String[] args) throws Exception {
        System.out.println("Rdb from Java (JDBC, thin)");
        Class.forName("oracle.rdb.jdbc.rdbThin.Driver");
        Connection con = DriverManager.getConnection("jdbc:rdbThin://192.168.0.10:1701/dka4:[rdb]test", "arne", "hemmeligt");
        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT f1,f2 FROM t1");
        while(rs.next()) {
            int f1 = rs.getInt(1);
            String f2 = rs.getString(2);
            System.out.println(f1 + " " + f2);
        }
        rs.close();
        stmt.close();
        con.close();
    }
}

Build and run - Windows:

javac Rdb2.java
java -cp .;rdbthinv8.jar Rdb2

Build and run - VMS:

$ javac Rdb2.java
$ java -cp .:rdbthinv5.jar "Rdb2"

Rdb2.kt:

import java.sql.*

fun main(args: Array<String>) {
    println("Rdb from Kotlin (JDBC, thin)")
    Class.forName("oracle.rdb.jdbc.rdbThin.Driver")
    val con = DriverManager.getConnection("jdbc:rdbThin://192.168.0.10:1701/dka4:[rdb]test", "arne", "hemmeligt")
    val stmt = con.createStatement()
    val rs = stmt.executeQuery("SELECT f1,f2 FROM t1")
    while(rs.next()) {
        val f1 = rs.getInt(1);
        val f2 = rs.getString(2);
        println("$f1 $f2");
    }
    rs.close()
    stmt.close()
    con.close()
}

Build and run - Windows:

call %KOTLIN%\bin\kotlinc -d . Rdb2.kt
java -cp .;%KOTLIN%\lib\*;rdbthinv8.jar Rdb2Kt

Rdb2.groovy:

import java.sql.*

println("Rdb from Groovy (JDBC, thin)")
Class.forName("oracle.rdb.jdbc.rdbThin.Driver")
con = DriverManager.getConnection("jdbc:rdbThin://192.168.0.10:1701/dka4:[rdb]test", "arne", "hemmeligt")
stmt = con.createStatement()
rs = stmt.executeQuery("SELECT f1,f2 FROM t1")
while(rs.next()) {
    f1 = rs.getInt(1)
    f2 = rs.getString(2)
    println("$f1 $f2")
}
rs.close()
stmt.close()
con.close()

Build and run - Windows:

call %GROOVY%\bin\groovyc Rdb2.groovy
java -cp .;%GROOVY%\lib\*;rdbthinv8.jar Rdb2 

jrdb1.py:

from java.lang import Class
from java.sql import DriverManager

from oracle.rdb.jdbc.rdbThin import Driver # replaces Class.forName('oracle.rdb.jdbc.rdbThin.Driver')

print('Rdb from JVM Python (JDBC, thin)')
con = DriverManager.getConnection('jdbc:rdbThin://192.168.0.10:1701/dka4:[rdb]test', 'arne', 'hemmeligt')
stmt = con.createStatement()
rs = stmt.executeQuery('SELECT f1,f2 FROM t1')
while rs.next():
    f1 = rs.getInt(1)
    f2 = rs.getString(2)
    print(str(f1) + ' ' + f2)
rs.close()
stmt.close()
con.close()

jrdb1.js:

importClass(Packages.java.lang.Class);
importClass(Packages.java.sql.DriverManager);

print("Rdb from JVM JavaScript (JDBC, thin)")
new Packages.oracle.rdb.jdbc.rdbThin.Driver(); //replaces Class.forName("oracle.rdb.jdbc.rdbThin.Driver");
con = DriverManager.getConnection("jdbc:rdbThin://192.168.0.10:1701/dka4:[rdb]test", "arne", "hemmeligt");
stmt = con.createStatement();
rs = stmt.executeQuery("SELECT f1,f2 FROM t1");
while(rs.next()) {
    f1 = rs.getInt(1);
    f2 = rs.getString(2);
    print(f1 + " " + f2);
}
rs.close();
stmt.close();
con.close();

JPA - native driver (VMS):

JPA is the Java standard for ORM.

We will use Hibernates JPA implementation.

Oracle provides two JDBC drivers for Rdb:

Here we will use native driver.

Oracle provides a Rdb dialect for Hibernate.

Oracle's Rdb dialect works with Hibernate 3.6 - it does not work with Hibernate 5.0 - I have not tested with other versions.

For details on JPA including updates and parameters see here.

META-INF/persistence.xml:

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
   <persistence-unit name="Rdb1">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <class>T1</class>
      <exclude-unlisted-classes/>
      <properties>
          <!--<property name="show_sql" value="true"/>-->
          <property name="hibernate.connection.driver_class" value="oracle.rdb.jdbc.rdbNative.Driver"/>
          <property name="hibernate.connection.url" value="jdbc:rdbNative:disk4:[rdb]test"/>
          <property name="hibernate.connection.username" value="arne"/>
          <property name="hibernate.connection.password" value="hemmeligt"/>
          <property name="hibernate.connection.pool_size" value="5"/>
          <property name="hibernate.dialect" value="org.hibernate.dialect.RdbDialect"/>
      </properties>
   </persistence-unit>
</persistence>

T1.java:

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="t1")
public class T1 {
    private int f1;
    private String f2;
    public T1() {
        this(0, "");
    }
    public T1(int f1, String f2) {
        this.f1 = f1;
        this.f2 = f2;
    }
    @Id
    @Column(name="f1")
    public int getF1() {
        return f1;
    }
    public void setF1(int f1) {
        this.f1 = f1;
    }
    @Column(name="f2")
    public String getF2() {
        return f2;
    }
    public void setF2(String f2) {
       this.f2 = f2;
    }
}

Rdb1X.java:

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;

public class Rdb1X {
    public static void main(String[] args) {
        System.out.println("Rdb from Java (JPA, native)");
        // disable Hibernate logging (outcomment for debugging)
        Logger.getLogger("org.hibernate").setLevel(Level.OFF);
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("Rdb1");
        EntityManager em = emf.createEntityManager();
        TypedQuery<T1> q = em.createQuery("SELECT o FROM T1 AS o", T1.class);
        List<T1> res = q.getResultList();
        for(T1 o : res) {
            System.out.println(o.getF1() + " " + o.getF2());
        }
        em.close();
        emf.close();
    }
}

Build and run - VMS:

$ javac -cp 'hibpath' Rdb1X.java T1.java
$ java -cp .:'hibpath':rdbhib.jar:rdbnativev5.jar "Rdb1X"

T1.java:

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="t1")
public class T1 {
    private int f1;
    private String f2;
    public T1() {
        this(0, "");
    }
    public T1(int f1, String f2) {
        this.f1 = f1;
        this.f2 = f2;
    }
    @Id
    @Column(name="f1")
    public int getF1() {
        return f1;
    }
    public void setF1(int f1) {
        this.f1 = f1;
    }
    @Column(name="f2")
    public String getF2() {
        return f2;
    }
    public void setF2(String f2) {
       this.f2 = f2;
    }
}

jrdb1x.py:

from java.util.logging import Level
from java.util.logging import Logger

from javax.persistence import Persistence

import T1

print("Rdb from JVM Python (JPA, native)")
# disable Hibernate logging (outcomment for debugging)
Logger.getLogger("org.hibernate").setLevel(Level.OFF)
emf = Persistence.createEntityManagerFactory("Rdb1")
em = emf.createEntityManager()
q = em.createQuery("SELECT o FROM T1 AS o", T1)
res = q.getResultList();
for o in res:
    print('%d %s' % (o.f1, o.f2))
em.close()
emf.close()

JPA - thin driver (VMS,WIN,NIX):

JPA is the Java standard for ORM.

We will use Hibernates JPA implementation.

Oracle provides two JDBC drivers for Rdb:

Here we will use thin driver.

Oracle provides a Rdb dialect for Hibernate.

Oracle's Rdb dialect works with Hibernate 3.6 - it does not work with Hibernate 5.0 - I have not tested with other versions.

For details on JPA including updates and parameters see here.

META-INF/persistence.xml:

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
   <persistence-unit name="Rdb2">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <class>T1</class>
      <exclude-unlisted-classes/>
      <properties>
          <!--<property name="show_sql" value="true"/>-->
          <property name="hibernate.connection.driver_class" value="oracle.rdb.jdbc.rdbThin.Driver"/>
          <property name="hibernate.connection.url" value="jdbc:rdbThin://192.168.0.10:1701/disk4:[rdb]test"/>
          <property name="hibernate.connection.username" value="arne"/>
          <property name="hibernate.connection.password" value="hemmeligt"/>
          <property name="hibernate.connection.pool_size" value="5"/>
          <property name="hibernate.dialect" value="org.hibernate.dialect.RdbDialect"/>
      </properties>
   </persistence-unit>
</persistence>

T1.java:

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="t1")
public class T1 {
    private int f1;
    private String f2;
    public T1() {
        this(0, "");
    }
    public T1(int f1, String f2) {
        this.f1 = f1;
        this.f2 = f2;
    }
    @Id
    @Column(name="f1")
    public int getF1() {
        return f1;
    }
    public void setF1(int f1) {
        this.f1 = f1;
    }
    @Column(name="f2")
    public String getF2() {
        return f2;
    }
    public void setF2(String f2) {
       this.f2 = f2;
    }
}

Rdb2X.java:

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;

public class Rdb2X {
    public static void main(String[] args) {
        System.out.println("Rdb from Java (JPA, thin)");
        // disable Hibernate logging (outcomment for debugging)
        Logger.getLogger("org.hibernate").setLevel(Level.OFF);
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("Rdb2");
        EntityManager em = emf.createEntityManager();
        TypedQuery<T1> q = em.createQuery("SELECT o FROM T1 AS o", T1.class);
        List<T1> res = q.getResultList();
        for(T1 o : res) {
            System.out.println(o.getF1() + " " + o.getF2());
        }
        em.close();
        emf.close();
    }
}

Build and run - Windows:

javac -cp %HIBPATH% Rdb2X.java T1.java
java -cp .;%HIBPATH%;rdbhib.jar;rdbthinv8.jar Rdb2X

Build and run - VMS:

$ javac -cp 'hibpath' Rdb2X.java T1.java
$ java -cp .:'hibpath':rdbhib.jar:rdbthinv5.jar "Rdb2X"

T1.kt:

import javax.persistence.*

@Entity
@Table(name="t1")
data class T1 (@Id @Column(name="f1") val f1: Int = 0,
               @Column(name="f2") val f2: String = "")

Rdb2X.kt:

import java.util.logging.*
import java.util.logging.Logger;

import javax.persistence.*

fun main(args: Array<String>) {
    println("Rdb from Kotlin (JPA, thin)")
    Logger.getLogger("org.hibernate").setLevel(Level.OFF)
    val emf = Persistence.createEntityManagerFactory("Rdb2")
    val em = emf.createEntityManager()
    val q = em.createQuery("SELECT o FROM T1 AS o", T1::class.java)
    val res = q.getResultList()
    for(o in res) {
        println("${o.f1} ${o.f2}")
    }
    em.close()
    emf.close()
}

Build and run - Windows:

call %KOTLIN%\bin\kotlinc -cp %HIBPATH% -d . Rdb2X.kt T1.kt 
java -cp .;%KOTLIN%\lib\*;%HIBPATH%;rdbhib.jar;rdbthinv8.jar Rdb2XKt

T1.groovy:

import javax.persistence.*

@Entity
@Table(name="t1")
class T1 {
    @Id
    @Column(name="f1")
    int f1
    @Column(name="f2")
    String f2
}

Rdb2X.groovy:

import java.util.logging.*

import javax.persistence.*

println("Rdb from Groovy (JPA, thin)")
// disable Hibernate logging (outcomment for debugging)
Logger.getLogger("org.hibernate").setLevel(Level.OFF)
emf = Persistence.createEntityManagerFactory("Rdb2")
em = emf.createEntityManager()
q = em.createQuery("SELECT o FROM T1 AS o", T1.class)
res = q.getResultList()
for(o in res) {
    println("${o.f1} ${o.f2}")
}
em.close()
emf.close()

Build and run - Windows:

call %GROOVY%\bin\groovyc -cp hibernate-jpa-2.0-api-1.0.0.Final.jar Rdb2X.groovy T1.groovy
java -cp .;%GROOVY%\lib\*;%HIBPATH%;rdbhib.jar;rdbthinv8.jar Rdb2X

T1.java:

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="t1")
public class T1 {
    private int f1;
    private String f2;
    public T1() {
        this(0, "");
    }
    public T1(int f1, String f2) {
        this.f1 = f1;
        this.f2 = f2;
    }
    @Id
    @Column(name="f1")
    public int getF1() {
        return f1;
    }
    public void setF1(int f1) {
        this.f1 = f1;
    }
    @Column(name="f2")
    public String getF2() {
        return f2;
    }
    public void setF2(String f2) {
       this.f2 = f2;
    }
}

jrdb2x.py:

from java.util.logging import Level
from java.util.logging import Logger

from javax.persistence import Persistence

import T1

print("Rdb from JVM Python (JPA, thin)")
# disable Hibernate logging (outcomment for debugging)
Logger.getLogger("org.hibernate").setLevel(Level.OFF)
emf = Persistence.createEntityManagerFactory("Rdb2")
em = emf.createEntityManager()
q = em.createQuery("SELECT o FROM T1 AS o", T1)
res = q.getResultList();
for o in res:
    print('%d %s' % (o.f1, o.f2))
em.close()
emf.close()

DB API 2.0 - native driver (VMS):

Jython (JVM Python) can use standard Python DB API 2.0 to access a database via the zxJDBC module and a standard JDBC driver.

jrdb1z.py:

from com.ziclix.python.sql import zxJDBC

print('Rdb from JVM Python (DB API 2.0 via zxJDBC, native)')
con = zxJDBC.connect('jdbc:rdbNative:disk4:[rdb]test', None, None, 'oracle.rdb.jdbc.rdbNative.Driver')
c = con.cursor()
c.execute('SELECT f1,f2 FROM t1')
data = c.fetchall()
c.close()
for row in data:
    print('%d %s' % (row[0], row[1]))
con.close()

DB API 2.0 - thin driver (VMS,WIN,NIX):

Jython (JVM Python) can use standard Python DB API 2.0 to access a database via the zxJDBC module and a standard JDBC driver.

jrdb2z.py:

from com.ziclix.python.sql import zxJDBC

print('Rdb from JVM Python (DB API 2.0 via zxJDBC, thin)')
con = zxJDBC.connect('jdbc:rdbThin://192.168.0.10:1701/dka4:[rdb]test', 'arne', 'hemmeligt', 'oracle.rdb.jdbc.rdbThin.Driver')
c = con.cursor()
c.execute('SELECT f1,f2 FROM t1')
data = c.fetchall()
c.close()
for row in data:
    print('%d %s' % (row[0], row[1]))
con.close()

.NET languages:

ADO.NET (WIN,NIX):

ADO.NET is .NET basic database API.

Oracle provides an ADO.NET provider for Rdb as part of Oracle Rdb Data Provider (ORDP).

For details on ADO.NET API including SQL updates, parameters and how to make the code database independent see here.

rdb1.cs:

using System;
using Oracle.DataAccess.RdbClient;

public class Program
{
    public static void Main(String[] args) 
    {
        Console.WriteLine("Rdb from C# (ADO.NET)");
        using(RdbConnection con = new RdbConnection("Server=192.168.0.10:GENERIC;Database=disk4:[rdb]test;User Id=arne;Password=hemmeligt;"))
        {
            con.Open();
            using(RdbCommand cmd = new RdbCommand("SELECT f1,f2 FROM t1", con))
            {
                using(RdbDataReader rdr = cmd.ExecuteReader())
                {
                    while(rdr.Read())
                    {
                        Console.WriteLine((int)rdr["f1"] + " " + (string)rdr["f2"]);
                    }
                }
            }
        }
    }
}

Build and run - Windows:

csc -platform:x86 /r:Oracle.DataAccess.Rdb.dll rdb1.cs
rdb1

rdb1.vb:

Imports System
Imports Oracle.DataAccess.RdbClient

Public Class Program
    Public Shared Sub Main(args As [String]())
        Console.WriteLine("Rdb from VB.NET (ADO.NET)")
        Using con As New RdbConnection("Server=192.168.0.10:GENERIC;Database=disk4:[rdb]test;User Id=arne;Password=hemmeligt;")
            con.Open()
            Using cmd As New RdbCommand("SELECT f1,f2 FROM t1", con)
                Using rdr As RdbDataReader = cmd.ExecuteReader()
                    While rdr.Read()
                        Console.WriteLine(rdr("f1") & " " & rdr("f2"))
                    End While
                End Using
            End Using
        End Using
    End Sub
End Class

Build and run - Windows:

vbc -platform:x86 /r:Oracle.DataAccess.Rdb.dll rdb1.vb
rdb1

ODBC (WIN):

ADO.NET can use an ODBC driver.

Oracle provides an ODBC driver for Rdb that needs to be installed.

The example assumes a DSN has been defined in ODBC manager.

It is strongly recommended using the databases ADO.NET provider instead of the ODBC driver. Mixing .NET and native for database access is not optimal.

rdb2.cs:

using System;
using System.Data.Odbc;

public class Program
{
    public static void Main(String[] args) 
    {
        Console.WriteLine("Rdb from C# (ODBC)");
        using(OdbcConnection con = new OdbcConnection("Dsn=ARNE1_RDB;Uid=arne;Pwd=hemmeligt"))
        {
            con.Open();
            using(OdbcCommand cmd = new OdbcCommand("SELECT f1,f2 FROM t1", con))
            {
                using(OdbcDataReader rdr = cmd.ExecuteReader())
                {
                    while(rdr.Read())
                    {
                        Console.WriteLine((int)rdr["f1"] + " " + (string)rdr["f2"]);
                    }
                }
            }
        }
    }
}

Build and run - Windows:

csc rdb2.cs
rdb2

rdb2.vb:

Imports System
Imports System.Data.Odbc

Public Class Program
    Public Shared Sub Main(args As [String]())
        Console.WriteLine("Rdb from VB.NET (ODBC)")
        Using con As New OdbcConnection("Dsn=ARNE1_RDB;Uid=arne;Pwd=hemmeligt")
            con.Open()
            Using cmd As New OdbcCommand("SELECT f1,f2 FROM t1", con)
                Using rdr As OdbcDataReader = cmd.ExecuteReader()
                    While rdr.Read()
                        Console.WriteLine(rdr("f1") & " " & rdr("f2"))
                    End While
                End Using
            End Using
        End Using
    End Sub
End Class

Build and run - Windows:

vbc rdb2.vb
rdb2

EF (WIN,NIX):

Entity Framework (EF) is a common ORM for .NET.

Oracle Rdb Data Provide (ORDP) supports EF.

For details on EF including updates and parameters see here.

Note that the version of ORDP EF and the version of core EF need to match. I got Oracle.Rdb.EntityFramework version 6.0.1.1 with EntityFramework version 6.0.0 working. I strongly recommend using NuGet to get Oracle.Rdb.EntityFramework and let it fetch the right version of EntityFramework.

The example will use code first approach.

rdb1x.exe.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </configSections>
    <connectionStrings>
        <add name="Rdb" connectionString="Server=192.168.0.10:GENERIC;Database=disk4:[rdb]test;User Id=arne;Password=hemmeligt;" providerName="Oracle.DataAccess.RdbClient" />
    </connectionStrings>
    <entityFramework>
        <defaultConnectionFactory type="Oracle.DataAccess.RdbClient.Entity.RdbConnectionFactory, Oracle.Rdb.EntityFramework"/>
        <providers>
            <provider invariantName="Oracle.DataAccess.RdbClient" type="Oracle.DataAccess.RdbClient.RdbProviderServices, Oracle.Rdb.EntityFramework"/>
        </providers>
    </entityFramework>
</configuration>

rdb1x.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;

// Note: table names and column names are case sensitive
[Table("T1")]
public class T1
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    [Column("F1")]
    public int F1 { get; set; }
    [Column("F2")]
    public string F2 { get; set; }
}

public class MySqlDbContext : DbContext
{
    public MySqlDbContext() : base("Rdb")
    {
    }
    public DbSet<T1> T1 { get; set; }
}

public class Program
{
    public static void Main(String[] args) 
    {
        Console.WriteLine("Rdb from C# (EF)");
        using(MySqlDbContext db = new MySqlDbContext())
        {
            List<T1> res =  db.T1.ToList();
            foreach(T1 o in res)
            {
                Console.WriteLine(o.F1 + " " + o.F2);
            }
        }
    }
}

Build and run - Windows:

csc -platform:x86 /r:System.ComponentModel.DataAnnotations.dll /r:EntityFramework.dll rdb1x.cs
rdb1x

rdb1x.vb:

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel.DataAnnotations
Imports System.ComponentModel.DataAnnotations.Schema
Imports System.Data.Entity
Imports System.Linq

' Note: table names and column names are case sensitive
<Table("T1")> _
Public Class T1
    <Key> _
    <DatabaseGenerated(DatabaseGeneratedOption.None)> _
    <Column("F1")> _
    Public Property F1() As Integer
    <Column("F2")> _
    Public Property F2() As String
End Class

Public Class MySqlDbContext
    Inherits DbContext
    Public Sub New()
        MyBase.New("Rdb")
    End Sub
    Public Property T1() As DbSet(Of T1)
End Class

Public Class Program
    Public Shared Sub Main(args As [String]())
        Console.WriteLine("Rdb from VB.NET (EF)")
        Using db As New MySqlDbContext()
            Dim res As List(Of T1) = db.T1.ToList()
            For Each o As T1 In res
                Console.WriteLine(o.F1 & " " & o.F2)
            Next
        End Using
    End Sub
End Class

Build and run - Windows:

vbc -platform:x86 /r:System.ComponentModel.DataAnnotations.dll /r:EntityFramework.dll rdb1x.vb
rdb1x

Python:

DB API 2.0 (VMS):

A DB API 2.0 compliant rdb module is available (may even be pre-installed with VMS Python).

For details on DB API 2.0 including SQL updates and parameters see here.

rdb1.py:

from rdb import dbapi2

print('Rdb from Python')
con = dbapi2.connect(database='disk4:[rdb]test')
c = con.cursor()
c.execute('SELECT f1,f2 FROM t1')
data = c.fetchall()
c.close()
for row in data:
    print('%d %s' % (row[0], row[1]))
con.close()

RDB (VMS)

The rdb module also has an RDB specific API.

rdb1.py:

import rdb

print('Rdb from Python')
rdb.attachDB('disk4:[rdb]test')
curs = rdb.statement('SELECT f1,f2 FROM t1')
rdb.read_only() # necessary to avoid a transaction error
curs.execute()
for row in curs:
    print('%d %s' % (row[0], row[1]))

Jython options:

Options for Jython (JVM Python) are described under JVM languages.

PHP:

ODBC (WIN):

PHP supports ODBC.

Oracle provides an ODBC driver for Rdb that needs to be installed.

The example assumes a DSN has been defined in ODBC manager.

rdb2.php:

<?php
echo "Rdb from PHP (ODBC)\r\n";
$con = odbc_connect('ARNE1_RDB', 'arne', 'hemmeligt');
$stmt = odbc_prepare($con, 'SELECT f1,f2 FROM t1');
odbc_execute($stmt, array());
while(odbc_fetch_row($stmt)){
    $f1 = odbc_result($stmt, 'f1');
    $f2 = odbc_result($stmt, 'f2');
    echo "$f1 $f2\r\n";
}
odbc_free_result($stmt);
odbc_close($con);
?>

PDO + ODBC (WIN):

PHP has a standard database API called PDO.

PDO supports ODBC.

Oracle provides an ODBC driver for Rdb that needs to be installed.

The example assumes a DSN has been defined in ODBC manager.

rdb2p.php:

<?php
echo "Rdb from PHP (PDO,ODBC)\r\n";
$con = new PDO('odbc:DSN=ARNE1_RDB;UID=arne;PWD=hemmeligt');
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$stmt = $con->prepare('SELECT f1,f2 FROM t1');
$stmt->execute(array());
while($row = $stmt->fetch()) {
    $f1 = $row['F1'];
    $f2 = $row['F2'];
    echo "$f1 $f2\r\n";
}
?>

VBS:

ODBC (WIN):

VBS supports ADO and ADO can use an ODBC driver.

Oracle provides an ODBC driver for Rdb that needs to be installed.

The example assumes a DSN has been defined in ODBC manager.

rdb.vbs:

WScript.Echo "Rdb from VBS (ODBC)"
Set con = CreateObject("ADODB.Connection")
con.Open "Dsn=ARNE1_RDB;Uid=arne;Pwd=hemmeligt;"
Set cmd = CreateObject("ADODB.Command")
cmd.ActiveConnection = con
cmd.CommandText = "SELECT f1,f2 FROM t1"
Set rs = cmd.Execute
Do While Not rs.EOF
    WScript.Echo rs("f1") & " " & rs("f2")
    rs.MoveNext
Loop
Set rs = Nothing
Set cmd = Nothing
Set con = Nothing

MySQL:

Background:

MySQL is a very widely used database. It was introduced in 1995. It was sold to Oracle in 2010. Same year a fork MariaDB was created. And today MariaDB is as widely used as MySQL.

MySQL is available on many platforms Linux, Windows, macOS, Solaris etc.. There are two ports to VMS:

MySQL uses a traditional database server architecture with all client application accessing a database server via network:

MySQL architecture

C:

libmysql (VMS,WIN,NIX):

MySQL C API usually called libmysql typical comes with MySQL.

For details on MySQL C API including SQL updates, parameters and error handling see here.

mysql1.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SOCKET int
#include <mysql.h>

#define F2_MAX_LEN 50

int main()
{
    MYSQL *con;
    con = mysql_init(NULL);
    con = mysql_real_connect(con, "192.168.0.10", "root", "", "test", 3306, NULL, 0);
    MYSQL_STMT *stmt;
    MYSQL_BIND out[2];
    char *sqlstr, f2[F2_MAX_LEN + 1];
    unsigned long int lenf2;
    int stat, f1;
    printf("MySQL from C (libmysql)\n");
    stmt = mysql_stmt_init(con);
    sqlstr = "SELECT f1,f2 FROM t1";
    stat = mysql_stmt_prepare(stmt, sqlstr, strlen(sqlstr));
    stat = mysql_stmt_execute(stmt);
    memset(out, 0, sizeof(out));
    out[0].buffer_type = MYSQL_TYPE_LONG;
    out[0].buffer = &f1;
    out[0].buffer_length = sizeof(f1);
    out[1].buffer_type = MYSQL_TYPE_STRING;
    out[1].buffer = f2;
    out[1].buffer_length = sizeof(f2);
    out[1].length = &lenf2;
    stat = mysql_stmt_bind_result(stmt, out);
    stat = mysql_stmt_store_result(stmt);
    while(!mysql_stmt_fetch(stmt))
    {
        f2[lenf2] = 0;
        printf("%d %s\n", f1, f2);
    }
    mysql_stmt_free_result(stmt);
    mysql_close(con);
    return 0;
}

Build and run - VMS:

$ cc /include=mysql055_root:[include.mysql] /names=as_is mysql1.c
$ link mysql1 + sys$input/opt
mysql055_root:[lib.alpha]libclientlib/lib
mysql055_root:[lib.alpha]libsql/lib
mysql055_root:[lib.alpha]libmysys/lib
mysql055_root:[lib.alpha]libdbug/lib
mysql055_root:[lib.alpha]libstrings/lib
mysql055_root:[lib.alpha]libvio/lib
mysql055_root:[lib.alpha]libz/lib
mysql055_root:[lib.alpha]ssl_libssl32/lib
mysql055_root:[lib.alpha]ssl_libcrypto32/lib
$
$ run mysql1

(MariaDB 5.5 on VMS Alpha)

Build and run - Windows:

gcc -I%MYSQL%\include -L%MYSQL%\lib mysql1.c -lmysql -o mysql1.exe
mysql1

ODBC (WIN):

MySQL provides an ODBC driver called MySQL Connector/ODBC that needs to be installed.

Standard ODBC API. For details on ODBC API including SQL updates, parameters and error handling see here.

The example assumes a DSN has been defined in ODBC manager.

mysql2.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <windows.h>
#include <sql.h>
#include <sqlext.h>

#define F2_MAX_LEN 50

static const char *dsn = "ARNE1_MYSQL";
static const char *un = "";
static const char *pw = "";

int main()
{
    SQLHENV env;
    SQLHDBC con;
    SQLHSTMT stmt;
    long int f1;
    char *sqlstr, f2[F2_MAX_LEN + 1];
    SQLLEN lenf2;
    int stat;
    printf("MySQL from C (ODBC)\n");
    stat = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
    stat = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
    stat = SQLAllocHandle(SQL_HANDLE_DBC, env, &con);
    stat = SQLConnect(con, (SQLCHAR *)dsn, (SQLSMALLINT)strlen(dsn),
                           (SQLCHAR *)un, (SQLSMALLINT)strlen(un),
                           (SQLCHAR *)pw, (SQLSMALLINT)strlen(pw));
    sqlstr = "SELECT f1,f2 FROM t1";
    stat = SQLAllocHandle(SQL_HANDLE_STMT, con, &stmt);
    stat = SQLExecDirect(stmt, (SQLCHAR *)sqlstr, strlen(sqlstr));
    stat = SQLBindCol(stmt, 1, SQL_C_LONG, &f1, 0, NULL);
    stat = SQLBindCol(stmt, 2, SQL_C_CHAR, f2, sizeof(f2), &lenf2);
    for(;;)
    {
        stat = SQLFetch(stmt);
        if((stat != SQL_SUCCESS) && (stat != SQL_SUCCESS_WITH_INFO)) break;
        f2[lenf2] = 0;
        printf("%d %s\n", f1, f2);
    }
    SQLCloseCursor(stmt);
    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
    SQLDisconnect(con);
    SQLFreeHandle(SQL_HANDLE_DBC, con);
    SQLFreeHandle(SQL_HANDLE_ENV, env);
    return 0;
}

Build and run - Windows:

gcc mysql2.c -lodbc32 -o mysql2.exe
mysql2

Pascal:

pmysql + libmysql (VMS):

Due to VMS calling convention it is possible to call a C library like libmysql from Pascal.

To make it a little easier I have created a wrapper pmysql that are also open source and can be downloaded here.

mysql.pas:

[inherit('pmysqldir:pmysql2', 'pmysqldir:pmysql', 'pmysqldir:mysql')]
program mysql(input, output);

var
   con : mysql_ptr;
   stmt : mysql_stmt_ptr;
   stat : integer;
   f1 : integer;
   f2 : longpstr(255);

begin
   writeln('MySQL from Pascal (pmysql, libmysql)');
   con := pmysql_init;
   con := pmysql_real_connect(con, '192.168.0.10', 'root', '', 'test');
   stmt := pmysql_prepare(con, 'SELECT f1,f2 FROM t1');
   stat := pmysql_get_result_start(stmt, long_arg(f1), longstring_arg(f2));
   while pmysql_stmt_fetch(stmt) = 0 do begin
      writeln(f1, ' ', stdstr(f2));
   end;
   pmysql_stmt_free_result(stmt);
   pmysql_close(con);
end.

Build and run - VMS:

$ pascal mysql
$ link mysql + sys$input/opt + pmysqldir:mysql55axp/opt
pmysqldir:pmysql2
pmysqldir:pmysql
pmysqldir:mysql
$
$ run mysql

SQLDB (WIN,NIX):

FPC comes with SQLDB unit for database access. SQLDB supports MySQL.

For details on SQLDB API including SQL updates, parameters and error handling see here.

mysql1.pas:

program mysql1(input, output);

uses
  SQLDB, MySQL55Conn;

var
  con : TSQLConnection;
  tx : TSQLTransaction;
  q : TSQLQuery;
  f1 : integer;
  f2 : string;

begin
  writeln('MySQL from Pascal (SQLDB, MySQL55)');
  con := TMySQL55Connection.Create(nil);
  con.HostName := '192.168.0.10';
  con.UserName := 'root';
  con.Password := '';
  con.DatabaseName := 'test';
  con.Open;
  tx := TSQLTransaction.Create(nil);
  con.Transaction := tx;
  q := TSQLQuery.Create(nil);
  q.DataBase := con;
  q.SQL.Text := 'SELECT f1,f2 FROM t1';
  q.Open;
  while not q.EOF do begin
    f1 := q.FieldByName('f1').AsInteger;
    f2 := q.FieldByName('f2').AsString;
    writeln(f1, ' ', f2);
    q.Next;
  end;
  q.Close;
  q.Free;
  con.Close;
  con.Free;
end.

Build and run - Windows:

fpc mysql1.pas
mysql1

SQLDB + ODBC (WIN):

FPC comes with SQLDB unit for database access. SQLDB supports ODBC.

MySQL provides an ODBC driver called MySQL Connector/ODBC that needs to be installed.

For details on SQLDB API including SQL updates, parameters and error handling see here.

The example assumes a DSN has been defined in ODBC manager.

mysql2.pas:

program mysql2(input, output);

uses
  SQLDB, ODBCConn;

var
  con : TSQLConnection;
  tx : TSQLTransaction;
  q : TSQLQuery;
  f1 : integer;
  f2 : string;

begin
  writeln('MySQL from Pascal (SQLDB, ODBC)');
  con := TODBCConnection.Create(nil);
  con.DatabaseName := 'ARNE1_MYSQL';
  con.Open;
  tx := TSQLTransaction.Create(nil);
  con.Transaction := tx;
  q := TSQLQuery.Create(nil);
  q.DataBase := con;
  q.SQL.Text := 'SELECT f1,f2 FROM t1';
  q.Open;
  while not q.EOF do begin
    f1 := q.FieldByName('f1').AsInteger;
    f2 := q.FieldByName('f2').AsString;
    writeln(f1, ' ', f2);
    q.Next;
  end;
  q.Close;
  q.Free;
  con.Close;
  con.Free;
end.

Build and run - Windows:

fpc mysql2.pas
mysql2

JVM languages:

JDBC (VMS,WIN,NIX):

JDBC is Java basic database API.

MySQL provides a JDBC driver called MySQL Connector/Java.

For details on JDBC API including SQL updates and parameters see here.

MySQL.java:

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;

public class MySQL {
    public static void main(String[] args) throws Exception {
        System.out.println("MySQL from Java (JDBC)");
        Class.forName("com.mysql.jdbc.Driver");
        Connection con = DriverManager.getConnection("jdbc:mysql://192.168.0.10:3306/test", "root", "");
        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT f1,f2 FROM t1");
        while(rs.next()) {
            int f1 = rs.getInt(1);
            String f2 = rs.getString(2);
            System.out.println(f1 + " " + f2);
        }
        rs.close();
        stmt.close();
        con.close();
    }
}

Build and run - Windows:

javac MySQL.java
java -cp .;mysql-connector-java-5.1.36-bin.jar MySQL

Build and run - VMS:

$ javac MySQL.java
$ java -cp .:mysql-connector-java-5_1_36-bin.jar "MySQL"

MySQL.kt:

import java.sql.*

fun main(args: Array<String>) {
    println("MySQL from Kotlin (JDBC)")
    Class.forName("com.mysql.jdbc.Driver")
    val con = DriverManager.getConnection("jdbc:mysql://192.168.0.10:3306/test", "root", "")
    val stmt = con.createStatement()
    val rs = stmt.executeQuery("SELECT f1,f2 FROM t1")
    while(rs.next()) {
        val f1 = rs.getInt(1);
        val f2 = rs.getString(2);
        println("$f1 $f2");
    }
    rs.close()
    stmt.close()
    con.close()
}

Build and run - Windows:

call %KOTLIN%\bin\kotlinc -d . MySQL.kt
java -cp .;%KOTLIN%\lib\*;mysql-connector-java-5.1.36-bin.jar MySQLKt

MySQL.groovy:

import java.sql.*

println("MySQL from Groovy (JDBC, thin)")
Class.forName("com.mysql.jdbc.Driver")
con = DriverManager.getConnection("jdbc:mysql://192.168.0.10:3306/test", "root", "")
stmt = con.createStatement()
rs = stmt.executeQuery("SELECT f1,f2 FROM t1")
while(rs.next()) {
    f1 = rs.getInt(1)
    f2 = rs.getString(2)
    println("$f1 $f2")
}
rs.close()
stmt.close()
con.close()

Build and run - Windows:

call %GROOVY%\bin\groovyc MySQL.groovy
java -cp .;%GROOVY%\lib\*;mysql-connector-java-5.1.36-bin.jar MySQL 

jmysql.py:

from java.lang import Class
from java.sql import DriverManager

from com.mysql.jdbc import Driver # replaces Class.forName('com.mysql.jdbc.Driver')

print('MySQL from JVM Python (JDBC)')
con = DriverManager.getConnection('jdbc:mysql://192.168.0.10:3306/test', 'root', '')
stmt = con.createStatement()
rs = stmt.executeQuery('SELECT f1,f2 FROM t1')
while rs.next():
    f1 = rs.getInt(1)
    f2 = rs.getString(2)
    print(str(f1) + ' ' + f2)
rs.close()
stmt.close()
con.close()

jmysql.js:

importClass(Packages.java.lang.Class);
importClass(Packages.java.sql.DriverManager);

print("MySQL from JVM JavaScript (JDBC)")
new Packages.com.mysql.jdbc.Driver(); //replaces Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://192.168.0.10:3306/test", "root", "");
stmt = con.createStatement();
rs = stmt.executeQuery("SELECT f1,f2 FROM t1");
while(rs.next()) {
    f1 = rs.getInt(1);
    f2 = rs.getString(2);
    print(f1 + " " + f2);
}
rs.close();
stmt.close();
con.close();

JPA (VMS,WIN,NIX):

JPA is the Java standard for ORM.

We will use Hibernates JPA implementation.

Oracle provides a JDBC driver called MySQL Connector/Java:

Hibernate comes woth support for MySQL dialect.

For details on JPA including updates and parameters see here.

META-INF/persistence.xml:

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
   <persistence-unit name="MySQL">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <class>T1</class>
      <exclude-unlisted-classes/>
      <properties>
          <!--<property name="show_sql" value="true"/>-->
          <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
          <property name="hibernate.connection.url" value="jdbc:mysql://192.168.0.10:3306/test"/>
          <property name="hibernate.connection.username" value="root"/>
          <property name="hibernate.connection.password" value=""/>
          <property name="hibernate.connection.pool_size" value="5"/>
      </properties>
   </persistence-unit>
   </persistence-unit>
</persistence>

T1.java:

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="t1")
public class T1 {
    private int f1;
    private String f2;
    public T1() {
        this(0, "");
    }
    public T1(int f1, String f2) {
        this.f1 = f1;
        this.f2 = f2;
    }
    @Id
    @Column(name="f1")
    public int getF1() {
        return f1;
    }
    public void setF1(int f1) {
        this.f1 = f1;
    }
    @Column(name="f2")
    public String getF2() {
        return f2;
    }
    public void setF2(String f2) {
       this.f2 = f2;
    }
}

MySQLX.java:

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;

public class MySQLX {
    public static void main(String[] args) {
        System.out.println("MySQL from Java (JPA)");
        // disable Hibernate logging (outcomment for debugging)
        Logger.getLogger("org.hibernate").setLevel(Level.OFF);
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("MySQL");
        EntityManager em = emf.createEntityManager();
        TypedQuery<T1> q = em.createQuery("SELECT o FROM T1 AS o", T1.class);
        List<T1> res = q.getResultList();
        for(T1 o : res) {
            System.out.println(o.getF1() + " " + o.getF2());
        }
        em.close();
        emf.close();
    }
}

Build and run - Windows:

javac -cp %HIBPATH% MySQLX.java T1.java
java -cp .;%HIBPATH%;mysql-connector-java-5.1.36-bin.jar MySQLX

Build and run - VMS:

$ javac -cp 'hibpath' MySQLX.java T1.java
$ java -cp .:'hibpath':mysql-connector-java-5_1_36-bin.jar "MySQLX"

T1.kt:

import javax.persistence.*

@Entity
@Table(name="t1")
data class T1 (@Id @Column(name="f1") val f1: Int = 0,
               @Column(name="f2") val f2: String = "")

MySQLX.kt:

import java.util.logging.*
import java.util.logging.Logger;

import javax.persistence.*

fun main(args: Array<String>) {
    println("MySQL from Kotlin (JPA)")
    Logger.getLogger("org.hibernate").setLevel(Level.OFF)
    val emf = Persistence.createEntityManagerFactory("MySQL")
    val em = emf.createEntityManager()
    val q = em.createQuery("SELECT o FROM T1 AS o", T1::class.java)
    val res = q.getResultList()
    for(o in res) {
        println("${o.f1} ${o.f2}")
    }
    em.close()
    emf.close()
}

Build and run - Windows:

call %KOTLIN%\bin\kotlinc -cp %HIBPATH% -d . MySQLX.kt T1.kt 
java -cp .;%KOTLIN%\lib\*;%HIBPATH%;mysql-connector-java-5.1.36-bin.jar MySQLXKt

T1.groovy:

import javax.persistence.*

@Entity
@Table(name="t1")
class T1 {
    @Id
    @Column(name="f1")
    int f1
    @Column(name="f2")
    String f2
}

MySQLX.groovy:

import java.util.logging.*

import javax.persistence.*

println("MySQL from Groovy (JPA, thin)")
// disable Hibernate logging (outcomment for debugging)
Logger.getLogger("org.hibernate").setLevel(Level.OFF)
emf = Persistence.createEntityManagerFactory("MySQL")
em = emf.createEntityManager()
q = em.createQuery("SELECT o FROM T1 AS o", T1.class)
res = q.getResultList()
for(o in res) {
    println("${o.f1} ${o.f2}")
}
em.close()
emf.close()

Build and run - Windows:

call %GROOVY%\bin\groovyc -cp hibernate-jpa-2.0-api-1.0.0.Final.jar MySQLX.groovy T1.groovy
java -cp .;%GROOVY%\lib\*;%HIBPATH%;mysql-connector-java-5.1.36-bin.jar MySQLX

T1.java:

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="t1")
public class T1 {
    private int f1;
    private String f2;
    public T1() {
        this(0, "");
    }
    public T1(int f1, String f2) {
        this.f1 = f1;
        this.f2 = f2;
    }
    @Id
    @Column(name="f1")
    public int getF1() {
        return f1;
    }
    public void setF1(int f1) {
        this.f1 = f1;
    }
    @Column(name="f2")
    public String getF2() {
        return f2;
    }
    public void setF2(String f2) {
       this.f2 = f2;
    }
}

jmysqlx.py:

from java.util.logging import Level
from java.util.logging import Logger

from javax.persistence import Persistence

import T1

print("MySQL from JVM Python (JPA)")
# disable Hibernate logging (outcomment for debugging)
Logger.getLogger("org.hibernate").setLevel(Level.OFF)
emf = Persistence.createEntityManagerFactory("MySQL")
em = emf.createEntityManager()
q = em.createQuery("SELECT o FROM T1 AS o", T1)
res = q.getResultList();
for o in res:
    print('%d %s' % (o.f1, o.f2))
em.close()
emf.close()

DB API 2.0 (VMS,WIN,NIX):

Jython (JVM Python) can use standard Python DB API 2.0 to access a database via the zxJDBC module and a standard JDBC driver.

jmysqlz.py:

from com.ziclix.python.sql import zxJDBC

print('MySQL from JVM Python (DB API 2.0 via zxJDBC)')
con = zxJDBC.connect('jdbc:mysql://192.168.0.10:3306/test', 'root', '', 'com.mysql.jdbc.Driver')
c = con.cursor()
c.execute('SELECT f1,f2 FROM t1')
data = c.fetchall()
c.close()
for row in data:
    print('%d %s' % (row[0], row[1]))
con.close()

.NET languages:

ADO.NET (WIN,NIX):

ADO.NET is .NET basic database API.

MySQL provides an ADO.NET provider called MySQL Connector/.NET.

For details on ADO.NET API including SQL updates, parameters and how to make the code database independent see here.

mysql1.cs:

using System;
using MySql.Data.MySqlClient;

public class Program
{
    public static void Main(String[] args) 
    {
        Console.WriteLine("MySQL from C# (ADO.NET)");
        using(MySqlConnection con = new MySqlConnection("Server=192.168.0.10;Port=3306;Database=test;User Id=root;Password="))
        {
            con.Open();
            using(MySqlCommand cmd = new MySqlCommand("SELECT f1,f2 FROM t1", con))
            {
                using(MySqlDataReader rdr = cmd.ExecuteReader())
                {
                    while(rdr.Read())
                    {
                        Console.WriteLine((int)rdr["f1"] + " " + (string)rdr["f2"]);
                    }
                }
            }
        }
    }
}

Build and run - Windows:

csc /r:MySql.Data.dll mysql1.cs
mysql1

mysql1.vb:

Imports System
Imports MySql.Data.MySqlClient

Public Class Program
    Public Shared Sub Main(args As [String]())
        Console.WriteLine("MySQL from VB.NET (ADO.NET)")
        Using con As New MySqlConnection("Server=192.168.0.10;Port=3306;Database=test;User Id=root;Password=")
            con.Open()
            Using cmd As New MySqlCommand("SELECT f1,f2 FROM t1", con)
                Using rdr As MySqlDataReader = cmd.ExecuteReader()
                    While rdr.Read()
                        Console.WriteLine(rdr("f1") & " " & rdr("f2"))
                    End While
                End Using
            End Using
        End Using
    End Sub
End Class

Build and run - Windows:

vbc /r:MySql.Data.dll mysql1.vb
mysql1

ODBC (WIN,NIX):

ADO.NET can use an ODBC driver.

MySQL provides an ODBC driver called MySQL Connector/ODBC that needs to be installed.

The example assumes a DSN has been defined in ODBC manager.

It is strongly recommended using the databases ADO.NET provider instead of the ODBC driver. Mixing .NET and native for database access is not optimal.

mysql2.cs:

using System;
using System.Data.Odbc;

public class Program
{
    public static void Main(String[] args) 
    {
        Console.WriteLine("MySQL from C# (ODBC)");
        using(OdbcConnection con = new OdbcConnection("Dsn=ARNE1_MYSQL"))
        {
            con.Open();
            using(OdbcCommand cmd = new OdbcCommand("SELECT f1,f2 FROM t1", con))
            {
                using(OdbcDataReader rdr = cmd.ExecuteReader())
                {
                    while(rdr.Read())
                    {
                        Console.WriteLine((int)rdr["f1"] + " " + (string)rdr["f2"]);
                    }
                }
            }
        }
    }
}

Build and run - Windows:

csc mysql2.cs
mysql2

mysql2.vb:

Imports System
Imports System.Data.Odbc

Public Class Program
    Public Shared Sub Main(args As [String]())
        Console.WriteLine("MySQL from VB.NET (ODBC)")
        Using con As New OdbcConnection("Dsn=ARNE1_MYSQL")
            con.Open()
            Using cmd As New OdbcCommand("SELECT f1,f2 FROM t1", con)
                Using rdr As OdbcDataReader = cmd.ExecuteReader()
                    While rdr.Read()
                        Console.WriteLine(rdr("f1") & " " & rdr("f2"))
                    End While
                End Using
            End Using
        End Using
    End Sub
End Class

Build and run - Windows:

vbc mysql2.vb
mysql2

EF (WIN,NIX):

Entity Framework (EF) is a common ORM for .NET.

MySQL Connector/.NET supports EF.

For details on EF including updates and parameters see here.

Note that the version of MySQL Connector/.NET EF and the version of core EF need to match. I got MySQL Connector/.NET version 6.9.9 with EntityFramework version 6.2.0 working. I strongly recommend using NuGet to get a consistent pair.

The example will use code first approach.

mysql1x.exe.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </configSections>
    <connectionStrings>
        <add name="MySQL" connectionString="Server=192.168.0.10;Database=test;User Id=root;Password=" providerName="MySql.Data.MySqlClient" />
    </connectionStrings>
    <entityFramework>
        <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/>
        <providers>
            <provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6"/>
        </providers>
    </entityFramework>
</configuration>

mysql1x.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;

[Table("t1")]
public class T1
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    [Column("f1")]
    public int F1 { get; set; }
    [Column("f2")]
    public string F2 { get; set; }
}

public class MySqlDbContext : DbContext
{
    public MySqlDbContext() : base("MySQL")
    {
    }
    public DbSet<T1> T1 { get; set; }
}

public class Program
{
    public static void Main(String[] args) 
    {
        Console.WriteLine("MySQL from C# (EF)");
        using(MySqlDbContext db = new MySqlDbContext())
        {
            List<T1> res =  db.T1.ToList();
            foreach(T1 o in res)
            {
                Console.WriteLine(o.F1 + " " + o.F2);
            }
        }
    }
}

Build and run - Windows:

csc /r:System.ComponentModel.DataAnnotations.dll /r:EntityFramework.dll mysql1x.cs
mysql1x

mysql1x.vb:

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel.DataAnnotations
Imports System.ComponentModel.DataAnnotations.Schema
Imports System.Data.Entity
Imports System.Linq

<Table("t1")> _
Public Class T1
    <Key> _
    <DatabaseGenerated(DatabaseGeneratedOption.None)> _
    <Column("f1")> _
    Public Property F1() As Integer
    <Column("f2")> _
    Public Property F2() As String
End Class

Public Class MySqlDbContext
    Inherits DbContext
    Public Sub New()
        MyBase.New("MySQL")
    End Sub
    Public Property T1() As DbSet(Of T1)
End Class

Public Class Program
    Public Shared Sub Main(args As [String]())
        Console.WriteLine("MySQL from VB.NET (EF)")
        Using db As New MySqlDbContext()
            Dim res As List(Of T1) = db.T1.ToList()
            For Each o As T1 In res
                Console.WriteLine(o.F1 & " " & o.F2)
            Next
        End Using
    End Sub
End Class

Build and run - Windows:

vbc /r:System.ComponentModel.DataAnnotations.dll /r:EntityFramework.dll mysql1x.vb
mysql1x

Python:

DB API 2.0 (VMS,WIN,NIX):

A DB API 2.0 compliant pymysql module can be installed via pip.

For details on DB API 2.0 including SQL updates and parameters see here.

mysql.py:

import pymysql

print('MySQL from Python')
con = pymysql.connect(host='192.168.0.10',user='root',password='',db='test')
c = con.cursor()
c.execute('SELECT f1,f2 FROM t1')
data = c.fetchall()
c.close()
for row in data:
    print('%d %s' % (row[0], row[1]))
con.close()

Jython options:

Options for Jython (JVM Python) are described under JVM languages.

PHP:

mysqli (VMS,WIN,NIX):

PHP comes with mysqli extension to connect to MySQL.

For details on mysqli API including SQL updates and parameters see here.

mysql1.php:

<?php
echo "MySQL from PHP (mysqli)\r\n";
$con = mysqli_connect('192.168.0.10', 'root', '', 'test');
$stmt = mysqli_prepare($con, 'SELECT f1,f2 FROM t1');
mysqli_stmt_execute($stmt);
$rs = mysqli_stmt_get_result($stmt);
while($row = mysqli_fetch_array($rs, MYSQLI_ASSOC)) {
    $f1 = $row['f1'];
    $f2 = $row['f2'];
    echo "$f1 $f2\r\n";
}
mysqli_stmt_close($stmt);
mysqli_close($con);
?>

PDO + mysql (VMS,WIN,NIX):

PHP has a standard database API called PDO.

PDO supports MySQL.

For details on PDO API and MySQL including SQL updates and parameters see here.

mysql1p.php:

<?php
echo "MySQL from PHP (PDO,mysql)\r\n";
$con = new PDO('mysql:host=192.168.0.10;dbname=test', 'root', '');
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$stmt = $con->prepare('SELECT f1,f2 FROM t1');
$stmt->execute(array());
while($row = $stmt->fetch()) {
    $f1 = $row['f1'];
    $f2 = $row['f2'];
    echo "$f1 $f2\r\n";
}
?>

ODBC (WIN):

PHP supports ODBC.

Oracle provides an ODBC driver for Rdb that needs to be installed.

The example assumes a DSN has been defined in ODBC manager.

mysql2.php:

<?php
echo "MySQL from PHP (ODBC)\r\n";
$con = odbc_connect('ARNE1_MYSQL', '', '');
$stmt = odbc_prepare($con, 'SELECT f1,f2 FROM t1');
odbc_execute($stmt, array());
while(odbc_fetch_row($stmt)){
    $f1 = odbc_result($stmt, 'f1');
    $f2 = odbc_result($stmt, 'f2');
    echo "$f1 $f2\r\n";
}
odbc_free_result($stmt);
odbc_close($con);
?>

PDO + ODBC (WIN):

PHP has a standard database API called PDO.

PDO supports ODBC.

Oracle provides an ODBC driver for Rdb that needs to be installed.

The example assumes a DSN has been defined in ODBC manager.

mysql2p.php:

<?php
echo "MySQL from PHP (PDO,ODBC)\r\n";
$con = new PDO('odbc:DSN=ARNE1_MYSQL;UID=;PWD=');
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$stmt = $con->prepare('SELECT f1,f2 FROM t1');
$stmt->execute(array());
while($row = $stmt->fetch()) {
    $f1 = $row['f1'];
    $f2 = $row['f2'];
    echo "$f1 $f2\r\n";
}
?>

VBS:

ODBC (WIN):

VBS supports ADO and ADO can use an ODBC driver.

MySQL provides an ODBC driver called MySQL Connector/ODBC that needs to be installed.

The example assumes a DSN has been defined in ODBC manager.

WScript.Echo "MySQL from VBS (ODBC)"
Set con = CreateObject("ADODB.Connection")
con.Open "Dsn=ARNE1_MYSQL;"
Set cmd = CreateObject("ADODB.Command")
cmd.ActiveConnection = con
cmd.CommandText = "SELECT f1,f2 FROM t1"
Set rs = cmd.Execute
Do While Not rs.EOF
    WScript.Echo rs("f1") & " " & rs("f2")
    rs.MoveNext
Loop
Set rs = Nothing
Set cmd = Nothing
Set con = Nothing

SQLite:

Background:

SQLite is an open source embedded database first released in 2000.

It is available for VMS.

I consider SQLite to be more of an alternative to index-sequential files than to RDB and MySQL/MariaDB.

Since it is an embedded database then a database on VMS can only be used on VMS.

Note though that a database on VMS can be transferred to PC and used there as the on disk format is standardized across platforms.

SQLite uses a traditional embedded database architecture with all client application accessing a database directly:

SQLite architecture

C:

Standard C API (VMS):

SQLite comes with a standard C API.

sqlite.c:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "sqlite3.h"

int main()
{
    sqlite3 *con;
    sqlite3_stmt *ins, *sel;
    char *sqlstr = "SELECT f1,f2 FROM t1";
    int stat;
    printf("SQLite from C\n");
    stat = sqlite3_open("test.db", &con);
    stat = sqlite3_prepare(con, sqlstr, strlen(sqlstr), &sel, NULL);
    while(sqlite3_step(sel) == SQLITE_ROW)
    {
        printf("%d %s\n", sqlite3_column_int(sel, 0), sqlite3_column_text(sel, 1));
    }
    sqlite3_finalize(sel);
    sqlite3_close(con);
    return 0;
}

Build and run - VMS:

$ cc/include=sqlite3_include: sqlite.c
$ link sqlite + sys$input/opt
sqlite3shr/share
$
$ run sqlite

Pascal:

psqlite + standard C API (VMS):

Due to VMS calling convention it is possible to call the standard C API from Pascal.

To make it a little easier I have created a wrapper psqlite that are also open source and can be downloaded here.

sqlite.pas:

[inherit('psqlitedir:sqlite', 'psqlitedir:psqlite')]
program sqlite(input, output);

var
   con : sqlite_ptr;
   sel : sqlite_stmt_ptr;

begin
   writeln('SQLite from Pascal (PSQLITE)');
   con := psqlite_open('test.db');
   sel := psqlite_prepare(con, 'SELECT f1,f2 FROM t1');
   while psqlite_step_query(sel) do begin
      writeln(psqlite_column_int(sel, 0), ' ', psqlite_column_text(sel, 1));
   end;
   psqlite_finalize(sel);
   psqlite_close(con);
end.

Build and run - VMS:

$ pas sqlite
$ link sqlite + sys$input/opt + psqlitedir:sqlite/opt
psqlitedir:psqlite
psqlitedir:sqlite
$
$ run sqlite

JVM languages:

JDBC (VMS):

A JDBC driver for SQLite is available.

Note that it is a type 2 JDBC driver aka it uses native code via JNI, so it is necessary to get a special VMS distribution of the JDBC driver.

SQLite.java:

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;

public class SQLite {
    public static void main(String[] args) throws Exception {
        System.out.println("SQLite from Java (JDBC)");
        Class.forName("org.sqlite.JDBC");
        Connection con = DriverManager.getConnection("jdbc:sqlite:test.db");
        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT f1,f2 FROM t1");
        while(rs.next()) {
            int f1 = rs.getInt(1);
            String f2 = rs.getString(2);
            System.out.println(f1 + " " + f2);
        }
        rs.close();
        stmt.close();
        con.close();
    }
}

Build and run - VMS:

$ javac SQLite.java
$ define/nolog java$filename_controls 8
$ define/nolog decc$efs_charset true
$ java -cp .:/javalib/sqlite-jdbc-3_14_1-vms.jar "SQLite"

jsqlite.py:

from java.lang import Class
from java.sql import DriverManager

from org.sqlite import JDBC # replaces Class.forName('org.sqlite.JDBC')

print('SQLite from JVM Python (JDBC)')
con = DriverManager.getConnection('jdbc:sqlite:test.db')
stmt = con.createStatement()
rs = stmt.executeQuery('SELECT f1,f2 FROM t1')
while rs.next():
    f1 = rs.getInt(1)
    f2 = rs.getString(2)
    print(str(f1) + ' ' + f2)
rs.close()
stmt.close()
con.close()

jsqlite.js:

importClass(Packages.java.lang.Class);
importClass(Packages.java.sql.DriverManager);

print("SQLite from JVM JavaScript (JDBC)")
new Packages.org.sqlite.JDBC(); //replaces Class.forName("org.sqlite.JDBC");
con = DriverManager.getConnection("jdbc:sqlite:test.db");
stmt = con.createStatement();
rs = stmt.executeQuery("SELECT f1,f2 FROM t1");
while(rs.next()) {
    f1 = rs.getInt(1);
    f2 = rs.getString(2);
    print(f1 + " " + f2);
}
rs.close();
stmt.close();
con.close();

DB API 2.0 (VMS):

Jython (JVM Python) can use standard Python DB API 2.0 to access a database via the zxJDBC module and a standard JDBC driver.

jsqlitez.py:

from java.lang import Class
from java.sql import DriverManager

from org.sqlite import JDBC # replaces Class.forName('org.sqlite.JDBC')

print('SQLite from JVM Python (JDBC)')
con = DriverManager.getConnection('jdbc:sqlite:test.db')
stmt = con.createStatement()
rs = stmt.executeQuery('SELECT f1,f2 FROM t1')
while rs.next():
    f1 = rs.getInt(1)
    f2 = rs.getString(2)
    print(str(f1) + ' ' + f2)
rs.close()
stmt.close()
con.close()

Python:

DB API 2.0 (VMS):

Python comes with a DB API 2.0 compliant sqlite3 module.

For details on DB API 2.0 including SQL updates and parameters see here.

sqlite.py:

import sqlite3

print('SQLite from Python')
con = sqlite3.connect('test.db')
c = con.cursor()
c.execute('SELECT f1,f2 FROM t1')
for row in c.fetchall():
    print('%d %s' % (row[0], row[1]))
con.commit()
con.close()

Jython options:

Options for Jython (JVM Python) are described under JVM languages.

PHP:

sqlite3 (VMS):

sqlite.php:

<?php
echo "SQLite from PHP (sqlite3)\r\n";
$con = new SQLite3('/disk2/arne/db/test.db');
$q = $con->query('SELECT f1,f2 FROM t1');
while($row = $q->fetchArray()) {
    $f1 = $row['f1'];
    $f2 = $row['f2'];
    echo "$f1 $f2\r\n";
}
$con->close();
?>

pdo + sqlite3 (VMS):

sqlitep.php:

<?php
echo "MySQL from PHP (PDO,sqlite)\r\n";
$con = new PDO('sqlite:/disk2/arne/db/test.db');
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$stmt = $con->prepare('SELECT f1,f2 FROM t1');
$stmt->execute(array());
while($row = $stmt->fetch()) {
    $f1 = $row['f1'];
    $f2 = $row['f2'];
    echo "$f1 $f2\r\n";
}
?>

Mimer:

Background:

Mimer is a relational database with a long history originally developed at Uppsala University an transferred to a commercial entity in 1984.

It is available for VMS, Windows, Linux and macOS.

It is not a database with a high media profile, but it is used in various industrial segments.

C:

Embedded SQL (VMS,WIN.NIX):

Mimer supports traditional embedded SQL including C.

The precompiler gets installed with the Mimer installation.

mimer1.ec:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

EXEC SQL INCLUDE SQLCA;

int main()
{
    EXEC SQL BEGIN DECLARE SECTION;
    char con[256];
    char usr[256];
    char pwd[256];
    char f2[51];
    long int f1;
    EXEC SQL END DECLARE SECTION;
    printf("Mimer from C (embedded)\n");
    strcpy(con, "test");
    strcpy(usr, "SYSADM");
    strcpy(pwd, "hemmeligt");
    EXEC SQL CONNECT TO :con USER :usr USING :pwd;
    EXEC SQL DECLARE curs CURSOR FOR SELECT f1,f2 FROM t1;
    EXEC SQL OPEN curs;
    for(;;)
    {
        EXEC SQL FETCH curs INTO :f1, :f2;
        if(sqlca.sqlcode != 0) break;
        printf("%d %s\n", f1, f2);
    }
    EXEC SQL CLOSE curs;
    return 0;
}

Build and run - VMS:

$ esql/c mimer1
$ cc mimer1
$ link mimer1 + sys$input/opt
mimlib9:lr/lib
mimlib9:mdr/lib
mimlib9:mimdb9/share
$
$ run mimer1

ODBC (WIN):

An ODBC driver for Mimer is available.

Standard ODBC API. For details on ODBC API including SQL updates, parameters and error handling see here.

The example assumes a DSN has been defined in ODBC manager.

mimer2.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <windows.h>
#include <sql.h>
#include <sqlext.h>

#define F2_MAX_LEN 50

static const char *dsn = "ARNE1_MIMER";
static const char *un = "SYSADM";
static const char *pw = "hemmeligt";

int main()
{
    SQLHENV env;
    SQLHDBC con;
    SQLHSTMT stmt;
    long int f1;
    char *sqlstr, f2[F2_MAX_LEN + 1];
    SQLLEN lenf2;
    int stat;
    printf("Mimer from C (ODBC)\n");
    stat = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
    stat = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
    stat = SQLAllocHandle(SQL_HANDLE_DBC, env, &con);
    stat = SQLConnect(con, (SQLCHAR *)dsn, (SQLSMALLINT)strlen(dsn),
                           (SQLCHAR *)un, (SQLSMALLINT)strlen(un),
                           (SQLCHAR *)pw, (SQLSMALLINT)strlen(pw));
    sqlstr = "SELECT f1,f2 FROM t1";
    stat = SQLAllocHandle(SQL_HANDLE_STMT, con, &stmt);
    stat = SQLExecDirect(stmt, (SQLCHAR *)sqlstr, strlen(sqlstr));
    stat = SQLBindCol(stmt, 1, SQL_C_LONG, &f1, 0, NULL);
    stat = SQLBindCol(stmt, 2, SQL_C_CHAR, f2, sizeof(f2), &lenf2);
    for(;;)
    {
        stat = SQLFetch(stmt);
        if((stat != SQL_SUCCESS) && (stat != SQL_SUCCESS_WITH_INFO)) break;
        f2[lenf2] = 0;
        printf("%ld %s\n", f1, f2);
    }
    SQLCloseCursor(stmt);
    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
    SQLDisconnect(con);
    SQLFreeHandle(SQL_HANDLE_DBC, con);
    SQLFreeHandle(SQL_HANDLE_ENV, env);
    return 0;
}

Build and run - Windows:

gcc mimer2.c -lodbc32 -o mimer2.exe
mimer2

Pascal:

SQLDB + ODBC (WIN):

FPC comes with SQLDB unit for database access. SQLDB supports ODBC.

An ODBC driver for Mimer is available.

For details on SQLDB API including SQL updates, parameters and error handling see here.

The example assumes a DSN has been defined in ODBC manager.

mimer2.pas:

program mimer2(input, output);

uses
  SQLDB, ODBCConn;

var
  con : TSQLConnection;
  tx : TSQLTransaction;
  q : TSQLQuery;
  f1 : integer;
  f2 : string;

begin
  writeln('Mimer from Pascal (SQLDB, ODBC)');
  con := TODBCConnection.Create(nil);
  con.DatabaseName := 'ARNE1_MIMER';
  con.UserName := 'SYSADM';
  con.Password := 'hemmeligt';
  con.Open;
  tx := TSQLTransaction.Create(nil);
  con.Transaction := tx;
  q := TSQLQuery.Create(nil);
  q.DataBase := con;
  q.SQL.Text := 'SELECT f1,f2 FROM t1';
  q.Open;
  while not q.EOF do begin
    f1 := q.FieldByName('f1').AsInteger;
    f2 := q.FieldByName('f2').AsString;
    writeln(f1, ' ', f2);
    q.Next;
  end;
  q.Close;
  q.Free;
  con.Close;
  con.Free;
end.

Build and run - Windows:

fpc mimer2.pas
mimer2

Fortran:

Embedded SQL (VMS):

Mimer supports traditional embedded SQL and on VMS Fortran.

The precompiler gets installed with the Mimer installation.

mimer1.efo:

      PROGRAM MIMER1
      EXEC SQL INCLUDE SQLCA
      EXEC SQL DECLARE curs CURSOR FOR SELECT f1,f2 FROM t1
      EXEC SQL BEGIN DECLARE SECTION
      CHARACTER*255 CON
      CHARACTER*255 USR
      CHARACTER*255 PWD
      INTEGER*4 F1
      CHARACTER*50 F2
      EXEC SQL END DECLARE SECTION
      WRITE(*,*) 'Mimer from Fortran (embedded)'
      CON = 'test'
      USR = 'SYSADM'
      PWD = 'hemmeligt'
      EXEC SQL CONNECT TO :CON USER :USR USING :PWD
      EXEC SQL OPEN curs
100   EXEC SQL FETCH curs INTO :f1, :f2
      IF(SQLCOD.EQ.0) THEN
        WRITE(*,*) F1, ' ', F2
        GOTO 100
      ENDIF
      EXEC SQL CLOSE curs
      END

Build and run - VMS:

$ esql/fortran mimer1
$ fortran mimer1
$ link mimer1 + sys$input/opt
mimlib9:lr/lib
mimlib9:mdr/lib
mimlib9:mimdb9/share
$
$ run mimer1

Cobol:

Embedded SQL (VMS):

Mimer supports traditional embedded SQL and on VMS Cobol.

The precompiler gets installed with the Mimer installation.

mimer1.eco:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. MIMER1.

       ENVIRONMENT DIVISION.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       EXEC SQL INCLUDE SQLCA END-EXEC.
       EXEC SQL BEGIN DECLARE SECTION END-EXEC.
       01 CON PIC X(255).
       01 USR PIC X(255).
       01 PWD PIC X(255).
       01 F1 PIC S9(9) BINARY.
       01 F2 PIC X(50).
       EXEC SQL END DECLARE SECTION END-EXEC.
       01 TEMP PIC 9(9) DISPLAY.
       EXEC SQL DECLARE curs CURSOR FOR SELECT f1,f2 FROM t1 END-EXEC.

       PROCEDURE DIVISION.
       MAIN-PARAGRAPH.
           DISPLAY "Mimer from Cobol (embedded)"
           MOVE "test" TO CON
           MOVE "SYSADM" TO USR
           MOVE "hemmeligt" TO PWD
           EXEC SQL CONNECT TO :CON USER :USR USING :PWD END-EXEC
           EXEC SQL OPEN curs END-EXEC
           MOVE 0 TO SQLCODE
           PERFORM UNTIL NOT SQLCODE = 0
               EXEC SQL FETCH curs INTO :f1, :f2 END-EXEC
               IF SQLCODE = 0 THEN
                   MOVE F1 TO TEMP
                   DISPLAY TEMP " " F2
               END-IF
           END-PERFORM
           EXEC SQL CLOSE curs END-EXEC
           STOP RUN.

Build and run - VMS:

$ esql/cobol mimer1
$ cobol/ansi mimer1
$ link mimer1 + sys$input/opt
mimlib9:lr/lib
mimlib9:mdr/lib
mimlib9:mimdb9/share
$
$ run mimer1

JVM languages:

JDBC - local (VMS):

JDBC is Java basic database API.

Mimer comes with a JDBC driver that supports both access to local databases and access to databases over network.

Here we will look at local access.

For details on JDBC API including SQL updates and parameters see here.

Mimer1.java:

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;

public class Mimer1 {
    public static void main(String[] args) throws Exception {
        System.out.println("Mimer from Java (JDBC,local)");
        Class.forName("com.mimer.jdbc.Driver");
        Connection con = DriverManager.getConnection("jdbc:mimer:/test", "SYSADM", "hemmeligt");
        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT f1,f2 FROM t1");
        while(rs.next()) {
            int f1 = rs.getInt(1);
            String f2 = rs.getString(2);
            System.out.println(f1 + " " + f2);
        }
        rs.close();
        stmt.close();
        con.close();
    }
}

Build and run - VMS:

$ javac Mimer1.java
$ java -cp .:/javalib/mimjdbc3.jar "Mimer1"

JDBC - network (VMS,WIN,NIX):

JDBC is Java basic database API.

Mimer comes with a JDBC driver that supports both access to local databases and access to databases over network.

Here we will look at access over network.

For details on JDBC API including SQL updates and parameters see here.

Mimer2.java:

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;

public class Mimer2 {
    public static void main(String[] args) throws Exception {
        System.out.println("Mimer from Java (JDBC,network)");
        Class.forName("com.mimer.jdbc.Driver");
        Connection con = DriverManager.getConnection("jdbc:mimer://SYSADM:hemmeligt@192.168.0.10:1360/test");
        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT f1,f2 FROM t1");
        while(rs.next()) {
            int f1 = rs.getInt(1);
            String f2 = rs.getString(2);
            System.out.println(f1 + " " + f2);
        }
        rs.close();
        stmt.close();
        con.close();
    }
}

Build and run - Windows:

javac Mimer2.java
java -cp .;\DivJava\mimjdbc3.jar Mimer2

Build and run - VMS:

$ javac Mimer2.java
$ java -cp .:/javalib/mimjdbc3.jar "Mimer2"

.NET languages:

ADO.NET (WIN,NIX):

ADO.NET is .NET basic database API.

An ADO.NET provider for Mimer is available.

For details on ADO.NET API including SQL updates, parameters and how to make the code database independent see here.

mimer1.cs:

using System;

using Mimer.Data.Client;

public class Program
{
    public static void Main(String[] args) 
    {
        Console.WriteLine("Mimer from C# (ADO.NET)");
        using(MimerConnection con = new MimerConnection("Node=192.168.0.10;Service=1360;Database=test;User Id=SYSADM;Password=hemmeligt"))
        {
            con.Open();
            using(MimerCommand cmd = new MimerCommand("SELECT f1,f2 FROM t1", con))
            {
                using(MimerDataReader rdr = cmd.ExecuteReader())
                {
                    while(rdr.Read())
                    {
                        Console.WriteLine((int)rdr["f1"] + " " + (string)rdr["f2"]);
                    }
                }
            }
        }
    }
}

Build and run - Windows:

csc /r:Mimer.Data.Client.dll mimer1.cs
mimer1

mimer1.vb:

Imports System
Imports Mimer.Data.Client

Public Class Program
    Public Shared Sub Main(args As [String]())
        Console.WriteLine("Mimer from VB.NET (ADO.NET)")
        Using con As New MimerConnection("Node=192.168.0.10;Service=1360;Database=test;User Id=SYSADM;Password=hemmeligt")
            con.Open()
            Using cmd As New MimerCommand("SELECT f1,f2 FROM t1", con)
                Using rdr As MimerDataReader = cmd.ExecuteReader()
                    While rdr.Read()
                        Console.WriteLine(rdr("f1") & " " & rdr("f2"))
                    End While
                End Using
            End Using
        End Using
    End Sub
End Class

Build and run - Windows:

vbc /r:Mimer.Data.Client.dll mimer1.vb
mimer1

ODBC (WIN):

ADO.NET can use an ODBC driver.

An ODBC driver for Mimer is available.

The example assumes a DSN has been defined in ODBC manager.

It is strongly recommended using the databases ADO.NET provider instead of the ODBC driver. Mixing .NET and native for database access is not optimal.

mimer2.cs:

using System;
using System.Data.Odbc;

public class Program
{
    public static void Main(String[] args) 
    {
        Console.WriteLine("Mimer from C# (ODBC)");
        using(OdbcConnection con = new OdbcConnection("Dsn=ARNE1_MIMER;Uid=SYSADM;Pwd=hemmeligt"))
        {
            con.Open();
            using(OdbcCommand cmd = new OdbcCommand("SELECT f1,f2 FROM t1", con))
            {
                using(OdbcDataReader rdr = cmd.ExecuteReader())
                {
                    while(rdr.Read())
                    {
                        Console.WriteLine((int)rdr["f1"] + " " + (string)rdr["f2"]);
                    }
                }
            }
        }
    }
}

Build and run - Windows:

csc mimer2.cs
mimer2

mimer2.vb:

Imports System
Imports System.Data.Odbc

Public Class Program
    Public Shared Sub Main(args As [String]())
        Console.WriteLine("Mimer from VB.NET (ODBC)")
        Using con As New OdbcConnection("Dsn=ARNE1_MIMER;Uid=SYSADM;Pwd=hemmeligt")
            con.Open()
            Using cmd As New OdbcCommand("SELECT f1,f2 FROM t1", con)
                Using rdr As OdbcDataReader = cmd.ExecuteReader()
                    While rdr.Read()
                        Console.WriteLine(rdr("f1") & " " & rdr("f2"))
                    End While
                End Using
            End Using
        End Using
    End Sub
End Class

Build and run - Windows:

vbc mimer2.vb
mimer2

PHP:

ODBC (WIN):

PHP supports ODBC.

An ODBC driver for Mimer is available.

The example assumes a DSN has been defined in ODBC manager.

mimer2.php:

<?php
echo "Mimer from PHP (ODBC)\r\n";
$con = odbc_connect('ARNE1_MIMER', 'SYSADM', 'hemmeligt');
$stmt = odbc_prepare($con, 'SELECT f1,f2 FROM t1');
odbc_execute($stmt, array());
while(odbc_fetch_row($stmt)){
    $f1 = odbc_result($stmt, 'f1');
    $f2 = odbc_result($stmt, 'f2');
    echo "$f1 $f2\r\n";
}
odbc_free_result($stmt);
odbc_close($con);
?>

PDO + ODBC (WIN):

PHP has a standard database API called PDO.

PDO supports ODBC.

An ODBC driver for Mimer is available.

The example assumes a DSN has been defined in ODBC manager.

mimer2p.php:

<?php
echo "Mimer from PHP (PDO,ODBC)\r\n";
$con = new PDO('odbc:DSN=ARNE1_MIMER;UID=SYSADM;PWD=hemmeligt');
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$stmt = $con->prepare('SELECT f1,f2 FROM t1');
$stmt->execute(array());
while($row = $stmt->fetch()) {
    $f1 = $row['F1']; // note uppercase field names
    $f2 = $row['F2'];
    echo "$f1 $f2\r\n";
}
?>

VBS:

ODBC (WIN):

VBS supports ADO and ADO can use an ODBC driver.

An ODBC driver for Mimer is available.

The example assumes a DSN has been defined in ODBC manager.

mimer.vbs:

WScript.Echo "Mimer from VBS (ODBC)"
Set con = CreateObject("ADODB.Connection")
con.Open "Dsn=ARNE1_MIMER;Uid=SYSADM;Pwd=hemmeligt"
Set cmd = CreateObject("ADODB.Command")
cmd.ActiveConnection = con
cmd.CommandText = "SELECT f1,f2 FROM t1"
Set rs = cmd.Execute
Do While Not rs.EOF
    WScript.Echo rs("f1") & " " & rs("f2")
    rs.MoveNext
Loop
Set rs = Nothing
Set cmd = Nothing
Set con = Nothing

Index-Sequential files:

RMS index-sequential files are covered here.

Article history:

Version Date Description
1.0 September 16th 2020 Initial version
1.1 September 28th 2020 Add SQLite section
1.2 October 11th 2020 Add Jython and Rhino examples
1.3 November 1st 2020 Add Mimer section
1.4 May 11th 2021 Add RDB VMS Python examples
1.5 July 22nd 2022 Add C SQL Services example

Other articles:

See list of all articles here

Comments:

Please send comments to Arne Vajhøj