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
cApplicationto simplify high-level coding
A more standard approach for dealing with SQL:
- Define a server/database connection
- Log in to the SQL server and database
- Open and access tables in that database
Basic cConnection Class Usage
At the simplest level, managed connections consist of:
- Create the Connections INI file (using the Studio's Manage Connections dialog)
- Configure your tables to use managed connections (using the Studio's Connection Wizard)
- Add a few lines of standard code to your application:
- Use the
cConnectionpackage - Create a
cConnectionobject and place it above or inside yourcApplicationobject - Add a login encryption object package and a database login dialog package inside or above the
cConnectionobject - Compile and run your application. The
cApplicationobject 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:
- Object
oConnection: The connection object should be placed inside of or before thecApplicationobject. TheoConnectionobject is optional. 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 thecApplicationobject'sEnd_Object. Placing it inside thecConnectionobject is recommended.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 thecApplicationobject'sEnd_Object. Placing it inside thecConnectionobject 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
pbEncryptPasswordisTrue,EncryptPasswordandDecryptPasswordforward the message to a password encryption object. LoadStoredConnections— reads the connections INI file.StoreConnectionIdCredentialscalls theOnWriteCredentialsevent 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 fromConnectionIDs.ConnectionIdCLIHandler— returns a handle for thecCLIHandlerobject 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
cConnectioninterface. 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 thecConnectionobject'sError_Reportevent.UnTrapErrors— stops error trapping and restores the standard error handler. AfterUnTrapErrorsyou can test if an error occurred by checking ifpiErrorNumberis 0.Error_Report— called when an error occurs with trapping enabled.- If an error occurs during trapping,
piErrorNumber,piErrorLine, andpsErrorTextare set. This occurs insideError_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.