Chapter 2. Tutorials

Table of Contents

2.1. Tutorial 1: Writing new rows to a table, based on a trigger
2.2. Tutorial 2: Updating existing rows, or writing new ones
2.3. Tutorial 3: Writing data from a database to the DataHub
2.4. Viewing data from a web browser

2.1. Tutorial 1: Writing new rows to a table, based on a trigger

This script creates and inserts a new row into a database whenever a trigger point changes value. The data that gets inserted into the row is an ID for the entry (the primary key), the value of a specified point, the timestamp of the change, and the name and quality of the point.

[Note]

The tutorials in this manual use SQL commands to query the database. The syntax for these commands may vary slightly from one ODBC database to another. If a given tutorial doesn't work right away, check the syntax of the SQL commands used here against the syntax that your database uses.

Getting Started

To run this code or the other tutorials in this manual, you will need to do the following:

  1. Set up a DSN (Data Source Name) called "DataHubTest" and point it to an empty database on your database server.
  2. Create a table in the database named "datatable" that contains at least five columns with names, data types, and other attributes exactly as specified here:
    Column nameData typeOther attributes
    IDintegeridentity, non-null, counter
    PTVALUErealnon-null
    PTTIMEdatetimenull
    PTNAMEtext stringnull
    PTQUALITYtext stringnull
    Any other columns in this table must be allowed to take on a null value.
  3. Start DataSim.
  4. Find the tutorial script ODBCTutorial1.g on your system, and run it.
    [Note]

    You can access DataHub scripts and scripting capabilities by pressing the Scripting button in the Properties window, to display the Scripting and Customization screen. The upper half of the screen shows the Gamma files currently configured in the DataHub:

    The Open button opens a file selector for you to add an existing script to the list. Scripts are normally kept in the DataHub's scripts subdirectory, C:\Program Files\Cogent\DataHub\scripts\myscript.g.

    The Edit button opens the selected script in the Script Editor for editing.

    You can view error message and printed output from a script in the Script Log. To open the Script Log, right click on the DataHub icon in the system tray, and select View Script Log.

    For complete information about DataHub scripting, please refer to the DataHub Scripting Manual

  5. Check the database table to see the results. Once you have it working, you can modify the code as explained below.

The Code: ODBCTutorial1.g

/* All user scripts should derive from the base "Application" class */

require ("Application");

/* Get the Gamma library functions and methods for ODBC and/or
 * Windows programming.  Uncomment either or both. */

//require ("WindowsSupport");
require ("ODBCSupport");
require ("Time");
require ("Quality");

/* Applications share the execution thread and the global name
 * space, so we create a class that contains all of the functions
 * and variables for the application.  This does two things:
 *   1) creates a private name space for the application, and
 *   2) allows you to re-load the application to create either
 *      a new unique instance or multiple instances without
 *      damaging an existing running instance.
 */

/* 
 * This application assumes that the table specified by the "tablename"
 * member variable exists in the DSN specified by the "DSN" member
 * variable below.
 * The table consists of at least the following columns:
 *    ID - integer, identity, non-null, counter
 *    PTVALUE - real, non-null
 *    PTTIME - datetime, null
 *    PTNAME - text string, null
 *    PTQUALITY - text string, null
 * Any other columns in this table must be allowed to take on a 
 * NULL value.
 */
 
class ODBCTutorial1 Application
{
    /* User-defined values, may be changed as needed. */
    DSN = "DataHubTest";
    user = "test";
    password = "test";
    tablename = "datatable";

    /* These values get defined by the program.*/
    conn;
    env;
    tableclass;
}

/* Connect to the DSN and create a class that maps the table. */
method ODBCTutorial1.Connect ()
{
    /* Create the ODBC environment and connection */
    .env = ODBC_AllocEnvironment();
    .conn = .env.AllocConnection();
	
    /* Attempt the connection. */
    ret = .conn.Connect (.DSN, .user, .password);
    if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
        error (.conn.GetDiagRec());

    /* Create a class from the table */
    .tableclass = .conn.ClassFromTable (#DataEntry, nil, .tablename);
    
    /* Set the primary key.  This is redundant for MS-SQL and MYSQL since
       they can figure it out themselves, but Access requires it. */
    mykey = .conn.SetPrimaryKey (.tableclass, "ID");
}

/* Fill a database record with new information from a point change. */
method ODBCTutorial1.FillRecord (record, sym, newvalue)
{
    local   timestamp;
	
    timestamp = localtime (PointGetUnixTime(sym));
    timestamp = format ("%d-%02d-%02d %02d:%02d:%02d",
        timestamp.year + 1900, timestamp.mon + 1,
        timestamp.mday, timestamp.hour, timestamp.min,
        timestamp.sec);
    record.PTNAME = string (sym);
    record.PTVALUE = number (newvalue);
    record.PTTIME = timestamp;
    record.PTQUALITY = GetQualityName(PointMetadata(sym).quality);
    record;
}

/* Write a new record into the database based on a point change. */
method ODBCTutorial1.AddRecord (sym, newvalue)
{
    local    record = new DataEntry();
    .FillRecord (record, sym, newvalue);
    .conn.Insert (record);
    record;
}

/* The mainline.  Connect to the database and begin storing data from
   the DataHub into the database. */
method ODBCTutorial1.constructor ()
{
    local    ret;
	
    /* Connect to the DSN. */
    .Connect();
	
    /* Add a record when a point changes.  */
    .OnChange (#$DataSim:Square, `(@self).AddRecord (#$DataSim:Sine, $DataSim:Sine));
    
    /* Add more points like this:
     *   .OnChange (#$DataSim:Square, `(@self).AddRecord (#$MyDomain:MyPt, $MyDomian:MyPt));
     * Have the trigger point's value get written like this:
     *   .OnChange (#$DataSim:Square, `(@self).AddRecord (#$DataSim:Square, $DataSim:Square));
     */  
}

/* Any code to be run when the program gets shut down. */
method ODBCTutorial1.destructor ()
{
}

/* Start the program by instantiating the class.  If your
 * constructor code does not create a persistent reference to
 * the instance (self), then it will be destroyed by the
 * garbage collector soon after creation.  If you do not want
 * this to happen, assign the instance to a global variable, or
 * create a static data member in your class to which you assign
 * 'self' during the construction process.  ApplicationSingleton()
 * does this for you automatically. */
ApplicationSingleton (ODBCTutorial1);

Modifying the Code

There are several ways you can modify the code. These modifications are made in the ODBCTutorial1.constructor method, towards the end of the script.

    Add more DataSim points  using this format:

    .OnChange (#$DataSim:Square, `(@self).AddRecord (#$DataSim:pointname, $DataSim:pointname));

    Where pointname is the name of a point in DataSim.

    Change the trigger point  like this:

    .OnChange (#$DataSim:pointname, `(@self).AddRecord (#$DataSim:Sine, $DataSim:Sine));

    Where pointname is the name of a point in DataSim.

    Add your own points You can add your own points using this syntax:

    .OnChange (#$domain:pointname, `(@self).AddRecord (#$domain:pointname, $domain:pointname));

    where domain is the domain that the point is in, and pointname is the name of the point.