FairCom ISAM for C

Next Topic

FairCom ISAM API for C - Developers Guide

Developer Guide

FairCom ISAM for C




ISAM and Low-Level API Functions and Basic Concepts


© Copyright 2021, FairCom Corporation. All rights reserved. For full information, see the FairCom Copyright Notice.

 FairCom DB® Professional is the complete environment for developing applications using the sophisticated FairCom DB Advanced Core Engine. Written in the C language, FairCom DB file management integrates with your C/C++ applications to provide easy-to-use, yet flexible data file manipulation and indexing. FairCom DB is designed to be used in a variety of operating system environments.

The significant features of FairCom DB are:

  • fast file access via indexes using the most advanced B+ tree techniques, enhanced by our proprietary caching and compression algorithms
  • programs can be portable over a wide variety of operating systems
  • both single-user and multi-user file access, with full file and record locking control that often exceeds the capabilities provided by the operating environment
  • superior performance on network and multi-user systems using the multi-threaded FairCom DB approach to file management - a powerful client/server approach to data management
  • advanced Transaction Processing and fully automatic recovery, including full commit and rollback, intermediate savepoints, and complete logging; file security to prevent unauthorized access to your data files and indices

This guide serves both as an introduction to FairCom DB for the new user and as a reference guide for the experienced user.

In This Chapter

Prerequisites - C Language Concepts

JSON Data Type Support

Using JSON Data Types in Your ISAM Applications

Next Topic

Prerequisites - C Language Concepts

This manual assumes you are already familiar with the C programming language. If you are not familiar with these concepts, you should develop a reasonable proficiency with the language for effective usage of FairCom DB.

This section of the reference guide describes a number of conventions that we use in relation to the C language, as well as a few C language concepts that we believe are worth reviewing. In this section:

Data Type Conventions

The actual representation of a data type declaration may vary from one operating environment or processor type to another. For instance, on one system the int data type may be represented by a 2-byte integer, while on another system int may be represented by a 4-byte integer. Our goal is to make a product using FairCom DB as portable as possible. Differences like these between systems can interfere with that goal. We want to ensure that a 2-byte integer in FairCom DB will be a 2-byte integer on any system. Therefore, we define our own data types as shown below. By carefully using these data types, you guarantee that a program operates consistently across all supported operating environments.

The following data types are used throughout the FairCom DB routines called by your application programs. C language typedefs have been included in the c-tree header files. Most of these will be found in the header file ctport.h.

We recommend that you use these conventions in your products, as well. By carefully avoiding the use of native variable types in your variable declarations you can create an application that is very easy to port from one compiler, or operating environment, to another

COUNT parameters are used to pass values such as key length or file number to c-tree functions. Most c-tree functions return error codes of type COUNT. This is a 2-byte signed integer.

UCOUNT parameters are used to pass fixed length data record lengths and file extension sizes to the c-tree functions. This is a 2-byte unsigned integer.

LONG values represent data record positions. This is a 4-byte signed integer.

This is a 4-byte unsigned integer.

Character pointers to type TEXT are used to pass file names and key values to the c‑tree routines.

Incremental ISAM structure. IFIL structures contain the parameters necessary to create, open, and close ISAM files without a parameter file. The ISAM parameters are discussed in ISAM Functions.

The DATOBJ structure is the data type used in the Data Object Definition Array or DODA, which defines the record layout to c-tree. See Record Schemas for additional information.

VRLEN is used to pass or receive a record length and buffer sizes.

UINT are native system unsigned integers.

VOID is used in two ways: to define functions that return no value, and to define a generic pointer. Some compilers do not support the declaration void, and others do. In ctport.h you will find a define similar to the following:

#define void void

If your compiler does not support the void declaration, substitute the following;

#define void int

VOID pointers are better than character or TEXT pointers when you are passing a variable address to a function, and you don’t know if you are going to use a character string or a structure. A VOID pointer is a generic pointer, and if you are using function prototyping, it will let you use any type of variable pointer. A TEXT pointer will give you a warning when you compile a program passing a structure address.

The lower case p indicates this data type is cast to be a pointer. For example, pCOUNT is equivalent to (COUNT *). Most of the data types defined by c-tree have companion types prefaced with a lower case p (e.g., pVOID, pTEXT, . . .).


The C language has no formal data type for character strings. All string manipulation is done by processing arrays of characters. The C language provides no automatic checking on the boundaries of an array. These features can be exploited in many cases, but when it comes to string manipulation they present hurdles to overcome.

When you are copying a character string from one variable to another, it is up to the programmer to ensure that the receiving variable has enough room to hold the entire string being copied. If you are not careful, it is possible for the string being copied to overlay an adjacent variable in addition to the target, with unpredictable results. This may be the most common error that can occur in a C program, and it can be very difficult to trace.

To complicate matters, many string manipulation operations performed in a FairCom DB program are NOT working with traditional null-terminated character strings. As we will see later, some types of c-tree key values may have null characters embedded in the middle. In addition, copying data structures from one location to another is handled as a string manipulation, and the data structure will have a number of null characters embedded in it.

To assist in working with strings and structures, c‑tree includes a copy function, cpybuf(). c‑tree redefines cpybuf() to memcpy() in those environments which support this ANSI function. If not, cpybuf() is defined as:

void cpybuf(destination, source, length)

pTEXT destination;

pTEXT source;

UINT length;

This function copies length bytes from source to destination. It copies strings, structures, or buffers. It will NOT stop when it sees a null character in source. cpybuf() stops when it has copied length bytes. We strongly suggest using this function when you know the length of the buffer or string you are copying.

FairCom DB also includes cpybig(), which provides the same functionality as cpybuf(), but works for very large buffers even on machines with segmented memory models. The length parameter is declared as VRLEN instead of UINT, which provides for larger buffers.

Next Topic

JSON Data Type Support

V11.8 and later added JSON as a new data type, called CT_JSON. It is physically stored in a table using the CT_4STRING format, which can support strings up to 2 GB in length.

It is available in all APIs with varying levels of support: SQL, NAV, ISAM, and Low-Level.

The NAV API allows you to index specific JSON properties using FairCom’s path language. This allows you to find records containing specific property values or ranges of property values. And it allows you to navigate records in sorted order using JSON property values.

In SQL and ISAM, you can read and write the string value stored in a JSON field but you cannot extract the values in JSON properties and treat them as columns. You cannot also use indexes created by the NAV API.

Next Topic

Using JSON Data Types in Your ISAM Applications

JSON Data Type

To create a table that contains a CT_JSON field, specify CT_JSON as the field type in the DODA. When you add a record that contains a CT_JSON field value, store it in CT_4STRING format, with the first four bytes of the field containing the length of the JSON value, followed by the JSON value.

JSON Indexing

To create an index on a CT_JSON field, set the index attributes in the IIDX and ISEG structures that you pass to CREIFIL(). Before calling CREIFIL(), call the PUTKSEGDEF() function to set the CT_JSON index attributes that will be used for the CT_JSON index in the CREIFIL() call. The CT_JSON index attributes include the key segment length, the c-tree data type of the key value, and the JSON key name that is being indexed.

The PUTKSEGDEF() function can be used to specify CT_JSON index attributes for a call to CREIFIL():

  1. Declare and initialize an array of pointers to ctKSEGDEF structures.
  2. Pass this array of pointers to PUTKSEGDEF(filno,segno,pkdef) by setting filno to ctKSEGcreidx, setting segno to the number of pointers in the array, and setting pkdef to the address of the array. Note that the array you pass must contain a pointer for every key segment that precedes the CT_JSON key segment. A pointer can be NULL if no extended index information is to be supplied for that key segment.


In this example, the supplied IFIL definition (pifil) has two indexes of one key segment each. The example code sets the first extended segment info pointer to NULL and the second to a ctKSEGDEF structure initialized with the CT_JSON index attributes.

ISEG myseg[] = {

{ 8, 8, SRLSEG},

{ 3, 4, SCHSEG}


IIDX myidx[] = {

{8, 0, NO, NO, 0, 1, myseg, "$ROWID$"},

{4, 0, NO, NO, 0, 1, myseg+1, "doc_id"}


IFIL mydat = {












pctKSEGDEF pksegs[2];

/* No extended segment info for first index. */

pksegs[0] = NULL;

/* Set the extended segment info for the second segment. */


sd.kseg_type = ctKSEG_TYPE_JSON;

/* use source type from schema */

sd.kseg_styp = ctKSEG_STYP_PROVIDED;

/* set key segment length */

sd.kseg_ssiz = 4;

/* set c-tree data type of key value */

sd.kseg_comp = CT_INT4;

/* set the json key name that is being indexed */


pksegs[1] = sd;

rc = CREIFIL(pifil);

The name of the JSON key to index is stored in the kseg_desc field of the ctKSEGDEF structure. However, this field is limited to ctKSEGDLEN (32) bytes in the ctKSEGDEF structure definition. To overcome this limit, the ctKSEGcreidx usage of PUTKSEGDEF() accepts an array of pointers to ctKSEGDEF structures instead of an array of ctKSEGDEF structures so that an application can allocate a buffer to hold the CT_JSON index attributes that is larger than the ctKSEGDEF structure when the JSON key name exceeds the length of the field as defined in the ctKSEGDEF structure. As long as kseg_desc is NULL-terminated, the larger kseg_desc value can be passed to PUTKSEGDEF() in this manner.

The ctKSEGcreidx information that is passed to PUTKSEGDEF() is stored in the c-tree library until the next call to an ISAM level index create function: CREIFIL(), CREIFILX(), CREIFILX8(), PRMIIDX(), PRMIIDX8(), TMPIIDX(), TMPIIDXX(), TMPIIDXX8(). The recommended usage is to call PUTKSEGDEF() with filno of ctKSEGcreidx immediately before the index create call.

For an extended key segment type (kseg_type) of ctKSEG_TYPE_JSON, a call to GETKSEGDEF() is able to return to the caller a larger amount of ctKSEGDEF data than the size of the ctKSEGDEF structure. A call to GETKSEGDEF() for a kseg_type of ctKSEG_TYPE_JSON should set kseg_ssiz to the size of the supplied buffer. If GETKSEGDEF() finds that the data is larger than the supplied buffer size, it returns -VBSZ_ERR and returns the required length in the kseg_rsv1 field. For example:


NINT rc,bufsiz;

sd.kseg_type = ctKSEG_TYPE_JSON;

sd.kseg_ssiz = bufsiz;

if ((rc = GETKSEGDEF(keyno,i,&sd)) < 0) {

if (rc == -VBSZ_ERR) {

/* Buffer too small. sd.kseg_rsv1 holds the required size. */



This new behavior of PUTKSEGDEF() and GETKSEGDEF() is intended to be used to send and receive attributes for other extended key segment types in the future.

JSON Error Code

Error code 1122:

JSON_KTFM_ERR: CT_JSON key transformation failed. Check sysiocod for details. See CTJSON_* definitions.

sysiocod values that may be returned in case of error 1122:

#define CTJSON_NOT_JSON -1038 /* Not a valid JSON object */

#define CTJSON_NOT_OBJECT -1039 /* Valid JSON, but not an object */

#define CTJSON_UNSUPPORTED_TYPE -1040 /* The specified key data type is not supported */

Limitations to JSON Key Segments

  1. A CT_JSON key segment does not support the DSCSEG, ALTSEG, or ENDSEG key segment modes. Attempting to create an index that contains a CT_JSON key segment that includes any of these key segment modes fails with error NSUP_ERR.
  2. CT_JSON key segments that use CT_STRING as the c-tree data type are always padded with null (0x0) bytes. We don't support setting a different key segment padding character on JSON key segments.
  3. A CT_JSON key segment can specify any of the following c-tree data types: CT_BOOL, CT_CHAR, CT_CHARU, CT_INT2, CT_INT2U, CT_INT4, CT_INT4U, CT_INT8, CT_DFLOAT, CT_STRING. Note that CT_INT8U is not supported, because JSON only supports a signed 8-byte integer data type.
  4. Remember that the JSON field indexing behaves as follows: if the JSON data type of the value that is being indexed is not compatible with the underlying c-tree data type specified in the key segment definition, that value is treated as NULL and is not indexed. Some examples:
    • If the value is a string and the c-tree data type is an integer, the value is not indexed.
    • If the value is an integer and the c-tree data type is CT_INT2 but the value is out of range for a signed two-byte integer, the value is not indexed.