An ISAM Challenge with C# Ease
c-tree Plus offers multiple APIs for developing the optimal solution for your application needs. For the best performance, many developers make direct calls into their data files through our ISAM API with the standard 'C' language. The c-tree Plus for .NET API provides the same high performance ISAM record based c-tree technology as programming with our ISAM API. However, c-tree Plus for .NET technology handles the intricacies of IFIL and DODA management, freeing you to focus on simple and efficient application design. Put this power to work for your more demanding ISAM programming challenges.
Consider the case of adding an index to an existing data file. To further complicate this situation, try adding and removing fields of an existing data file. This can be a tricky challenge when using direct ISAM calls. In some cases, nearly impossible without completely repopulating an entire table of data.
Complex ISAM Challenge
With the c-tree Plus ISAM API, you define your table and index relationships in the IFIL structure and then add a DODA resource for the schema information.
ISAM Code Example 1
/* Data Record Definitions */
DATOBJ custmast_doda[] = {
{"cm_custnumb", NULL,CT_FSTRING, 4},
{"cm_custzipc", NULL,CT_FSTRING, 9},
{"cm_custstat", NULL,CT_FSTRING, 3},
{"cm_custratg", NULL,CT_FSTRING, 1},
{"cm_custname", NULL,CT_STRING, 47},
{"cm_custaddr", NULL,CT_STRING, 47},
{"cm_custcity", NULL,CT_STRING, 47}
};
/* Data File Definitions */
IFIL custmast_ifil = {
"custmast", /* data file name */
-1, /* data file number */
16, /* data record length */
4096, /* data extension size */
ctVLENGTH, /* data file mode */
0, /* number of indices */
0, /* index extension size */
0, /* index file mode */
(pIIDX)0, /* pointer to index array */
"cm_custnumb", /* pointer to first field name (r-tree) */
"cm_custcity" /* pointer to last field name (r-tree) */
};
VOID Define()
{
/* open files */
if (OpenIFile(&custmast_ifil))
{
/* create files */
if (CreateIFile(&custmast_ifil))
Handle_Error("Define(): CreateIFile()", 0);
/* store record information into data file */
if (PutDODA(custmast_ifil.tfilno, custmast_doda, (UCOUNT)NBR_OF_FIELDS))
Handle_Error("Define(): PutDODA()", 0);
/* close files */
CloseIFile(&custmast_ifil);
if (OpenIFile(&custmast_ifil))
Handle_Error("Define(): OpenIFile()", 0);
}
/* get file number */
custmast_filno = custmast_ifil.tfilno;
}
Now the tricky part! How do you remove and/or add a field? How about adding an index? The trick is to modify the internal IFIL and DODA resources, write them back into the file, and then rebuild the indexes. Of course, you need exclusive access to the file to perform these activities.
Note: Adding or changing fields directly from the ISAM API, in general, will only work in the variable length portion of your record. In the code demonstrated below, we do not modify fields in the fixed length portion of the record. Doing so would require us to create a new table, and consequently, copy over all of the records with a transformation of each record!
In the following example, we will add an index to the file with two segments, cm_custnumb, and cm_custname. We will also change the string field cm_custratg to an integer field cm_status. Here is the pseudocode outlining the basic steps required.
ISAM Code Example 2
/* To add an index - Create new ISEG and IIDX structures */
ISEG cust_iidx_seg {
{0, 4, 12}, /* first segment - cm_custnumb field */
{17, 47, 12) /* second segment - cm_custname filed */
};
IIDX cust_iidx { 51, /* key length */
0, /* key type */
0, /* duplicate flag */
0, /* NULL key flag */
0, /* empty character */
2, /* num segments */
&cust_iidx_seg, /* segments */
NULL, /* r-tree symbolic name */
NULL, /* index file name */
NULL, /* alternate squence */
NULL, /* pad byte character */
} ;
/* Create/Modify the IFIL stucture */
IFIL custmast_ifil_2 = {
"custmast", /* data file name */
-1, /* data file number */
16, /* data record length */
4096, /* data extension size */
ctVLENGTH, /* data file mode */
1, /* number of indices */
0, /* index extension size */
0, /* index file mode */
&cust_iidx, /* pointer to index array */
"cm_custnumb", /* pointer to first field name (r-tree) */
"cm_custcity" /* pointer to last field name (r-tree) */
};
...
if (CloseIFile(custmast_ifil))
Handle_Error("ChangeTable: CloseIFile()", 0);
if (PutIFile(custmast_ifil_2))
Handle_Error("ChangeTable: PutIFIL()", 0);
/* To remove a field - Create a modified DODA */
DATOBJ custmast_doda_2[] = {
{"cm_custnumb",NULL,CT_FSTRING,NUMBLEN},
{"cm_custzipc",NULL,CT_FSTRING,ZIPCLEN},
{"cm_custstat",NULL,CT_FSTRING,STATLEN},
/* NOTE -- THIS IS A DIFFERENT FIELD TYPE! */
{"cm_custatus",NULL,CT_INTEGER,4},
{"cm_custname",NULL,CT_STRING,NAMELEN},
{"cm_custaddr",NULL,CT_STRING,ADDRLEN},
{"cm_custcity",NULL,CT_STRING,CITYLEN}
};
/* Place the DODA back into the file */
if (PutDODA(custmast_ifil_2.tfilno, custmast_doda_2, (UCOUNT)NBR_OF_FIELDS))
Handle_Error("ChangeTable: PutDODA()", 0);
...
/* Rebuild your indexes */
if (RebuildIFile(custmast_ifil_2)) Handle_Error("ChangeTable: RebuildIFile()", 0);
*Whew* That's a lot of details to keep track of. In addition, this may not always work, due to the nature of the fixed length portion of the record.
Elegant C# Solution
c-tree Plus for .NET makes this easy. The following C# code segment demonstrates how simple the above challenge can become using the Alter Table function.
C# Code Example
// Create the table
MyTable.AddField("cm_custnum",FIELD_TYPE.FSTRING,5);
MyTable.AddField("cm_zip",FIELD_TYPE.FSTRING,10);
MyTable.AddField("cm_state",FIELD_TYPE.FSTRING,3);
MyTable.AddField("cm_rating",FIELD_TYPE.FSTRING,2);
MyTable.AddField("cm_name",FIELD_TYPE.FSTRING,48);
MyTable.AddField("cm_address",FIELD_TYPE.FSTRING,48);
MyTable.AddField("cm_city",FIELD_TYPE.FSTRING,48);
MyTable.Create("CUSTMAST", CREATE_MODE.NORMAL_CREATE);
MyTable.Open("CUSTMAST", OPEN_MODE.NORMAL_OPEN);
..
MyTable.Close();
...
// Add an Index
MyTable.Open("CUSTMAST", OPEN_MODE.EXCLUSIVE_OPEN);
Index=Mytable.AddIndex("cm_index1", KEY_TYPE.FIXED_INDEX, false, false);
Index.AddSegment("cm_custnum", SEG_MODE.SCHSEG_SEG);
Index.AddSegment("cm_name", SEG_MODE.SCHSEG_SEG);
// Remove a field
MyTable.DelField("cm_rating");
// Add a field
MyTable.InsertField("cm_name", "cm_status", FIELDTYPE.INTEGER, 4);
// Update the Table!
MyTable.Alter(CTDB_ALTER_INDEX);
That's it! The c-treeDB Alter Table function inspects all of the changes to the table and index relationships, determines what, if any, changes are to be made, and takes care of all the messy details behind the scenes. All with the speed and performance of c-tree Plus!
Not only does c-tree Plus for .NET make these routine programming tasks easy, it seamlessly integrates into the Visual Studio environment. Start typing a few characters of your table name for instance, and Microsoft's IntelliSense brings up a list of matching objects. Pres the "." and the complete list of properties and methods available for this entity is displayed. The complete c-tree Plus environment at your fingertips!
c-tree Plus for .NET still makes it easy to start your application as a simple standalone process, and later, quickly grow into a full client/server enterprise solution. Simply relink your application with the c-tree Plus client library and change a couple lines of code to access the full power of the c-tree Server.
Mix-n-Match APIs!
It is quite possible to extend the elegant c-tree Plus for .NET solution to existing ISAM tables. Given that the table has the appropriate IFIL and DODA resources, simply use a c-tree Plus for .NET Session type of SESSION_TYPE.CTREE_SESSION. You can then work with existing c-tree data files (tables) easily applying the c-tree Plus for .NET API for table modifications. c-tree Plus allows this seamless integration!
Related Articles
Review these previous FairCom eNewsletter articles about the c-tree Plus for .NET interface for other tips and reference.
Build your c-tree Plus for .NET Assembly
Save Time Locating the c-tree Plus for .NET Assembly Reference
.NET Unlicensed dll Errors
|