Click here to Skip to main content
Click here to Skip to main content

OpenClient++: C++ wrapper for Sybase Open Client library

, 21 Nov 2004 MPL
Rate this:
Please Sign up or sign in to vote.
OpenClient++ is a thread safe, cross platform C++ wrapper for Sybase Open Client API.

Introduction

Sybase Open Client is the interface (API) between client applications and Sybase database server. In fact, it allows client applications to communicate to any database server which supports Tabular Data Stream (TDS) protocol. Currently, Microsoft SQL server and Sybase database server support TDS protocol. Open Client API can be thought of having two components.

  1. Programming Interface component implemented in C programming language which allows a user to build applications to communicate to Server. It contains Client-Library, DB-Library and CS-Library.
    • DB-Library, a collection of routines for use in writing client applications. DB-Library includes a bulk copy library and the two-phase commit special library.
    • Client-Library, a collection of routines for use in writing client applications. Client-Library is a new library, designed to accommodate cursors and other advanced features in the SYBASE 10.0 product line.
    • CS-Library, a collection of utility routines that are useful to both client and server applications. All Client-Library applications will include at least one call to CS-Library, because Client-Library routines use a structure which is allocated in CS-Library.
  2. Open Client Network services includes network library which provides support for specific network protocols such as TCP/IP or DCENet. For more information, see www.sybase.com.

Tabular Data Stream protocol was developed by Sybase to provide client-server communication between Sybase client and Server. You can get protocol specifications from Sybase or see www.freetds.org.

OpenClient++

I wanted to learn the Open Client library to access Sybase ASE server (12_5) from my client application. The best way I found was to implement C++ wrapper which can provide thread safe, cross platform interface similar to MySQL++ or other database library. Current version of OpenClient++ library provides following features using Client-Library (CT_LIB and CS_LIB routines):

  • C++ API
  • Thread Safe access
  • Cross platform (Windows and Linux)
  • Error Handling: it provides error handling using C++ Exception handling as well as traditional way where return values of function call is checked. Exception handling can be enabled/disabled at library level or individual class level.
  • Following SQL commands are supported:
    1. SELECT
    2. UPDATE
    3. DELETE
    4. INSERT
    5. COMPUTE: SUM, COUNT, MIN, MAX, AVG
  • Good documentation generated using DOxygen.

Interface Design:

Following classes are implemented to develop this library.

  1. Context:
    • Context: It is a singleton class which provides the instance of itself. It stores CS_CONTEXT structure and provides thread safe access context of client-library. It provides methods to set the debug level, enabled/disable exception handling, and call back function settings for error handling.
    • ContextException: It is an exception class for Context class. It is derives from the standard "Exception" class.
  2. Connection:
    • Connection: It’s a wrapper class for CS_CONNECTION structure. It stores connection parameters and establishes connection with server.
    • ConnectException: It is an exception class for Connection class. It is derived from the standard "Exception" class.
  3. Command:
    • Command: It’s a wrapper class for CS_COMMAND structure. It stores the SQL command string and type of command. It also builds and executes the commands using ct_command() and ct_send() functions of Client-Library.
    • CommandException: It is an exception class for Command class. It is derived from the standard "Exception" class.
  4. Query:
    • Query: It executes the command string, processes the result received from the server, and stores it into a RecordSet.
    • QueryException: It is an exception class for Query class. It is derived from the standard "Exception" class.
  5. Record Set:
    • Record: It’s a wrapper class for COLUMN_DATA structure. It stores information about columns and its value.
    • RecordSet: It stores the Record class objects, number of row updates, query success/failure, transaction ID and command ID.
  6. Utility classes:
    • Mutex: It provides the synchronized access to Context class object. It is implemented in two different header files.
      1. Mutex.h: Mutex class implementation for Linux.
      2. MutexWin.h: Mutex class implementation for Windows.
    • template<class T> Lock: It provides the guard lock functionality for Mutex class which avoids indefinite mutex locking in error condition.

Here is the diagram showing relationship among the classes:

Class Digram

Usage:

The simple usage of this library involves the following steps:

  • Set up the environment variables: get the instance of Context class which is a singleton class and set the environment variables like debug level, exception handling and error display. It provides the default call back functions to display the errors on the terminal. You can write your own custom call back functions and set it to context.
  • Connect to the server: connection class provides multiple constructor and connect() methods to pass connection information.
  • Create a Query Object: Connection class provides the method GetQuery() which creates the Query object by setting this as member variable.
  • Send a Command: Query object provides the method Execute() to send a command to the Server, it processes the result received from the server, stores into RecordSet, and returns the RecordSet object.
  • Result Processing: RecordSet object provides GetRecordsCount() method which returns total number of Records available. It provides GetRecord(index) method to retrieve the Record class object using which you can retrieve field name and value.
int main()
{
    try {
        // Get the context instance
        Context* pInstance = Context::GetInstance();
        std::cout << "Initialized the Context" << std::endl;
        
    }catch(ContextException &e) {
        std::cout << e.what() << std::endl;
        return -1;
    }
    try {
        // Set the debug level to all
        pInstance->SetDebugLevel(CS_DBG_ALL);
        // Set the call back handles for CS, CT and SRV libs
        pInstance->SetCallbackHandler(Context::CS_LIB,csmsg_callback);
        pInstance->SetCallbackHandler(Context::CT_LIB,ctmsg_callback);
        pInstance->SetCallbackHandler(Context::SRV_LIB, servermsg_callback);
    }catch(ContextException &e) {
        std::cout << e.what() << std::endl;
    }
    
    // Initialize the connection object
    Connection oConn("TestDB", "username", "password", "servername");
    try {
        // connect to server
        oConn.Connect();
    }catch (ConnectionException &e) {
        std::cout << e.what() << std::endl;
        return -1;
    }
    
    // Get the instance of Query class
    Query q = oConn.GetQuery();
    
    try {
        char sCommandBuff[256] = "";
        string sCmd;
        // execute the command untill userinput is "q"
        while(sCmd != "q") {
            std::cout << ">";
            std::cin.getline(sCommandBuff, 256);
            string sCmd = sCommandBuff;
            if(sCmd == "q")
                break;
            
            // Execute the query
            RecordSet &result = q.Execute(sCmd);
            if(result.IsSuccess()) {
                for(int i =0; i < result.GetRecordsCount(); i++) {
                    // Get the record
                    Record *pRecord = result.GetRecord(i);
                    if(!pRecord)
                      continue;
                    for(int j =0 ; j < pRecord->GetFieldsCount(); j++) {
                        std::cout << "Column:"
                                  << result.GetFieldName(j) 
                                  << "    Value:" 
                                  << pRecord->GetFieldValue(j) 
                                  << std::endl;
                    }
                 }
                 
                 std::cout << result.GetMessage()<< std::endl;
                 std::cout << "Result:"<<(bool)result
                            << " NumRows:" << result.GetRowsRead() 
                            << " CmdNum:" << result.GetCommandId()
                            << "Transaction Id:" 
                            << result.GetTransState() << std::endl;
             }else {
                 // print failure condition
                 std::cout << result.GetMessage() << std::endl;
                 std::cout << "Result:"<<(bool)result
                            << " NumRows:" << result.GetRowsRead() 
                            << " CmdNum:" << result.GetCommandId()
                            << "Transaction Id:" 
                            << result.GetTransState() << std::endl;
             }
                    
        } // while end
     
     }catch (QueryException &e) {
         std::cout << e.what() << std::endl;
    }
      return 0;
}

References:

Your comments, suggestions and rating for this article are appreciated.

License

This article, along with any associated source code and files, is licensed under The Mozilla Public License 1.1 (MPL 1.1)

Share

About the Author

Rohit Joshi
Software Developer
United States United States
Rohit Joshi is a software engineer working for a telecom company in USA. He has development expirience using C, C++ ,C#, VoiceXML, ASR, IMAP, LDAP, HTTP, SIP, H323 on unix/linux and platforms.

Comments and Discussions

 
QuestionUnix makefile Pinmemberrameshmelam31-Aug-08 20:05 
AnswerRe: Unix makefile PinmemberRohit Joshi5-Sep-08 14:26 
GeneralRe: Unix makefile Pinmemberrameshmelam14-Sep-08 12:50 
GeneralRe: Unix makefile PinmemberHL HL2-Dec-11 22:43 
QuestionHow can I find the open client version PinmemberMember 321339531-Jul-08 11:03 
AnswerRe: How can I find the open client version PinmemberRohit Joshi5-Sep-08 14:27 
QuestionWhat type of license is applicable on this. Pinmemberrmerchant22-Jul-08 15:42 
AnswerRe: What type of license is applicable on this. PinmemberRohit Joshi23-Jul-08 3:11 
QuestionDo I need the libct.dll to use this wrapper? PinmemberAnneZ25-Sep-07 10:23 
AnswerRe: Do I need the libct.dll to use this wrapper? PinmemberRohit Joshi26-Sep-07 5:46 
AnswerRe: Do I need the libct.dll to use this wrapper? PinmemberRohit Joshi26-Sep-07 5:47 
GeneralRe: Do I need the libct.dll to use this wrapper? PinmemberAnneZ26-Sep-07 6:02 
GeneralRe: Do I need the libct.dll to use this wrapper? PinmemberRohit Joshi27-Sep-07 9:44 
GeneralRe: Do I need the libct.dll to use this wrapper? Pinmembermindplaytm25-Oct-07 10:37 
GeneralRe: Do I need the libct.dll to use this wrapper? Pinmemberttttnht19-Jun-08 7:05 
QuestionCould you send me a project? Pinmemberhubei_121820-Jul-07 19:22 
Generala problem Pinmemberhubei_121820-Jul-07 19:17 
GeneralMemory leak PinmemberLukasz Kurylo18-Apr-07 0:51 
GeneralRe: Memory leak PinmemberRohit Joshi18-Apr-07 4:30 
GeneralRe: Memory leak Pinmemberdave_dave19-Mar-12 23:28 
GeneralQuestion about wrapper Pinmembervasjos15-Nov-05 9:26 
GeneralMore methods Pinmemberelecoest29-Apr-05 2:52 
GeneralAnything like this in C# PinmemberPink Floyd7-Apr-05 8:54 
GeneralRe: Anything like this in C# PinmemberRohit Joshi14-Apr-05 14:03 
Questionthreadsafe? Pinmemberanybody anyone16-Mar-05 5:28 
AnswerRe: threadsafe? PinsussAnonymous16-Mar-05 15:14 
AnswerRe: threadsafe? PinmemberRohit Joshi16-Mar-05 15:21 
GeneralSupport for cursor PinsussAnonymous21-Nov-04 9:48 
GeneralRe: Support for cursor PinmemberRohit Joshi21-Nov-04 10:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141220.1 | Last Updated 21 Nov 2004
Article Copyright 2004 by Rohit Joshi
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid