/*<section title="Intro">
# NAV Tutorial 2 for Java - JOINS

#### DESCRIPTION
This tutorial demonstrates basic table relationships for C-Tree products,
using the Java (jtdb) NAV API, that makes it easy to navigate your data.

It shows how to:

1. Connect to the database
2. Create multiple tables with foreign keys
3. Insert records into each table
4. Navigate those tables utilizing foreign keys

It creates a console application that outputs each step to standard out.

### Why use a NAV API?
1. __NAV makes it easy to achieve unequaled performance.__

    - NAV gives you complete control over data processing.
        1. Navigate records in any order.
        2. Save record positions.
        3. Jump back to saved positions.
        4. Control how each record is locked and participates in transactions.

    - Algorithms are the secret to fast performance.
      - You are not limited to the algorithms built into SQL.
      - NAV allows you to implement any algorithm to process data,
        including algorithms for hierarchies, graphs, objects, documents, etc.

2. __NAV is the easiest way to solve complex data problems.__
    - You can walk through tough problems by navigating through the data step by step.
    - You can debug database data step by step in your favorite programming language.
    - You can leverage the power of your programming language to encapsulate complexity.

3. __NAV literally makes the database an extension of your favorite programming language.__
    - NAV makes working with data no different than working with native collections of objects.
    - NAV makes complex data processing easy to implement, debug, and maintain.


### Why use SQL?
- The easier the problem, the more ideal SQL is.
  - SQL makes it easy to do simple queries and joins.
  - SQL solves many difficult issues with prebuilt SQL syntax, such as JOIN, ORDER BY, GROUP BY, etc.
  - SQL becomes exponentially more difficult to program as data processing becomes more complicated.

## Use and NAV _and_ SQL
- SQL and NAV are equal partners in the FairCom Database Engine.
- You can use both at any time (and at the same time).
- Together, they make working with data easy and fun.

<br />
<br />
<br />

Copyright 2020 by FairCom Corporation, 6300 West Sugar Creek Drive, Columbia, MO 65203 USA

</section> */



/* <comments for="references">

## Adding NAV to your project

Connecting to the NAV APIs in the FairCom Database Engine requires the application to use FairCom's client driver.
1. Reference __``ctreeJTDB.jar``__ in your project libraries or classpath. It provides the object-oriented API to the FairCom Database Engine.
2. Include __``mtclijni64.dll``__ or __``libmtclijni64.so``__ in your project and make sure it is distributed with your application.
   It is the communication layer between your application and the FairCom Database engine that handles the Java Native Interface calls.

These files are located in the folder __``<...database...>\drivers\java.nav\``__

For convenience, this tutorial uses static CTree objects to process session, table, and record data.

<br />

<div style="text-align: center; line-height: normal;">

## You can now leverage the full power of the world's leading _binary structure database_

</div>

</comments> */
//<code title="References" name="references">

import FairCom.CtreeDb.*;
import FairCom.CtreeDb.Types.*;

import java.math.BigDecimal;
import java.util.Calendar;


public class JTDBTutorial2
{
	static CTSession mySession;
	static CTTable tableCustOrdr;
	static CTTable tableOrdrItem;
	static CTTable tableItemMast;
	static CTTable tableCustMast;
	static CTRecord recordCustOrdr;
	static CTRecord recordOrdrItem;
	static CTRecord recordItemMast;
	static CTRecord recordCustMast;

//</code>


	/* <comments for="main">
	## MAIN

	The tutorial is organized into four functions:

	1. __``connect()``__
		- Connects to the database.

	2. __``create()``__
		- Opens or an existing table or creates a table.

	3. __``processData()``__
		- Deletes existing records (if any).
		- Adds data to the tables.
		- Queries the tables and outputs the results to stdout.

	4. __``disconnect()``__
		- Disconnects from the database.


	</comments> */
//<code title="Main" name="main">

	public static void main( String[] args )
	{
		connect();

		create();

		processData();

		disconnect();
	}

//</code>

/*<section title="Prep">
# Preparation
This section shows how to connect to the database and create tables.

<br />

<div style="line-height: normal;">

## _Use your favorite programming language to completely control all database functions_

</div>

</section> */

/* <comments for="connect">
## Connect

__``connect()``__ does the following:
1. Initializes the global session, table, and record objects.
2. Uses the session object to store session state.
3. Logs into the session.

#### NOTES
1. __Logging in__
   - The default user name and password are both __``ADMIN``__
   - The default name for the database server is __``FAIRCOMS``__

2. __Starting the database engine__
   - Starting the database engine is only required
     when you embed the database into your application
     by compiling it in or by linking to it statically or dynamically.

3. __Embedding the database in your application__
   - The FairCom Database Engine has the unique ability to be embedded in an application.
   - The entire database engine can run as a DLL in the application.
   - This is useful for creating self-contained applications for:
      - Devices
      - Desktop Applications
      - Mobile apps
   - When the application connects to an external FairCom Database Engine (as in an N-tier Application Model),
     comment out the following two lines of code:
      - __``CTSession.SetConfigurationFile("ctsrvr.cfg");``__
      - __``CTSession.StartDatabaseEngine();``__

<br />

<div style="text-align: center; line-height: normal;">

## _Connect to many FairCom databases and simultaneously "remote control" all of them_

</div>

</comments> */
//<code title="Connect to Database" name="connect">

	static void connect()
	{
		System.out.println( "Connect" );

		try
		{
			mySession = new CTSession( SESSION_TYPE.CTREE );

			tableCustOrdr = new CTTable( mySession );
			tableOrdrItem = new CTTable( mySession );
			tableItemMast = new CTTable( mySession );
			tableCustMast = new CTTable( mySession );

			recordCustOrdr = new CTRecord( tableCustOrdr );
			recordOrdrItem = new CTRecord( tableOrdrItem );
			recordItemMast = new CTRecord( tableItemMast );
			recordCustMast = new CTRecord( tableCustMast );

			System.out.println( "\tLogon to server..." );
			mySession.Logon( "FAIRCOMS", "ADMIN", "ADMIN" );
		}
		catch( CTException E )
		{
			generalExceptionHandler( E );
		}
	}

//</code>

/* <comments for="create">
## Create

__``Create()``__ calls four methods, each of which will:
1. Open the table, if it exists.
2. Otherwise create the table and then open it.

#### NOTES

1. A typical pattern in NAV is to first open an object, and if it doesn't exist, create it.

2. Another common pattern in NAV is to configure an object and then apply it.
   - For example, the __``AddField()``__ method populates the CTTable object with field definitions.
     and then the __``Create()``__ method creates the table containing those fields.

3. Another pattern is for the NAV API to throw an error when something does not work.
   - Everything in a database is stateful and all state changes follow rules.
   - Many database operations change state and can potentially break rules.
   - When an operation breaks a rule, such as trying to add a table or a record that already exists,
     the operation throws an exception to indicate that it did not change state.
   - Thus, NAV code wraps each major operation in __``try / catch``__.

<br />

<div style="text-align: center; line-height: normal;">

## _NAV leverages object-oriented patterns_

</div>


</comments> */
//<code title="Create Tables" name="create">

	static void create()
	{
		System.out.println( "Create" );

		createCustomerMasterTable();

		createCustomerOrdersTable();

		createOrderItemsTable();

		createItemMasterTable();
	}


	static void createCustomerMasterTable()
	{

		System.out.println( "\tCreating table \"custMast\"" );
		try
		{
			tableCustMast.Open( "custMast", OPEN_MODE.NORMAL );
		}
		catch( CTException unused )
		{
			try
			{
				CTField field1 = tableCustMast.AddField( "cm_custnumb", FIELD_TYPE.CHARS, 4 );
				tableCustMast.AddField( "cm_custzipc", FIELD_TYPE.CHARS, 9 );
				tableCustMast.AddField( "cm_custstat", FIELD_TYPE.CHARS, 2 );
				tableCustMast.AddField( "cm_custratg", FIELD_TYPE.CHARS, 1 );
				tableCustMast.AddField( "cm_custname", FIELD_TYPE.VARCHAR, 47 );
				tableCustMast.AddField( "cm_custaddr", FIELD_TYPE.VARCHAR, 47 );
				tableCustMast.AddField( "cm_custcity", FIELD_TYPE.VARCHAR, 47 );

				CTIndex index1 = tableCustMast.AddIndex( "cmCustomerNumberIndex", KEY_TYPE.FIXED_INDEX, false, false );
				index1.AddSegment( field1, SEG_MODE.SCHSEG );

				System.out.println( "\tCreate table..." );
				tableCustMast.Create( "custMast", CREATE_MODE.NORMAL );

				System.out.println( "\tOpen table..." );
				tableCustMast.Open( "custMast", OPEN_MODE.NORMAL );
			}
			catch( CTException ctException )
			{
				generalExceptionHandler( ctException );
			}
		}

		changeTransactionProcessing( tableCustMast );

		try
		{
			tableCustMast.GetIndex( "cmCustomerNumberIndex" );
		}
		catch( CTException unused )
		{
			try
			{
				CTField field1 = tableCustMast.GetField( "cm_custnumb" );
				CTIndex index1 = tableCustMast.AddIndex( "cmCustomerNumberIndex", KEY_TYPE.FIXED_INDEX, false, false );
				index1.AddSegment( field1, SEG_MODE.SCHSEG );
				tableCustMast.Alter( ALTER_TABLE.NORMAL );
			}
			catch( CTException ctException )
			{
				generalExceptionHandler( ctException );
			}
		}
	}


	static void createCustomerOrdersTable()
	{
		System.out.println( "\tCreating table \"customerOrder\"" );
		try
		{
			tableCustOrdr.Open( "customerOrder", OPEN_MODE.NORMAL );
		}
		catch( CTException unused )
		{
			try
			{
				tableCustOrdr.AddField( "coOrderDate", FIELD_TYPE.DATE, 4 );
				tableCustOrdr.AddField( "coPromiseDate", FIELD_TYPE.DATE, 4 );
				CTField field1 = tableCustOrdr.AddField( "coOrderNumber", FIELD_TYPE.CHARS, 6 );
				CTField field2 = tableCustOrdr.AddField( "coCustomerNumber", FIELD_TYPE.CHARS, 4 );

				CTIndex index1 = tableCustOrdr.AddIndex( "coOrderNumber_idx", KEY_TYPE.LEADING_INDEX, false, false );
				index1.AddSegment( field1, SEG_MODE.SCHSEG );
				CTIndex index2 = tableCustOrdr.AddIndex( "coCustomerNumber_idx", KEY_TYPE.LEADING_INDEX, true, false );
				index2.AddSegment( field2, SEG_MODE.SCHSEG );

				System.out.println( "\tCreate table..." );
				tableCustOrdr.Create( "customerOrder", CREATE_MODE.NORMAL );

				System.out.println( "\tOpen table..." );
				tableCustOrdr.Open( "customerOrder", OPEN_MODE.NORMAL );
			}
			catch( CTException ctException )
			{
				generalExceptionHandler( ctException );
			}
		}

		changeTransactionProcessing( tableCustOrdr );
	}


	static void createOrderItemsTable()
	{
		System.out.println( "\tCreating table \"orderItem\"" );
		try
		{
			tableOrdrItem.Open( "orderItem", OPEN_MODE.NORMAL );
		}
		catch( CTException unused )
		{
			try
			{
				CTField field1 = tableOrdrItem.AddField( "oiSequenceNumber", FIELD_TYPE.SMALLINT, 2 );
				tableOrdrItem.AddField( "oiQuantity", FIELD_TYPE.SMALLINT, 2 );
				CTField field2 = tableOrdrItem.AddField( "oiOrderNumber", FIELD_TYPE.CHARS, 6 );
				CTField field3 = tableOrdrItem.AddField( "oiItemNumber", FIELD_TYPE.CHARS, 5 );

				CTIndex index1 = tableOrdrItem.AddIndex( "oiOrderNumberIndex", KEY_TYPE.LEADING_INDEX, false, false );
				index1.AddSegment( field2, SEG_MODE.SCHSEG );
				index1.AddSegment( field1, SEG_MODE.SCHSEG );
				CTIndex index2 = tableOrdrItem.AddIndex( "oiItemNumberIndex", KEY_TYPE.LEADING_INDEX, true, false );
				index2.AddSegment( field3, SEG_MODE.SCHSEG );

				System.out.println( "\tCreate table..." );
				tableOrdrItem.Create( "orderItem", CREATE_MODE.NORMAL );

				System.out.println( "\tOpen table..." );
				tableOrdrItem.Open( "orderItem", OPEN_MODE.NORMAL );
			}
			catch( CTException ctExceptionE )
			{
				generalExceptionHandler( ctExceptionE );
			}
		}
		changeTransactionProcessing( tableOrdrItem );
	}


	static void createItemMasterTable()
	{
		System.out.println( "\ttable \"itemMaster\"" );
		try
		{
			tableItemMast.Open( "itemMaster", OPEN_MODE.NORMAL );
		}
		catch( CTException unused )
		{
			try
			{
				tableItemMast.AddField( "imItemWeight", FIELD_TYPE.INTEGER, 4 );
				tableItemMast.AddField( "imItemPrice", FIELD_TYPE.MONEY, 4 );
				CTField field1 = tableItemMast.AddField( "imItemNumber", FIELD_TYPE.CHARS, 5 );
				tableItemMast.AddField( "imItemDescription", FIELD_TYPE.VARCHAR, 47 );

				CTIndex index1 = tableItemMast.AddIndex( "imItemNumberIndex", KEY_TYPE.LEADING_INDEX, false, false );
				index1.AddSegment( field1, SEG_MODE.SCHSEG );

				System.out.println( "\tCreate table..." );
				tableItemMast.Create( "itemMaster", CREATE_MODE.NORMAL );

				System.out.println( "\tOpen table..." );
				tableItemMast.Open( "itemMaster", OPEN_MODE.NORMAL );
			}
			catch( CTException ctException )
			{
				generalExceptionHandler( ctException );
			}
		}
		changeTransactionProcessing( tableItemMast );
	}

//</code>


/*<section title="Process">
# Processing Data
This section shows how to insert, delete, and display Records

<br />

## _NAV eliminates double processing of your data_

  - A SQL database loops through your data and then returns the data so your application can loop through it again.

  - In NAV, your application loops through the data once by "remote controlling" the database.




</section> */

/* <comments for="processData">
## Process Data

ProcessData() calls separate functions to add records to all tables.

It then queries all orders, and gathers information about each order from various tables before displaying the results.


<br />

## _Literally extend your app directly into the database_

</comments> */
//<code title="Process Data" name="processData">

	static void processData()
	{
		int quantity;
		BigDecimal price;
		BigDecimal total;
		String itemNumber;
		String customerNumber;
		String orderNumber;
		String customerName;
		boolean isOrderFound;
		boolean isItemFound;

		System.out.println( "Process Data" );

		addCustomerMasterRecords();
		addCustomerOrdersRecords();
		addOrderItemsRecords();
		addItemMasterRecords();

		System.out.println( "\n\tQuery Results" );

		try
		{
			isOrderFound = recordCustOrdr.First();

			while( isOrderFound )
			{
				orderNumber = recordCustOrdr.GetFieldAsString( 2 );
				customerNumber = recordCustOrdr.GetFieldAsString( 3 );

				recordCustMast.Clear();
				recordCustMast.SetFieldAsString( 0, customerNumber );
				if( !recordCustMast.Find( FIND_MODE.EQUAL ) )
				{
					continue;
				}
				customerName = recordCustMast.GetFieldAsString( 4 );

				recordOrdrItem.Clear();
				recordOrdrItem.SetFieldAsString( 2, orderNumber );
				recordOrdrItem.RecordSetOn( 6 );
				isItemFound = recordOrdrItem.First();

				total = BigDecimal.ZERO;
				while( isItemFound )
				{
					quantity = recordOrdrItem.GetFieldAsInt( 1 );
					itemNumber = recordOrdrItem.GetFieldAsString( 3 );

					recordItemMast.Clear();
					recordItemMast.SetFieldAsString( 2, itemNumber );
					recordItemMast.Find( FIND_MODE.EQUAL );
					price = recordItemMast.GetFieldAsBigDecimal( 1 );

					total = total.add( price.multiply( new BigDecimal( quantity ) ) );

					isItemFound = recordOrdrItem.Next();
				}

				recordOrdrItem.RecordSetOff();

				System.out.println( "\t" + customerName + "\t" + total );

				if( !recordCustOrdr.Next() )
				{
					isOrderFound = false;
				}
			}
		}
		catch( CTException E )
		{
			generalExceptionHandler( E );
		}
	}

//</code>


/* <comments for="DeleteRecords">
## Delete Records

__``DeleteRecords()``__ shows how to
1. Find the first record in a table.
2. Delete all records in a table one by one.

<br />

#### Algorithm
  - Find the first record
  - When a record is found:
    - Delete it
    - Move to next record
  - Repeat

<br />

#### NOTES
 - Working with data is the same as working with collections of objects.
   Your code controls every step.

 - The FairCom Database Engine is designed specifically to give your application complete control,
   and do it with unrivaled speed.

 - Everything about the database engine is designed to navigate data:
   - The indexes have a special structure to make
     __``First()``__, __``Next()``__, __``Prev()``__, and  __``Last()``__ very fast.
   - The communication protocols are highly optimized to minimize latency and marshalling.

<br />

<div style="text-align: center; line-height: normal;">

## _The database becomes an extension of the application &mdash; doing exactly what the application tells it to do_

</div>

</comments> */
//<code title="Delete Records" name="DeleteRecords">

	static void deleteRecords( CTRecord record )
	{
		boolean found;

		System.out.println( "\tDelete records..." );

		try
		{
			found = record.First();

			while( found )
			{
				record.Delete();
				found = record.Next();
			}
		}
		catch( CTException E )
		{
			generalExceptionHandler( E );
		}
	}

//</code>

/* <comments for="addCustomerMasterRecords">
## Add Records

__``addCustomerMasterRecords()``__ shows how to insert records into the "custMast" table.

1. It uses the __``CustomerRecord``__ class to hold customer data.

2. It creates an array of __``CustomerRecord``__ objects and populates them with data.

3. It then iterates through that array, and inserts each record into the "custMast" table.

<br />

#### NOTES

This example illustrates how NAV makes the FairCom Database Engine an extension of the objects in your code.
In fact, in C and C++ you can literally write the binary data in object memory directly into records
and read binary data out of records directly into object memory. This completely eliminates data transformation.

In all programming languages, the c-tree Database API makes it easy and fast
to extract data from an object and put it into a record.
It is fast and efficient because under the hood, its driver writes data into a binary buffer, and
that buffer goes directly into and out of the database without translation.
In other words, the application does all the work of mapping and formatting data,
and the database simply processes all data as simple binary data stored in records.

This approach distributes the processing load between the client and the database.
This is much more effective than SQL databases because a SQL database must do all the work
of translating client data into proprietary internal database structures and vice-versa.

<br />

<div style="text-align: center; line-height: normal;">

## _Achieve extreme speed by minimizing and distributing data&nbsp;transformation across app servers_

</div>

</comments> */
//<code title="Add Customer Records" name="addCustomerMasterRecords">

	static void addCustomerMasterRecords()
	{
		CustomerRecord[] customerRecords = new CustomerRecord[4];
		customerRecords[0] = new CustomerRecord( "1000", "92867", "CA", "1", "Bryan Williams", "2999 Regency", "Orange" );
		customerRecords[1] = new CustomerRecord( "1001", "61434", "CT", "1", "Michael Jordan", "13 Main", "Harford" );
		customerRecords[2] = new CustomerRecord( "1002", "73677", "GA", "1", "Joshua Brown", "4356 Cambridge", "Atlanta" );
		customerRecords[3] = new CustomerRecord( "1003", "10034", "MO", "1", "Keyon Dooling", "19771 Park Avenue", "Columbia" );

		deleteRecords( recordCustMast );

		System.out.println( "\tAdd records in table \"custmast\"..." );

		try
		{
			for( CustomerRecord customerRecord : customerRecords )
			{
				recordCustMast.Clear();

				recordCustMast.SetFieldAsString( 0, customerRecord.number );
				recordCustMast.SetFieldAsString( 1, customerRecord.zipcode );
				recordCustMast.SetFieldAsString( 2, customerRecord.state );
				recordCustMast.SetFieldAsString( 3, customerRecord.rating );
				recordCustMast.SetFieldAsString( 4, customerRecord.name );
				recordCustMast.SetFieldAsString( 5, customerRecord.address );
				recordCustMast.SetFieldAsString( 6, customerRecord.city );

				recordCustMast.Write();
			}
		}
		catch( CTException E )
		{
			generalExceptionHandler( E );
		}
	}

//</code>

/* <comments for="addCustomerOrdersRecords">
## Add Records

__``addCustomerOrdersRecords()``__ shows how to insert records into the "customerOrder" table.

1. It uses the __``OrderData``__ class to hold customer data.

2. It creates an array of __``OrderData``__ objects and populates them with data.

3. It then iterates through that array, and inserts each record into the "customerOrder" table.

<br />

#### NOTES

This example illustrates how NAV makes the FairCom Database Engine an extension of the objects in your code.
In fact, in C and C++ you can literally write the binary data in object memory directly into records
and read binary data out of records directly into object memory. This completely eliminates data transformation.

In all programming languages, the c-tree Database API makes it easy and fast
to extract data from an object and put it into a record.
It is fast and efficient because under the hood, its driver writes data into a binary buffer, and
that buffer goes directly into and out of the database without translation.
In other words, the application does all the work of mapping and formatting data,
and the database simply processes all data as simple binary data stored in records.

This approach distributes the processing load between the client and the database.
This is much more effective than SQL databases because a SQL database must do all the work
of translating client data into proprietary internal database structures and vice-versa.

<br />

<div style="text-align: center; line-height: normal;">

## _Achieve extreme speed by minimizing and distributing data&nbsp;transformation across app servers_

</div>

</comments> */
//<code title="Add Customer Order Records" name="addCustomerOrdersRecords">

	static void addCustomerOrdersRecords()
	{
		OrderRecord[] orderRecords = new OrderRecord[2];
		Calendar orderDate0 = Calendar.getInstance();
		Calendar promiseDate0 = Calendar.getInstance();
		orderDate0.set( 2002, Calendar.SEPTEMBER, 1 );
		promiseDate0.set( 2002, Calendar.SEPTEMBER, 5 );
		orderRecords[0] = new OrderRecord( orderDate0, promiseDate0, "1", "1001" );
		Calendar orderDate1 = Calendar.getInstance();
		Calendar promiseDate1 = Calendar.getInstance();
		orderDate1.set( 2002, Calendar.SEPTEMBER, 2 );
		promiseDate1.set( 2002, Calendar.SEPTEMBER, 6 );
		orderRecords[1] = new OrderRecord( orderDate1, promiseDate1, "2", "1002" );

		deleteRecords( recordCustOrdr );

		System.out.println( "\tAdd records in table CustomerOrders..." );

		try
		{
			for( OrderRecord orderRecord : orderRecords )
			{
				recordCustOrdr.Clear();

				recordCustOrdr.SetFieldAsCalendar( 0, orderRecord.orderDate );
				recordCustOrdr.SetFieldAsCalendar( 1, orderRecord.promiseDate );
				recordCustOrdr.SetFieldAsString( 2, orderRecord.orderNumber );
				recordCustOrdr.SetFieldAsString( 3, orderRecord.customerNumber );

				recordCustOrdr.Write();
			}
		}
		catch( CTException E )
		{
			generalExceptionHandler( E );
		}
	}

//</code>

/* <comments for="addOrderItemsRecords">
## Add Records

__``addOrderItemsRecords()``__ shows how to insert records into the "orderItem" table.

1. It uses the __``OrderItemData``__ class to hold customer data.

2. It creates an array of __``OrderItemData``__ objects and populates them with data.

3. It then iterates through that array, and inserts each record into the "orderItem" table.

<br />

#### NOTES

This example illustrates how NAV makes the FairCom Database Engine an extension of the objects in your code.
In fact, in C and C++ you can literally write the binary data in object memory directly into records
and read binary data out of records directly into object memory. This completely eliminates data transformation.

In all programming languages, the c-tree Database API makes it easy and fast
to extract data from an object and put it into a record.
It is fast and efficient because under the hood, its driver writes data into a binary buffer, and
that buffer goes directly into and out of the database without translation.
In other words, the application does all the work of mapping and formatting data,
and the database simply processes all data as simple binary data stored in records.

This approach distributes the processing load between the client and the database.
This is much more effective than SQL databases because a SQL database must do all the work
of translating client data into proprietary internal database structures and vice-versa.

<br />

<div style="text-align: center; line-height: normal;">

## _Achieve extreme speed by minimizing and distributing data&nbsp;transformation across app servers_

</div>

</comments> */
//<code title="Add Order Item Records" name="addOrderItemsRecords">

	static void addOrderItemsRecords()
	{
		OrderItemRecord[] orderItemRecords = new OrderItemRecord[4];
		orderItemRecords[0] = new OrderItemRecord( 1, 2, "1", "1" );
		orderItemRecords[1] = new OrderItemRecord( 2, 1, "1", "2" );
		orderItemRecords[2] = new OrderItemRecord( 3, 1, "1", "3" );
		orderItemRecords[3] = new OrderItemRecord( 1, 3, "2", "3" );

		deleteRecords( recordOrdrItem );

		System.out.println( "\tAdd records in table \"orderItems\"..." );

		try
		{
			for( OrderItemRecord orderItemRecord : orderItemRecords )
			{
				recordOrdrItem.Clear();

				recordOrdrItem.SetFieldAsInt( 0, orderItemRecord.seqNumber );
				recordOrdrItem.SetFieldAsInt( 1, orderItemRecord.quantity );
				recordOrdrItem.SetFieldAsString( 2, orderItemRecord.orderNum );
				recordOrdrItem.SetFieldAsString( 3, orderItemRecord.itemNum );

				recordOrdrItem.Write();
			}
		}
		catch( CTException E )
		{
			generalExceptionHandler( E );
		}
	}

//</code>

/* <comments for="addItemMasterRecords">
## Add Records

__``addItemMasterRecords()``__ shows how to insert records into the "itemMaster" table.

1. It uses the __``ItemData``__ class to hold customer data.

2. It creates an array of __``ItemData``__ objects and populates them with data.

3. It then iterates through that array, and inserts each record into the "itemMaster" table.

<br />

#### NOTES

This example illustrates how NAV makes the FairCom Database Engine an extension of the objects in your code.
In fact, in C and C++ you can literally write the binary data in object memory directly into records
and read binary data out of records directly into object memory. This completely eliminates data transformation.

In all programming languages, the c-tree Database API makes it easy and fast
to extract data from an object and put it into a record.
It is fast and efficient because under the hood, its driver writes data into a binary buffer, and
that buffer goes directly into and out of the database without translation.
In other words, the application does all the work of mapping and formatting data,
and the database simply processes all data as simple binary data stored in records.

This approach distributes the processing load between the client and the database.
This is much more effective than SQL databases because a SQL database must do all the work
of translating client data into proprietary internal database structures and vice-versa.

<br />

<div style="text-align: center; line-height: normal;">

## _Achieve extreme speed by minimizing and distributing data&nbsp;transformation across app servers_

</div>

</comments> */
//<code title="Add Item Records" name="addItemMasterRecords">

	static void addItemMasterRecords()
	{
		ItemRecord[] itemRecords = new ItemRecord[4];
		itemRecords[0] = new ItemRecord( 10, new BigDecimal( "19.95" ), "1", "Hammer" );
		itemRecords[1] = new ItemRecord( 3, new BigDecimal( "9.99" ), "2", "Wrench" );
		itemRecords[2] = new ItemRecord( 4, new BigDecimal( "16.59" ), "3", "Saw" );
		itemRecords[3] = new ItemRecord( 1, new BigDecimal( "3.98" ), "4", "Pliers" );

		deleteRecords( recordItemMast );

		System.out.println( "\tAdd records in table \"itemMaster\"..." );

		try
		{
			for( ItemRecord itemRecord : itemRecords )
			{
				recordItemMast.Clear();

				recordItemMast.SetFieldAsInt( 0, itemRecord.weight );
				recordItemMast.SetFieldAsBigDecimal( 1, itemRecord.price );
				recordItemMast.SetFieldAsString( 2, itemRecord.itemNum );
				recordItemMast.SetFieldAsString( 3, itemRecord.description );

				recordItemMast.Write();
			}
		}
		catch( CTException E )
		{
			generalExceptionHandler( E );
		}
	}

//</code>


/*<section title="Cleanup">
# Cleanup
This section shows how to close tables and disconnect from the database.

<br />

## Release database objects when your code is disconnect with them
## &mdash; just like any other resource in your code

</section> */


/* <comments for="disconnect">
## Disconnect

__``Disconnect()``__ shows how to

1. Close an open table.

2. Log out from the FairCom Database Engine.

<br />

#### NOTES
- You only need to stop the database engine when the database is embedded in the application -
  like it is in this tutorial.

</comments> */
//<code title="Disconnect from Database" name="disconnect">

	static void disconnect()
	{
		System.out.println( "Disconnect" );

		try
		{
			System.out.println( "\tClose tables..." );
			tableCustMast.Close();
			tableCustOrdr.Close();
			tableOrdrItem.Close();
			tableItemMast.Close();

			System.out.println( "\tLogout..." );
			mySession.Logoff();
		}
		catch( CTException E )
		{
			generalExceptionHandler( E );
		}
	}

//</code>

/*<section title="General">
# General
This section contains helper functions:

1. to handle exceptions.

2. to change the table transaction processing mode.

<br />

<div style="line-height: normal;">

## _Encapsulate and extend the NAV API using your favorite programming language features_

</div>

</section> */


/* <comments for="GeneralExceptionHandler">
## Handling General Exceptions

__``GeneralExceptionHandler()``__ does the following:

1. Writes an unexpected error to standard out.

2. Exits the application with an error code of 1.

</comments> */
//<code title="Handling General Exceptions" name="GeneralExceptionHandler">

	static void generalExceptionHandler( CTException err )
	{
		System.out.println( "\nERROR: [" + err.GetErrorCode() + "] - " + err.GetErrorMsg() );
		System.out.println( "*** Execution aborted *** " );
		System.exit( 1 );
	}

//</code>

/* <comments for="ChangeTransactionProcessing">
## Changing Table Transaction Mode

__``ChangeTransactionProcessing()``__ is a helper function
used during table creation to disable transaction processing.
It illustrates how you can control the transaction processing characteristics of each individual table.

Transaction control ensures full ACID durability and, like all other ACID-compliant SQL databases,
it comes with the performance cost of writing transactions into transaction logs on disk.

Turning off transaction control increases the speed of all database inserts, updates, and deletes,
but it also increases the risk of data loss if the hardware or software fails unexpectedly.

<br />

### Function Process
- It gets the create mode of a table.
- If the table is not under transaction control,
  it updates the table's create mode to be under transaction control.
- A table's creation modes are a set of bit flags. This code turns off the "transaction&nbsp;control" bit flag.

<br />

### NOTES
- Transaction control is turned on in this tutorial to illustrate one of many low-level table features
  that you can individually control in each table.
- The tutorial works equally well transaction control turned on or off.

<br />

## _NAV makes it easy to take complete control of your data_

</comments> */
//<code title="Changing Table Transaction Mode" name="ChangeTransactionProcessing">

	static void changeTransactionProcessing( CTTable table )
	{
		try
		{
			int mode = table.GetCreateMode();

			if( ( mode & CREATE_MODE.TRNLOG ) != 0 )
			{
				mode ^= CREATE_MODE.TRNLOG;
				table.UpdateCreateMode( mode );
			}
		}
		catch( CTException E )
		{
			generalExceptionHandler( E );
		}
	}

//</code>

/* <comments for="CustomerRecord">
## The CustomerRecord data structure class

__``CustomerRecord``__ is a data storage class used by addCustomerMasterRecords() to load data into the "custMast" table.

</comments> */
//<code title="The CustomerRecord class" name="CustomerRecord">

	public static class CustomerRecord
	{
		private final String number;
		private final String zipcode;
		private final String state;
		private final String rating;
		private final String name;
		private final String address;
		private final String city;


		public CustomerRecord( String number, String zipcode, String state, String rating, String name, String address, String city )
		{
			this.number = number;
			this.zipcode = zipcode;
			this.state = state;
			this.rating = rating;
			this.name = name;
			this.address = address;
			this.city = city;
		}
	}

//</code>

/* <comments for="OrderRecord">
## The OrderRecord data structure class

__``OrderRecord``__ is a data storage class used by addCustomerOrdersRecords() to load data into the "customerOrder" table.

</comments> */
//<code title="The OrderRecord class" name="OrderRecord">

	public static class OrderRecord
	{
		private final Calendar orderDate;
		private final Calendar promiseDate;
		private final String orderNumber;
		private final String customerNumber;


		public OrderRecord( Calendar orderDate, Calendar promiseDate, String orderNumber, String customerNumber )
		{
			this.orderDate = orderDate;
			this.promiseDate = promiseDate;
			this.orderNumber = orderNumber;
			this.customerNumber = customerNumber;
		}
	}

//</code>

/* <comments for="OrderItemRecord">
## The OrderItemRecord data structure class

__``OrderItemRecord``__ is a data storage class used by addOrderItemsRecords() to load data into the "orderItem" table.

</comments> */
//<code title="The OrderItemRecord class" name="OrderItemRecord">

	public static class OrderItemRecord
	{
		private final String orderNum;
		private final int seqNumber;
		private final int quantity;
		private final String itemNum;


		public OrderItemRecord( int seqNumber, int quantity, String orderNum, String itemNum )
		{
			this.orderNum = orderNum;
			this.seqNumber = seqNumber;
			this.quantity = quantity;
			this.itemNum = itemNum;
		}
	}

//</code>

/* <comments for="ItemRecord">
## The ItemRecord data structure class

__``ItemRecord``__ is a data storage class used by addItemMasterRecords() to load data into the "itemMaster" table.

</comments> */
//<code title="The ItemRecord class" name="ItemRecord">

	public static class ItemRecord
	{
		private final int weight;
		private final BigDecimal price;
		private final String itemNum;
		private final String description;


		public ItemRecord( int weight, BigDecimal price, String itemNum, String description )
		{
			this.weight = weight;
			this.price = price;
			this.itemNum = itemNum;
			this.description = description;
		}
	}
}

//</code>
