Skip to content

cConnection

Properties · Events · Methods · Index of Classes

Handles connections for drivers that support Connection IDs (Managed Connections).

Hierarchy

cObject
cConnection

Library: Common (Windows and Web Application) Class Library
Package: cConnection.pkg

Description

Handles connections for drivers that support Connection IDs. This is referred to as using Managed Connections.

Read extended information about Managed Connections.

The cConnection class (typically represented as a single global object) allows you to:

  • Add Connection ID / Connection String pairs
  • Use those Connection IDs in your table INT files
  • Log in to database servers via Connection IDs
  • Make embedded SQL (ESQL) connections to servers via Connection IDs

The cConnection class provides a complete interface, including:

  • Adding, removing, and editing connections
  • Login/Logout via Connection IDs
  • Handling encrypted credentials (user names and encrypted passwords)
  • Dynamic switching of connection string definitions at runtime
  • A simple high-level interface for basic usage
  • A complete lower-level interface for advanced usage
  • Integration with cApplication to simplify high-level coding

A more standard approach for dealing with SQL:

  1. Define a server/database connection
  2. Log in to the SQL server and database
  3. Open and access tables in that database

Basic cConnection Class Usage

At the simplest level, managed connections consist of:

  1. Create the Connections INI file (using the Studio's Manage Connections dialog)
  2. Configure your tables to use managed connections (using the Studio's Connection Wizard)
  3. Add a few lines of standard code to your application:
  4. Use the cConnection package
  5. Create a cConnection object and place it above or inside your cApplication object
  6. Add a login encryption object package and a database login dialog package inside or above the cConnection object
  7. Compile and run your application. The cApplication object will automatically register and log in all managed connections.

Example:

Use cConnection.pkg
:
Object oApplication is a cApplication

    Set psProduct to "DataFlex Examples"
    :

    Object oConnection is a cConnection
        Set pbLoginOnOpen to False
        Use LoginEncryption.pkg
        Use DatabaseLoginDialog.dg  // (Windows applications only)
    End_Object

End_Object

Login Credentials for Managed Connections in Web Applications

Windows applications include a connection dialog (via Use DatabaseLoginDialog.dg). Web applications cannot display Windows dialogs and the DataFlex Web Application Service often uses a different Windows user id than the Studio developer id. To simplify credential management, the Studio includes a Windows application template under File > Create New > Project named "Managed Connection Login Project". Running this template application allows you to set credentials for managed applications; afterwards you can run a Web Application in the same workspace that uses those credentials.


ghoConnection Handle

Typically there is a single global cConnection object. When the object is created the system global ghoConnection is set to its object handle. This allows other parts of the framework to communicate with the cConnection object without knowing its name and location. Developers should use this handle when communicating with the cConnection object.

Because a global handle is used, it does not matter where the cConnection object is located as long as it is created before it is used. As a general rule it should be created before or inside your cApplication object.


Auto Connect

If pbAutoConnect is True, AutoConnect registers all connections by sending RegisterAllConnections and logs in to all connections by sending LoginAll. If either of these messages fail, the application is aborted.


Object, Class and Package Placement Recommendations and Requirements

The cConnection object should be placed inside of or before the cApplication object. If you are not using managed connections, you don't need it, although having it won't cause problems. Creating the cConnection object inside a cApplication subclass is allowed, but it makes customization via property settings and events harder; therefore packages do not do this by default.

Recommended object placement:

Object oApplication is a cApplication

    Set psProduct to "DataFlex Examples"
    :

    Object oConnection is a cConnection
        Use LoginEncryption.pkg
        Use DatabaseLoginDialog.dg
    End_Object

End_Object

Summary of requirements:

  1. Object oConnection: The connection object should be placed inside of or before the cApplication object. The oConnection object is optional.
  2. Use LoginEncryption.pkg: The Login Encryption object (if used) must be created before a connection is added (registered). The encryption object must be created before the cApplication object's End_Object. Placing it inside the cConnection object is recommended.
  3. Use DatabaseLoginDialog.pkg: The database login dialog object (if used) must be created before a connection is logged into. The login dialog object must be created before the cApplication object's End_Object. Placing it inside the cConnection object is recommended.

Embedded SQL and cConnection

Using Connection IDs makes Embedded SQL (ESQL) easier. Once a connection is created and logged in, obtain an SQL connection handle by calling SQLConnectionId on ghoConnection, passing the Connection ID. This lets you create SQL statements without handling connection strings and logins.

Example:

Get SQLConnectionId of ghoConnection "ID1" to hoConnect
Get SQLOpen of hoConnect to hoStmt
Send SQLExecDirect of hoStmt "select * from salesp"
Get SQLFetchResultsetValues of hoStmt to Mydata
Send SQLClose of hoStmt
Send SQLDisconnect of hoConnect

Note: the connection must be registered and logged into before it can be used.

In addition to SQLConnectionId, the message SQLConnectionByTable may be used to create a connection handle for the connection being used by an opened table.


Advanced cConnection Class Usage

Under the high-level interface there are at least two lower-level interfaces for handling custom and dynamic conditions. Tools like the Studio use these lower-level interfaces to register connections, log in to servers, open and close tables, log out of connections, remove connections, and re-register a new set of connections. These interfaces are available for deep customization.

Adding Connections

Before using a managed connection you must define and initialize it. Typically this is done by reading the connections INI file and registering all active connections. Public interfaces to add connections include:

  • RegisterAllConnections — reads all connections and registers all active connections.
  • AddAllConnections — reads all connections and registers all active connections.
  • LoadStoredConnections — loads an array of managed connections from a stored source.

Logging Into Connections

Logins occur after connections are registered and should happen before tables that use the connection are opened. Interfaces for logging in include:

  • LoginAll — logs in to all managed connections.
  • LoginAllConnections — attempts to log in to all managed connections.
  • LoginConnectionId — attempts to log in to the connection identified by the passed Connection ID.
  • LoginConnectIdBase — attempts the actual login.
  • LoginConnectIdDialog — pops up a database login dialog allowing the user to log in and store credentials.

Login Credentials and Encryption

When a connection is registered it may be passed login credentials (user name, password, and a trusted-connection flag). Normally this information is stored in the connections INI file; the password will be encrypted. Credentials are read and decrypted as part of LoadStoredConnections. Credentials are encrypted and written by StoreConnectionIdCredentials. Augmentable interfaces exist for encrypting/decrypting passwords and for reading/writing credentials to the connections INI file.

  • StoreConnectionIdCredentials — stores login credentials (user name, password, trusted-connection) in the connections INI file.
  • EncryptPassword — encrypts a password (accepts plain text, returns encrypted).
  • DecryptPassword — decrypts a password (accepts encrypted, returns plain text).
  • If pbEncryptPassword is True, EncryptPassword and DecryptPassword forward the message to a password encryption object.
  • LoadStoredConnections — reads the connections INI file.
  • StoreConnectionIdCredentials calls the OnWriteCredentials event to write credentials to the connections INI file.

Logging Out and Removing Connections

You can log out of any or all connections and remove any or all connections. This may be necessary if you want to remove a current set of connections and register/log in to a new set.

Hierarchy rules:

  • A connection must be registered before it can be logged into.
  • A connection must be logged into before a table can be opened.
  • When a connection is logged out, all open tables using that connection will be closed.
  • When a connection is removed, all connections are logged out (and therefore their tables are closed).

Interfaces:

  • UnRegisterAllConnections — removes all registered Connection IDs.
  • DeleteConnectionID — removes a registered connection for the passed ID parameter.
  • LogoutAllConnections — logs out of all connections.
  • LogoutConnectionId — logs out the specified Connection ID.

Changing Connections

Changing connections means changing an existing server connection while keeping the same Connection ID (the ID must remain the same). The connection server string (DSN or Server + Database) and credentials can change, but the back-end table definitions in the table INT file must remain identical across sources. It is your responsibility to ensure definitions match.

See Changing Connections for more information.


Managing Connection Information

Methods and events for managing connection information:

  • IsConnectionIdLoggedIn — tests if the passed Connection ID is logged in to the database server.
  • OnAddConnection — called right before a connection is registered.
  • ConnectionIniFile — returns the full path name of the Connections INI file.
  • AssembleConnectionString — helper that assembles a complete ODBC server string from components.
  • ConnectionIDs — returns the array of all registered Connection IDs.
  • ConnectionIdIndex — returns the index for the passed Connection ID in the internal array from ConnectionIDs.
  • ConnectionIdCLIHandler — returns a handle for the cCLIHandler object associated with the passed Connection ID.
  • ConnectionIdInfo — returns complete and up-to-date information for a registered connection.

Driver Management

Each managed connection has a driver. When a connection is added, its driver is loaded and registered as needed. Once a driver is loaded and registered it is never removed. Adding a connection will normally handle driver loading for you.

Interfaces for driver management:

  • RegisterDriver — loads and registers a managed driver.
  • OnDriverRegistered — called after a driver is registered.
  • DriverIndex — returns the index for a loaded driver.
  • DriverCLIHandler — returns a handle for the CLI object associated with the passed driver.
  • LoadedDrivers — returns a string array of all loaded drivers, both managed and unmanaged.
  • DriverServerNames — returns an array of logged-in servers for the passed driver.

Error Handling

cConnection has its own error handling and differentiates three kinds of errors:

  • User Errors — typically login errors; these are handled errors (no stack dump). See UserError.
  • Configuration Errors — issues like missing connections INI file, bad connection information, missing drivers, etc. Treated as a variation of a user error and handled to provide useful configuration information.
  • Programming Errors — errors due to misuse of the cConnection interface. These are unhandled and require code fixes.

Configuration Errors

Configuration errors occur when something is wrong with the setup (e.g., bad INI format, missing keywords, missing Connection ID, or missing/incorrect driver). These are typically installation/configuration issues rather than code errors.

When a configuration error occurs, the ConfigurationError message is sent.

Error Trapping

An interface is provided to trap errors by surrounding potentially failing code with trap start and end messages. After trapping ends you can check if an error occurred and handle it. Many class methods use this interface and it is available to developers.

Example:

// low level load which does not register the driver - only loads
{ Visibility=Private }
Function LoadDriver String sDriver Returns Boolean
    Integer iErrorNumber
    Send TrapErrors
    Load_Driver sDriver
    Send UnTrapErrors
    Get piErrorNumber to iErrorNumber
    Function_Return (iErrorNumber = 0)
End_Function

Interfaces:

  • TrapErrors — starts error trapping. Any error that occurs is sent to the cConnection object's Error_Report event.
  • UnTrapErrors — stops error trapping and restores the standard error handler. After UnTrapErrors you can test if an error occurred by checking if piErrorNumber is 0.
  • Error_Report — called when an error occurs with trapping enabled.
  • If an error occurs during trapping, piErrorNumber, piErrorLine, and psErrorText are set. This occurs inside Error_Report.

The cApplication Object, Opening Workspaces and Managing Connections

After the cApplication opens a workspace, it can auto-connect to managed connections. If the cConnection object exists (ghoConnection is non-zero), it will send AutoConnect to the connection object. If the connection object's pbAutoConnect property is True, an auto-connect will register all connections (RegisterAllConnections) and log in to all connections (LoginAll). If either process fails, the application will be halted.

This process is instigated within the cApplication DoOpenWorkspace method, which is the main interface used to open a workspace. DoOpenWorkspace is typically called when the cApplication object is created (either in OnCreate or by the object's end-constructor). When a workspace is automatically opened, managed connections can be automatically connected.

You can disable auto-connect by setting pbAutoConnect to False in the cConnection object. To customize auto-connect, augment the cConnection AutoConnect procedure or the cApplication OnWorkspaceOpened event.

Because the cApplication object sends messages to the cConnection object, the cConnection object must be created before or inside the cApplication object.


LoginEncryption.pkg

LoginEncryption.pkg creates an object used for login password encryption and decryption. It determines encryption rules and can be replaced with a custom package.

The cConnection property pbEncryptPassword determines whether a password encryption object is used. If True, an encryption object is required; if False, no encryption object is needed and the package may be omitted. If required but missing, an unhandled programming error will be raised.

The cLoginEncryption object must be created before a connection is added. If connections are created automatically by the cApplication object, the encryption object must be created before the cApplication object's End_Object. Placing it inside the cConnection object is recommended.


DatabaseLoginDialog.dg

DatabaseLoginDialog.dg defines the database login dialog that appears if stored login credentials are incomplete (i.e., when a silent login fails). This dialog is typically used once to configure and store credentials; afterwards it is seldom shown. If the dialog is not included, a password dialog will not appear and a failed database login will result in an application abort.

The property pbLoginDialogRequired determines whether a database login dialog is required. If True, a login dialog object is required; if False, the dialog will not be used and a failed silent login will simply fail. If required but missing, an unhandled programming error will be raised.


Extending the cConnection Class

The connection interface can be extended at the cConnection object level or class level. The cApplication object can also be extended to change how it works with managed connections.

Read extended information about Managed Connections.