CobolSQLite3 User Guide for Version A.01

  ____      _           _  ____   ___  _     _ _        _____
 / ___|___ | |__   ___ | |/ ___| / _ \| |   (_) |_ ___ |___ /
| |   / _ \| '_ \ / _ \| |\___ \| | | | |   | | __/ _ \  |_ \
| |__| (_) | |_) | (_) | | ___) | |_| | |___| | ||  __/ ___) |
 \____\___/|_.__/ \___/|_||____/ \__\_\_____|_|\__\___||____/
Author:Robert W.Mills
Date:September 2017
Rights:Copyright © 2017-2021, Robert W.Mills.
Email:rwm.cobol@gmail.com
Purpose:An SQLite3 Interface Library for GnuCOBOL

1. License

1.1. CobolSQLite3 Library

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License, in the file COPYING, along with this program. If not, see <http://www.gnu.org/licenses/gpl.txt>.

1.2. CobolSQLite3 User Guide

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.

A copy of this license, in the file COPYING, should be included with this software. If not, see <http://www.gnu.org/licenses/fdl.txt>.

1.3. SQLite3

SQLite is in the Public Domain

All of the code and documentation in SQLite has been dedicated to the public domain by the authors. All code authors, and representatives of the companies they work for, have signed affidavits dedicating their contributions to the public domain and originals of those signed affidavits are stored in a firesafe at the main offices of Hwaci <https://www.hwaci.com/>. Anyone is free to copy, modify, publish, use, compile, sell, or distribute the original SQLite code, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

All of the deliverable code in SQLite has been written from scratch. No code has been taken from other projects or from the open internet. Every line of code can be traced back to its original author, and all of those authors have public domain dedications on file. So the SQLite code base is clean and is uncontaminated with licensed code from other projects.

2. Description

The CobolSQLite3 Library is an interface to the SQLite3 Database Engine.

The interface consists of a Dynamic Library (.so file in Linux & .dll in Windows). It containing User Defined Functions that perform the following actions:

  • Open/Create an SQLite Database.
  • Close an SQLite Database.
  • Compile an SQL Statement into byte-code.
  • Bind values to parameters in a compiled SQL Statement.
  • Execute a compiled SQL Statement.
  • Release (delete) a compiled SQL Statement.
  • Reset (re-initialise) a compiled SQL Statement.
  • Compile, execute and release an SQL Statement.
  • Retrieve all columns from a SELECTed row.
  • Request information about the Database (currently a limited function).
  • Translate a Status Code into human-readable text.

2.1. Quote from SQLite author

D Richard Hipp, architect and primary author of SQLite as well as the Fossil SCM, said:

"SQLite is a C library that implements an embeddable SQL database engine. Programs that link with the SQLite library can have SQL database access without running a separate RDBMS process. The distribution comes with a standalone command-line access program (SQLite) that can be used to administer a SQLite database and which serves as an example of how to use the SQLite library.

SQLite is not a client library used to connect to a big database server. SQLite is the server. The SQLite library reads and writes directly to and from the database files on disk."

3. Reusing Compiled Statements

It is not useful to evaluate the exact same SQL Statement more than once. More often, you want to execute similar statements. For example, you might want to execute an INSERT statement multiple times with different values. Or you might want to execute the same query multiple times using a different key in the WHERE clause.

To accommodate this, CobolSQLite3 allows SQL Statements to contain parameters which are bound to values prior to being executed. These values can later be changed and the same compiled SQL Statement can be executed a second time using the new values.

A question-mark (?) is used as a place-holder for the parameter within the SQL Statement. CobolSQLite3 allows a parameter wherever a string literal, numeric constant, or NULL is allowed. It may not be used for column or table names. A call to DBINFO Mode 200 will return the expanded SQL Statement.

A parameter initially has a value of NULL. Prior to calling DBEXECUTE the first time or immediately after a DBRESET, the program can call DBBIND to attach values to the parameters. Each use of DBBIND overrides prior bindings on the same parameter. Note that existing bindings are not cleared by DBRESET.

There is no arbitrary limit to the number of SQL Statements that can be compiled. A program can call DBCOMPILE multiple times at start-up, to create all of the compiled SQL Statements it will ever need, and then execute them as needed.

4. Library Functions

4.0. Restrictions

DBCOMPILE and DBSQL will only use the 1st statement passed in the sql-statement parameter, any additional statements will be dropped.

This helps prevent SQL Injection Attacks against the Database.

4.1. DBSTATUS

Returns the Status Code of the last executed CobolSQLite3 function.

Syntax

move DBSTATUS to status-code

if DBSTATUS <> ZERO then ... end-if

Parameters

status-code is a size 4 signed binary integer.

4.2. DBOPEN

Opens the specified database and creates a Database Object.

Syntax

move DBOPEN(db-name) to db-object

Parameters

db-name is either an alphanumeric variable or quoted string. It holds the name of the Database to be opened. The path to the Database must be specified if it's not in the working directory.

db-object is a size 8 alphanumeric variable. It is used to hold the internal handle to the Database Object.

Notes

If the database does not exist then it will be automatically created.

If db-name specifies a file that is not an SQLite3 Database then DBOPEN will return an error (use DBSTATUS to return the Status Code).

4.3. DBCLOSE

Closes the specified database and destroys its Database Object.

Syntax

if DBCLOSE(db-object) <> ZERO then ... end-if

Parameters

db-object is a size 8 alphanumeric variable. It is used to hold the internal handle to the Database Object.

Notes

If DBCLOSE returns a non-zero value then use DBSTATUS to obtain the Status Code.

4.4. DBCOMPILE

Compiles an SQL Statement, into byte-code, and creates an SQL Object for it.

Syntax

move DBCOMPILE(db-object, sql-statement) to sql-object

Parameters

db-object is a size 8 alphanumeric variable. It is used to hold the internal handle to the Database Object.

sql-statement is either an alphanumeric variable or quoted string. It holds the SQL Statement to be compiled.

sql-object is a size 8 alphanumeric variable. It is used to hold the internal handle to the SQL Object created for a compiled SQL Statement.

Notes

Use DBSTATUS to obtain the Status Code and check for a non-zero return.

4.5. DBBIND

Binds a value to a compiled SQL statement parameter.

Syntax

if DBBIND(sql-object, param-idx, param-value) <> ZERO then ... end-if

Parameters

sql-object is a size 8 alphanumeric variable. It is used to hold the internal handle to the SQL Object created for a compiled SQL Statement.

param-idx is either an alphanumeric variable or an unquoted string. It indicates which parameter, in the compiled SQL statement, is to be bound.

param-value is either an alphanumeric variable, or a quoted string. It holds the value to be bound to the parameter pointed to by param-idx.

Notes

The leftmost SQL Statement parameter has an index of 1.

See Section 3. Reusing Compiled Statements for more details.

4.6. DBEXECUTE

Executes an SQL Object (a compiled SQL Statement).

Syntax

if DBEXECUTE(sql-object) <> ZERO then ... end-if

Parameters

sql-object is a size 8 alphanumeric variable. It is used to hold the internal handle to the SQL Object created for a compiled SQL Statement.

4.7. DBRELEASE

Releases (deletes) an SQL Object (a compiled SQL Statement).

Syntax

if DBRELEASE(sql-object) <> ZERO then ... end-if

Parameters

sql-object is a size 8 alphanumeric variable. It is used to hold the internal handle to the SQL Object created for a compiled SQL Statement.

Notes

This function MUST be executed against all SQL Objects before the database is closed as failure to do so result's in memory leaks.

4.8. DBRESET

Resets the SQL Object back to initial state so it can be re-executed.

Syntax

if DBRESET(sql-object) <> ZERO then ... end-if

Parameters

sql-object is a size 8 alphanumeric variable. It is used to hold the internal handle to the SQL Object created for a compiled SQL Statement.

Notes

If the SQL Object contains any bound parameter values, they will not be cleared.

4.9. DBSQL

Executes an SQL Statement against the Database Object.

Syntax

if DBSQL(db-object, sql-statement) <> ZERO then ... end-if

Parameters

db-object is a size 8 alphanumeric variable. It is used to hold the internal handle to the Database Object.

sql-statement is either an alphanumeric variable or quoted string. It holds the SQL Statement to be executed.

Notes

This function combines the DBCOMPILE, DBEXECUTE and DBRELEASE functionality.

4.10. DBGET

Returns the current result row of an SQL Query (Select).

Syntax

if DBGET(sql-object, row-delims, row-buffer) <> ZERO then ... end-if

Parameters

sql-object is a size 8 alphanumeric variable. It is used to hold the internal handle to the SQL Object created for a compiled SQL Statement.

row-delims is a size 2 alphanumeric variable. It containing the delimiters to use when loading the row-buffer.

  • The 1st character is placed between each column (see Notes below).
  • The 2nd character is placed after the last column to indicate the end of data in row-buffer (see Notes below)

row-buffer is an alphanumeric variable that contains the complete row in delimited format. All numeric column data is converted to display format.

Notes

The row-delims entry in the Working-Storage Copybook sets default values of HEX 1D (Group Separator) and HEX 1E (Record Separator) for the 1st and 2nd delimiter. These values are the developers choice and you can keep them as-is, modify the row-delims entry in the Copybook, or override the values within your program by using one-or-more MOVE commands.

A modified version of the following unstring statement should be used to extract the data for each column from row-buffer. You, as the developer using this Library, are in complete control of the picture format/size of the Working-storage field that will be the recipient of the column data. It is suggested that you use the SQLite Command-Line Shell (see Section 5.1) to look at the current data formats/sizes used and code accordingly.

unstring row-buffer
  delimited by field-delimiter or row-delimiter
  into
    ws-column-1
    ws-column-2
    ws-column-n
end-unstring

4.11. DBINFO

Returns information about the Database being accessed.

Syntax

move DBINFO(dbinfo-mode, db-object) to dbinfo-buffer

Parameters

dbinfo-mode is a size 4 unsigned numeric variable. It indicates what information to return (see DBINFO Modes table below).

db-object is a size 8 alphanumeric variable. It is used to hold the internal handle to the Database/SQL Object.

dbinfo-buffer is an alphanumeric variable for returning the requested information. Refer to the mapping for dbinfo-buffer in the Working-Storage Copybook (CobolSQLite3-WS.cpy) for further details.

DBINFO Modes

Mode Description
100 The number of rows modified, inserted or deleted by the most recently completed INSERT, UPDATE or DELETE statement against the database. Changes caused by triggers, foreign key actions or REPLACE constraint resolution are not counted.
200 Return a compiled SQL Statement with bind parameters expanded.

4.12. DBERRMSG

Returns the error message associated with the last Status Code setting.

Syntax

move DBERRMSG to error-message

display DBERRMSG

Parameters

error-message is a size 256 alphanumeric variable. It will hold the error message text for the last Status Code.

Notes

The returned error-message will have one of following prefixes:

DBINF is not an actual error but for information. DBINFO 0: Successful completion. is the only entry with this prefix.

DBERR errors are generated by the CobolSQLite3 Library.

SQLite3ERR errors are generated by the SQLite3 Library.

5. Compilation Instructions

5.1. Linux/UNIX

Compile the CobolSQLite3 source (CobolSQLite3.cob) by entering the following command within any terminal program:

cobc -o CobolSQLite3.so -debug CobolSQLite3.cob -lsqlite3

5.2. Apple Mac OS X

Compile the source file as for Linux/Unix.

5.3. Windows

I do not have access to Windows, Windows/Cygwin or Windows/MinGW but I understand that the following commands should work [YMMV].

Windows/MinGW and Windows/Cygwin (inside the terminal program):

Compile the source file as for Linux/Unix.

Windows/MinGW and Windows/Cygwin (outside the terminal program):

cobc -debug -lsqlite3 [drive:][path/to/]CobolSQLite3.cob

Native Windows:

cobc -debug -lsqlite3 [drive:][path\\to\\]CobolSQLite3.cob

5.4. Hard-copy Listings

If you want a Hard-copy Listing then:

cobc -F -Xref -T CobolSQLite3.lst CobolSQLite3.cob

The source listing, including cross-reference, will be written to the file CobolSQLite3.lst.

6. Installation

6.1. Requirements

GnuCOBOL: Version 3.1 (or greater) installed and tested fully working.

See the documentation supplied with GnuCOBOL. You must have run both the sanity checks created by the test procedures included within the Cobol85 suite as well as the make check procedure.

SQLite3: Version 3.14 (or greater).

As a minimum you need to install the Shared Library (Libsqlite3-0) and Development Files (Libsqlite3-dev). Available from most Linux Distros, but for Windows you will have to download them from sqlite.org.

Note: If updating from a previous version you may need to execute the 'ldconfig' command.

Although you do not need it you will find it an advantage to also install the following:

  • Command-Line Shell (sqlite3) is a utility that allows the manual entry and execution of SQL statements against an SQLite database. Documentation is at <https://www.sqlite.org/cli.html>.
  • SQLite Database Analyzer (sqlite3_analyzer) reads an SQLite database and outputs a file showing the space used by each table and index and other statistics. Documentation is at <https://www.sqlite.org/sqlanalyze.html>.
  • SQLite Database Diff (sqldiff) compares two SQLite database files and outputs the SQL needed to convert one into the other. Documentation is at <https://www.sqlite.org/sqldiff.html>.

The SQLite Download page <https://www.sqlite.org/download.html> contains Source Code files and precompiled binaries for multiple platforms. As of writing, February 2021, version 3.34.1 is available from here.

See <https://www.sqlite.org/about.html> for information on SQLite.

6.2. Before First Use

Before you use the CobolSQLite3 Library for the first time (and also after a new release) you must generate the Copybook modules required by the programs using the Library.

Enter the following commands:

cobcrun ./CobolSQLite3 --repository > CobolSQLite3-CSR.cpy

cobcrun ./CobolSQLite3 --copylib > CobolSQLite3-WS.cpy

The first command generates a copylibrary containing a list of the functions that are available in the CobolSQLite3 Library. This module needs to be included in the REPOSITORY statement within the programs CONFIGURATION SECTION.

For example,

configuration section.

  repository.
    copy "CobolSQLite3-CSR.cpy".
    function all intrinsic.

The second command generates a copylibrary containing the Library data definitions. This module needs to be included in the programs WORKING-STORAGE SECTION.

For example,

working-storage section.

  copy "CobolSQLite3-WS.cpy".

  *> additional data definitions

There are two additional commands that you can run:

cobcrun ./CobolSQLite3 --version

cobcrun ./CobolSQLite3 --help

The first command displays the CobolSQLite3 Library and SQLite3 versions.

For example,

CobolSQLite3/A.01.00
SQLite3 Interface Functions for GnuCOBOL
Copyright (c) Robert W.Mills <rwm.cobol@gmail.com>, 2017-2021
SQLite3 Library Version 3.13

 ** Please update SQLite3 Library to at least Version 3.14 **

This is free software; see the source for copying conditions. There is NO
WARRANTY; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

The second command displays some help text.

For example,

cobcrun [path/]CobolSQLite3 [option] [>filename]

option:
  -h, --help          Display this help text.
  -v, --version       Display the Library and SQLite3 Versions.
  -r, --repository    Generate the Repository Copylibrary module.
  -c, --copylib       Generate the Working-storage Copylibrary module.

Output from the --repository and --copylib options is written to
Standard Out. Use >filename to redirect it to a disc file instead.

6.3. Copybook Listings

Below are examples of the two Copybook's that are generated by CobolSQLite3.

CobolSQLite3-CSR.cpy contains the Library function definitions. It needs to be COPYed into the Repository paragraph within the Configuration Section.

 *> CobolSQLite3 Function Definitions.
 *>
 *> DO NOT EDIT THIS MODULE. See User Guide Section 6.2.

      Function DBSTATUS
      Function DBOPEN
      Function DBCLOSE
      Function DBCOMPILE
      Function DBBIND
      Function DBEXECUTE
      Function DBRELEASE
      Function DBRESET
      Function DBSQL
      Function DBGET
      Function DBINFO
      Function DBERRMSG

CobolSQLite3-WS.cpy contains the Library data definitions. It needs to be COPYed into the Working-Storage Section. It is recommended that copy statement is placed at the start of the section.

 *> CobolSQLite3 Working Storage Definitions.
 *>
 *> DO NOT EDIT THIS MODULE. See User Guide Section 6.2.

    01  db-object                      pic x(008).
      88  database-is-closed             value NULL.

    01  db-status                      pic s9(04) comp.
      88  call-successful                value ZERO.
      *> -- CobolSQLite3 Function codes ----------------------
      88  database-already-open          value -1.
      88  database-open-failed           value -2.
      88  database-not-open              value -3.
      88  unreleased-sql-objects-exist   value -4.
      88  sql-compile-failed             value -5.
      88  database-lock-failed           value -6.
      88  sql-object-not-released        value -7.
      88  sql-object-not-reset           value -8.
      88  invalid-bind-index             value -9.
      88  bind-value-to-big              value -10.
      88  datatype-unknown-unsupported   value -11.
      88  datatype-undefined             value -12.
      88  invalid-dbinfo-mode            value -13.
      88  not-an-sqlite-database         value -14.
      88  no-data-returned               value -15.
      88  row-buffer-overflow            value -16.
      88  dbinfo-buffer-overflow         value -17.
      *> -- SQLite3 Library codes ----------------------------
      88  database-row-available         value 100.
      88  sql-statement-finished         value 101.

    01  sql-object                     pic x(008).
      88  object-released                value NULL.

    01  row-delims.
      05  field-delimiter              pic x(001) value x'1D'.
      05  row-delimiter                pic x(001) value x'1E'.

    01  dbinfo-mode                    pic 9(004) value zeros.
      88  dbinfo-changed-rows            value 100.
      88  dbinfo-expand-sql              value 200.

    01  dbinfo-buffer                  pic x(2048).
        *> 2K should be big enough.

    01  redefines dbinfo-buffer.
      05  dbinfo-rows-changed          pic s9(09) comp.

    01  error-message                  pic x(128).

7. Accessing the Library

Prior to executing a program that uses the CobolSQLite3 Library you need to set the COB_PRE_LOAD environment variable. This tells the GnuCOBOL runtime link resolver what dynamic link modules are included in a run.

export COB_PRE_LOAD=CobolSQLite3

If the Library is not in the current working directory along with the executable, the COB_LIBRARY_PATH environment variable can be set to find them.

export COB_LIBRARY_PATH=/path/to/library

8. Example/Test Programs

Test-1.cob Open a new SQLite3 Database; create a Table with an Integer, Real (IEEE Floating Point) and Text column; load 4 entries into the Table; display all entries from the Table; and close the Database.

*> ** >>SOURCE FORMAT IS FREE
*>
*> Author    : Robert W.Mills <CobolMac@btinternet.com>
*> Dedicated to the public domain.
*>
*> Purpose   : CobolSQLite3 example and test program.
*>
*> Tests     : See Test-1 entry in the 'Example/Test Programs' section of the
*>             CobolSQLite3 User Guide.
*>
*> Written   : September 2017
*> Modified  : Not yet.
*>
*> Tectonics : Install the SQLite3 library (sqlite.org), if required.
*>             prompt$ cobc -x -fdebugging-line Test-1.cob
*>          or prompt$ cobc -x Test-1.cob
*>             prompt$ export COB_PRE_LOAD=CobolSQLite3
*>             prompt$ ./Test-1

identification division.

  program-id.                          Test-1.

environment division.

  configuration section.

    repository.
      copy "CobolSQLite3-CSR.cpy".
      function all intrinsic.

data division.

  working-storage section.

    copy "CobolSQLite3-WS.cpy".

    01  database-name                  pic x(080) value "./test.sdb".

    01  sql-statements.
      05  create-table-foo             pic x(128) value
            "create table foo (foo_integer int, foo_real real, foo_text text);".
      05  insert-into-foo-1            pic x(128) value
            "insert into foo (foo_integer, foo_real, foo_text) " &
            "values (-12345, -12.345, '1st line, numbers should be -12345 and -12.345');".
      05  insert-into-foo-2            pic x(128) value
            "insert into foo (foo_integer, foo_real, foo_text) " &
            "values (2, 2.99, '2nd line, numbers should be 2 and 2.99');".
      05  insert-into-foo-3            pic x(128) value
            "insert into foo (foo_integer, foo_real, foo_text) " &
            "values (-3, -3.99, '3rd line, numbers should be -3 and -3.99');".
      05  insert-into-foo-4            pic x(128) value
            "insert into foo (foo_integer, foo_real, foo_text) " &
            "values (4, 4.99, '4th line, numbers should be 4 and 4.99');".
      05  select-from-foo              pic x(128) value
            "select * from foo;".

    01  row-buffer                     pic x(128).

    01  foo-heading-1.
      05                               pic x(001) value spaces.
      05                               pic x(007) value "integer".
      05                               pic x(003) value spaces.
      05                               pic x(007) value "real".
      05                               pic x(003) value spaces.
      05                               pic x(059) value "Text".

    01  foo-heading-2.
      05                               pic x(001) value spaces.
      05                               pic x(007) value all "-".
      05                               pic x(003) value spaces.
      05                               pic x(007) value all "-".
      05                               pic x(003) value spaces.
      05                               pic x(059) value all "-".

    01  foo-detail.
      05                               pic x(002) value spaces.
      05  fd-integer                   pic -(5)9(1).
      05                               pic x(003) value spaces.
      05  fd-real                      pic -(3).9(3).
      05                               pic x(003) value spaces.
      05  fd-text                      pic x(059).

procedure division.

Test-1-mainline.

>>D display "- opening database ", trim(database-name) end-display

  call "C$DELETE" using trim(database-name),
                        0 *> required but unused
  end-call

  move DBOPEN(database-name) to db-object

  if DBSTATUS <> ZERO then
    display "DBOPEN: ", DBERRMSG end-display
    goback
  end-if

>>D display "- creating table foo" end-display

  if DBSQL(db-object, create-table-foo) <> ZERO then
    display "DBSQL (create table foo): ", DBERRMSG end-display
    goback
  end-if

>>D display "- adding record(s) to table foo" end-display

  if DBSQL(db-object, insert-into-foo-1) <> ZERO then
    display "DBSQL (insert foo 1): ", DBERRMSG end-display
    goback
  end-if

  if DBSQL(db-object, insert-into-foo-2) <> ZERO then
    display "DBSQL (insert foo 2): ", DBERRMSG end-display
    goback
  end-if

  if DBSQL(db-object, insert-into-foo-3) <> ZERO then
    display "DBSQL (insert foo 3): ", DBERRMSG end-display
    goback
  end-if

  if DBSQL(db-object, insert-into-foo-4) <> ZERO then
    display "DBSQL (insert foo 4): ", DBERRMSG end-display
    goback
  end-if

>>D display "- selecting all records from foo" end-display

  move DBCOMPILE(db-object, select-from-foo) to sql-object

  if DBSTATUS <> ZERO then
    display "DBCOMPILE (select foo): ", DBERRMSG end-display
    goback
  end-if

  move DBEXECUTE(sql-object) to db-status

  evaluate true

    when database-row-available

      perform print-column-headings

      perform get-print-data
        until sql-statement-finished

      display space end-display
      display "-- End of Report --" end-display

    when sql-statement-finished
      continue

    when database-lock-failed
      display "DBEXECUTE: ", DBERRMSG end-display
      goback

    when other
      display "DBEXECUTE: ", DBERRMSG end-display
      goback

  end-evaluate

  if DBRELEASE(sql-object) <> ZERO then
    display "DBRELEASE: ", DBERRMSG end-display
  end-if

>>D display "- closing database ", trim(database-name) end-display

  if DBCLOSE(db-object) <> ZERO then
    display "DBCLOSE: ", DBERRMSG end-display
  end-if

  move zero to return-code
  goback
  .

print-column-headings.

  *> Print the column heading lines.

  display foo-heading-1 end-display
  display foo-heading-2 end-display
  .

get-print-data.

  *> Get the current result row and extract the values.

  if DBGET(sql-object, row-delims, row-buffer) <> ZERO then
    display "DBGET (foo): ", DBERRMSG end-display
  end-if

  unstring row-buffer
    delimited by field-delimiter or row-delimiter
    into
      fd-integer
      fd-real
      fd-text
  end-unstring

  *> Print the detail line.

  display foo-detail end-display

  *> Get the next row.

  move DBEXECUTE(sql-object) to db-status
  .

end program Test-1.

Test-2.cob is a copy of Test-1.cob that passes alphanumeric variables to the functions instead of quoted strings.

*> ** >>SOURCE FORMAT IS FREE
*>
*> Author    : Robert W.Mills <CobolMac@btinternet.com>
*> Dedicated to the public domain.
*>
*> Purpose   : CobolSQLite3 example and test program.
*>
*> Tests     : See Test-3 entry in the 'Example/Test Programs' section of the
*>             CobolSQLite3 User Guide.
*>
*> Written   : September 2017
*> Modified  : Not yet.
*>
*> Tectonics : Install the SQLite3 library (sqlite.org), if required.
*>             prompt$ cobc -x -fdebugging-line Test-2.cob
*>          or prompt$ cobc -x Test-2.cob
*>             prompt$ export COB_PRE_LOAD=CobolSQLite3
*>             prompt$ ./Test-2

identification division.

  program-id.                          Test-2.

environment division.

  configuration section.

    repository.
      copy "CobolSQLite3-CSR.cpy".
      function all intrinsic.

data division.

  working-storage section.

    copy "CobolSQLite3-WS.cpy".

    01  row-buffer                     pic x(128).

    01  foo-heading-1.
      05                               pic x(001) value spaces.
      05                               pic x(007) value "integer".
      05                               pic x(003) value spaces.
      05                               pic x(007) value "real".
      05                               pic x(003) value spaces.
      05                               pic x(059) value "Text".

    01  foo-heading-2.
      05                               pic x(001) value spaces.
      05                               pic x(007) value all "-".
      05                               pic x(003) value spaces.
      05                               pic x(007) value all "-".
      05                               pic x(003) value spaces.
      05                               pic x(059) value all "-".

    01  foo-detail.
      05                               pic x(002) value spaces.
      05  fd-integer                   pic -(5)9(1).
      05                               pic x(003) value spaces.
      05  fd-real                      pic -(3).9(3).
      05                               pic x(003) value spaces.
      05  fd-text                      pic x(059).

procedure division.

Test-2-mainline.

>>D display "- opening database ./test.sdb" end-display

  call "C$DELETE" using "./test.sdb",
                        0 *> required but unused
  end-call

  move DBOPEN("./test.sdb") to db-object

  if DBSTATUS <> ZERO then
    display "DBOPEN: ", DBERRMSG end-display
    goback
  end-if

>>D display "- creating table foo" end-display

  if DBSQL(db-object,
           "create table foo (foo_integer int, foo_real real, foo_text text);"
          ) <> ZERO then
    display "DBSQL (create table foo): ", DBERRMSG end-display
    goback
  end-if

>>D display "- adding record(s) to table foo" end-display

  if DBSQL(db-object,
           "insert into foo (foo_integer, foo_real, foo_text) " &
           "values (-12345, -12.345, '1st line, numbers should be -12345 and -12.345');"
          ) <> ZERO then
    display "DBSQL (insert foo 1): ", DBERRMSG end-display
    goback
  end-if

  if DBSQL(db-object,
           "insert into foo (foo_integer, foo_real, foo_text) " &
           "values (2, 2.99, '2nd line, numbers should be 2 and 2.99');"
          ) <> ZERO then
    display "DBSQL (insert foo 2): ", DBERRMSG end-display
    goback
  end-if

  if DBSQL(db-object,
           "insert into foo (foo_integer, foo_real, foo_text) " &
           "values (-3, -3.99, '3rd line, numbers should be -3 and -3.99');"
          ) <> ZERO then
    display "DBSQL (insert foo 3): ", DBERRMSG end-display
    goback
  end-if

  if DBSQL(db-object,
           "insert into foo (foo_integer, foo_real, foo_text) " &
           "values (4, 4.99, '4th line, numbers should be 4 and 4.99');"
          ) <> ZERO then
    display "DBSQL (insert foo 4): ", DBERRMSG end-display
    goback
  end-if

>>D display "- selecting all records from foo" end-display

  move DBCOMPILE(db-object, "select * from foo;") to sql-object

  if DBSTATUS <> ZERO then
    display "DBCOMPILE (select foo): ", DBERRMSG end-display
    goback
  end-if

  move DBEXECUTE(sql-object) to db-status

  evaluate true

    when database-row-available

      perform print-column-headings

      perform get-print-data
        until sql-statement-finished

      display space end-display
      display "-- End of Report --" end-display

    when sql-statement-finished
      continue

    when database-lock-failed
      display "DBEXECUTE: ", DBERRMSG end-display
      goback

    when other
      display "DBEXECUTE: ", DBERRMSG end-display
      goback

  end-evaluate

  if DBRELEASE(sql-object) <> ZERO then
    display "DBRELEASE: ", DBERRMSG end-display
  end-if

>>D display "- closing database ./test.sdb" end-display

  if DBCLOSE(db-object) <> ZERO then
    display "DBCLOSE: ", DBERRMSG end-display
  end-if

  move zero to return-code
  goback
  .

print-column-headings.

  *> Print the column heading lines.

  display foo-heading-1 end-display
  display foo-heading-2 end-display
  .

get-print-data.

  *> Get the current result row and extract the values.

  if DBGET(sql-object, row-delims, row-buffer) <> ZERO then
    display "DBGET (foo): ", DBERRMSG end-display
  end-if

  unstring row-buffer
    delimited by field-delimiter or row-delimiter
    into
      fd-integer
      fd-real
      fd-text
  end-unstring

  *> Print the detail line.

  display foo-detail end-display

  *> Get the next row.

  move DBEXECUTE(sql-object) to db-status
  .

end program Test-2.

Test-3.cob is a copy of Test-1.cob that demonstrates Reusing Compiled Statements. It calls the DBCOMPILE, DBBIND, DBEXECUTE and DBRELEASE functions, instead of DBSQL, to load the 4 entries into the Table.

*> ** >>SOURCE FORMAT IS FREE
*>
*> Author    : Robert W.Mills <CobolMac@btinternet.com>
*> Dedicated to the public domain.
*>
*> Purpose   : CobolSQLite3 example and test program.
*>
*> Tests     : See Test-3 entry in the 'Example/Test Programs' section of the
*>             CobolSQLite3 User Guide.
*>
*> Written   : October 2017
*> Modified  : Feburary 2021
*>
*> Tectonics : Install the SQLite3 library (sqlite.org), if required.
*>             prompt$ cobc -x -fdebugging-line Test-3.cob
*>          or prompt$ cobc -x Test-3.cob
*>             prompt$ export COB_PRE_LOAD=CobolSQLite3
*>             prompt$ ./Test-3

identification division.

  program-id.                          Test-3.

environment division.

  configuration section.

    repository.
      copy "CobolSQLite3-CSR.cpy".
      function all intrinsic.

data division.

  working-storage section.

    copy "CobolSQLite3-WS.cpy".

    01  database-name                  pic x(080) value "./test.sdb".

    01  sql-statements.
      05  create-table-foo             pic x(128) value
            "create table foo (foo_integer int, foo_real real, foo_text text);".
      05  insert-into-foo              pic x(128) value
            "insert into foo (foo_integer, foo_real, foo_text) values (?, ?, ?);".
      05  select-from-foo              pic x(128) value
            "select * from foo;".

    01  row-buffer                     pic x(128).

    01  foo-heading-1.
      05                               pic x(001) value spaces.
      05                               pic x(007) value "integer".
      05                               pic x(003) value spaces.
      05                               pic x(007) value "real".
      05                               pic x(003) value spaces.
      05                               pic x(059) value "Text".

    01  foo-heading-2.
      05                               pic x(001) value spaces.
      05                               pic x(007) value all "-".
      05                               pic x(003) value spaces.
      05                               pic x(007) value all "-".
      05                               pic x(003) value spaces.
      05                               pic x(059) value all "-".

    01  foo-detail.
      05                               pic x(002) value spaces.
      05  fd-integer                   pic -(5)9(1).
      05                               pic x(003) value spaces.
      05  fd-real                      pic -(3).9(3).
      05                               pic x(003) value spaces.
      05  fd-text                      pic x(059).

procedure division.

Test-3-mainline.

  set dbinfo-expand-sql to true

>>D display "- opening database ", trim(database-name) end-display

  call "C$DELETE" using trim(database-name),
                        0 *> required but unused
  end-call

  move DBOPEN(database-name) to db-object

  if DBSTATUS <> ZERO then
    display "DBOPEN: ", DBERRMSG end-display
    goback
  end-if

>>D display "- creating table foo" end-display

  if DBSQL(db-object, create-table-foo) <> ZERO then
    display "DBSQL (create table foo): ", DBERRMSG end-display
    goback
  end-if

>>D display "- adding record(s) to table foo" end-display

  perform add-records-to-table

  if DBRELEASE(sql-object) <> ZERO then
    display "DBRELEASE: ", DBERRMSG end-display
  end-if

>>D display "- selecting all records from foo" end-display

  move DBCOMPILE(db-object, select-from-foo) to sql-object

  if DBSTATUS <> ZERO then
    display "DBCOMPILE (select foo): ", DBERRMSG end-display
    goback
  end-if
>>D display "-- ", trim(DBINFO(dbinfo-mode,sql-object)) end-display

  move DBEXECUTE(sql-object) to db-status

  evaluate true

    when database-row-available

      perform print-column-headings

      perform get-print-data
        until sql-statement-finished

      display space end-display
      display "-- End of Report --" end-display

    when sql-statement-finished
      continue

    when database-lock-failed
      display "DBEXECUTE: ", DBERRMSG end-display
      goback

    when other
      display "DBEXECUTE: ", DBERRMSG end-display
      goback

  end-evaluate

  if DBRELEASE(sql-object) <> ZERO then
    display "DBRELEASE: ", DBERRMSG end-display
  end-if

>>D display "- closing database ", trim(database-name) end-display

  if DBCLOSE(db-object) <> ZERO then
    display "DBCLOSE: ", DBERRMSG end-display
  end-if

  move zero to return-code
  goback
  .

add-records-to-table.

  move DBCOMPILE(db-object, insert-into-foo) to sql-object

  if DBSTATUS <> ZERO then
    display "DBCOMPILE: ", DBERRMSG end-display
    goback
  end-if
>>D display "-- ", trim(DBINFO(dbinfo-mode,sql-object)) end-display

>>D display "-- Add record 1 to table." end-display

  if DBBIND(sql-object, 1, '12345') <> ZERO then
    display "DBBIND (1-1): ", DBERRMSG end-display
    goback
  end-if

  if DBBIND(sql-object, 2, '23.456') <> ZERO then
    display "DBBIND (1-2): ", DBERRMSG end-display
    goback
  end-if

  if DBBIND(sql-object, 3, '1st line, numbers should be 12345 and 23.456') <> ZERO then
    display "DBBIND (1-3): ", DBERRMSG end-display
    goback
  end-if

>>D display "--- ", trim(DBINFO(dbinfo-mode,sql-object)) end-display
>>D display "--- Insert the record." end-display

  move DBEXECUTE(sql-object) to db-status

  if not call-successful and not sql-statement-finished then
    display "DBEXECUTE (1): ", DBERRMSG end-display
    goback
  end-if

>>D display "--- Reset the sql object." end-display

  if DBRESET(sql-object) <> ZERO then
    display "DBRESET (1): ", DBERRMSG end-display
    goback
  end-if

>>D display "-- Add record 2 to table." end-display

  if DBBIND(sql-object, 1, '2') <> ZERO then
    display "DBBIND (2-1): ", DBERRMSG end-display
    goback
  end-if

  if DBBIND(sql-object, 2, '2.990') <> ZERO then
    display "DBBIND (2-2): ", DBERRMSG end-display
    goback
  end-if

  if DBBIND(sql-object, 3, "2nd line, numbers should be 2 and 2.990") <> ZERO then
    display "DBBIND (2-3): ", DBERRMSG end-display
    goback
  end-if

>>D display "--- ", trim(DBINFO(dbinfo-mode,sql-object)) end-display
>>D display "--- Insert the record." end-display

  move DBEXECUTE(sql-object) to db-status

  if not call-successful and not sql-statement-finished then
    display "DBEXECUTE (2): ", DBERRMSG end-display
    goback
  end-if

>>D display "--- Reset the sql object." end-display

  if DBRESET(sql-object) <> ZERO then
    display "DBRESET (2): ", DBERRMSG end-display
    goback
  end-if

>>D display "-- Add record 3 to table." end-display

  if DBBIND(sql-object, 1, '-3') <> ZERO then
    display "DBBIND (3-1): ", DBERRMSG end-display
    goback
  end-if

  if DBBIND(sql-object, 2, '-3.990') <> ZERO then
    display "DBBIND (3-2): ", DBERRMSG end-display
    goback
  end-if

  if DBBIND(sql-object, 3, "3rd line, numbers should be -3 and -3.990") <> ZERO then
    display "DBBIND (3-3): ", DBERRMSG end-display
    goback
  end-if

>>D display "--- ", trim(DBINFO(dbinfo-mode,sql-object)) end-display
>>D display "--- Insert the record." end-display

  move DBEXECUTE(sql-object) to db-status

  if not call-successful and not sql-statement-finished then
    display "DBEXECUTE (3): ", DBERRMSG end-display
    goback
  end-if

>>D display "--- Reset the sql object." end-display

  if DBRESET(sql-object) <> ZERO then
    display "DBRESET (3): ", DBERRMSG end-display
    goback
  end-if

>>D display "-- Add record 4 to table." end-display

  if DBBIND(sql-object, 1, '4') <> ZERO then
    display "DBBIND (4-1): ", DBERRMSG end-display
    goback
  end-if

  if DBBIND(sql-object, 2, '4.99') <> ZERO then
    display "DBBIND (4-2): ", DBERRMSG end-display
    goback
  end-if

  if DBBIND(sql-object, 3, "4th line, numbers should be 4 and 4.990") <> ZERO then
    display "DBBIND (4-3): ", DBERRMSG end-display
    goback
  end-if

>>D display "--- ", trim(DBINFO(dbinfo-mode,sql-object)) end-display
>>D display "--- Insert the record." end-display

  move DBEXECUTE(sql-object) to db-status

  if not call-successful and not sql-statement-finished then
    display "DBEXECUTE (4): ", DBERRMSG end-display
    goback
  end-if

>>D display "--- Reset the sql object." end-display

  if DBRESET(sql-object) <> ZERO then
    display "DBRESET (4): ", DBERRMSG end-display
    goback
  end-if
  .

print-column-headings.

  *> Print the column heading lines.

  display foo-heading-1 end-display
  display foo-heading-2 end-display
  .

get-print-data.

  *> Get the current result row and extract the values.

  if DBGET(sql-object, row-delims, row-buffer) <> ZERO then
    display "DBGET (foo): ", DBERRMSG end-display
  end-if

  unstring row-buffer
    delimited by field-delimiter or row-delimiter
    into
      fd-integer
      fd-real
      fd-text
  end-unstring

  *> Print the detail line.

  display foo-detail end-display

  *> Get the next row.

  move DBEXECUTE(sql-object) to db-status
  .

end program Test-3.

9. Modification History

Version A.01.01 February 2021 Robert W.Mills (rwm.cobol@gmail.com)

  • We now use the CONTENT-OF function instead of a BASED variable and address manipulation to access the character data returned by an SQLite3 char function. See the call to sqlite3_libversion in the libraries outer block for an example of it's use.
  • Added work-around for GnuCOBOL 3.1.2 COMPUTE bug in DBBIND. Should be fixed in 3.2.
  • Added a makefile. Use the command 'make help' to list the available options.
  • Removed the genhtml script (use the command 'make html' instead).

Version A.01.00 February 2021 Robert W.Mills (rwm.cobol@gmail.com)

  • This release requires that Version 3.14 (or greater) of the SQLite3 Library is installed.
  • The 'cobcrun ./CobolSQLite3 --version' command will display a warning message if the current SQLite3 Library needs to be updated.
  • Changed contact email address.
  • Fixed DBOPEN problem discovered by Laszlo Erdos.
  • Added section 1.3. SQLite3 to the User Guide documenting that SQLite is in the Public Domain.
  • Added the DBBIND function.
  • Added Mode 200 to DBINFO that will return a compiled SQL Statement with bind parameters expanded.
  • Increased size of DBINFO-BUFFER (in CobSQLite3 Working Storage) from 80 characters to 1024 characters. This is required because of the DBINFO Mode 200 addition. Error -17 will be returned if this buffer overflows.
  • Added a new section, 3. Reusing Compiled Statements, to the User Guide documenting how the DBBIND function is used. Note: The number of the original section 3, and all following sections, has been increased by 1 (one).
  • CobolSQLite3 now requires use of runtime-options to generate the Copylibrary modules instead of ask if it should create them. See section 6.2. of the User Guide for further details.
  • Added a third Example/Test Program. Test-3.cob is a modified copy of Test-1.cob that demonstrates the DBBIND function and Reusing Compiled Statements.
  • Updated the User Guide to document the changes made.

Version A.00.00 September 2017 Robert W.Mills (CobolMac@btinternet.com)

  • First production release to GnuCOBOL Contributions.

Version X.03.00 [BETA] September 2017 Robert W.Mills (CobolMac@btinternet.com)

  • Created a User Guide that is in HTML format. The source text is held within the CobolSQLite3 source file in ReStructuredText format. It is extracted by ocdoc and then passed to Doccutils which generates the HTML file. The Modification History and Planned Enhancements are held in external files (ChangeLog and ToDo) which are merged into the User Guide when Docutils generates it.
  • Added the DBGET function (replaces the DBGETSTR and DBGETINT functions).

Version X.02.00 [BETA] September 2017 Robert W.Mills (CobolMac@btinternet.com)

  • Added this ChangeLog document.
  • Added check in DBOPEN for SQLite3 Database before attempting to open it. A new status code, -14, and error message was added.
  • Allow quoted strings to be used in place of string variables in parameters.
  • Cleaned up comments (too many uses of the word 'the').
  • Cleaned up error messages (too many uses of the word 'the').

Version X.01.00 [BETA] September 2017 Robert W.Mills (CobolMac@btinternet.com)

  • Initial release to GnuCOBOL Contributions.

Version X.00.00 [ALPHA] August 2017 Robert W.Mills (CobolMac@btinternet.com)

  • Start of development.

10. Planned Enhancements

  • DBERRMSG: Add optional parameter to return error message for any Status Code.
  • DBINFO: Add Mode 300 (Check if specified table exists).