Link to home
Start Free TrialLog in
Avatar of Dancindan84
Dancindan84Flag for Canada

asked on

C++ ODBC Again

Ok, now that the below is working, I'd like something one step better. :-) It would make my life a whole lot easier if the function was "void ODBCConnection(string statement)" and then statement was somehow converted into UCHAR szSqlStr[]; Is there a way to do that? Thanks again.


#include <windows.h>
#include <sqlext.h>
#include <stdio.h>
#include <iostream>

void ODBCConnection(UCHAR szSqlStr[])
{
    cout << szSqlStr;
    HENV    hEnv = NULL;  // Env Handle from SQLAllocEnv()
    HDBC    hDBC = NULL;  // Connection handle
    HSTMT   hStmt = NULL; // Statement handle
    UCHAR   szDSN[SQL_MAX_DSN_LENGTH] = "Employee";    // Data Source Name buffer
    UCHAR*  szUID = NULL;    // User ID buffer
    UCHAR*  szPasswd = NULL;    // Password buffer
    UCHAR   szModel[128];    // Model buffer
    SDWORD  cbModel; // Model buffer bytes recieved
    //UCHAR   szSqlStr [] = "SELECT * FROM Employee";    // SQL string
    RETCODE retcode; // Return code

    // Allocate memory for ODBC Environment handle
    SQLAllocEnv (&hEnv);

    // Allocate memory for the connection handle
    SQLAllocConnect (hEnv, &hDBC);

    // Connect to the data source "db97" using userid and password.
    retcode = SQLConnect (hDBC, szDSN, SQL_NTS, szUID, SQL_NTS, szPasswd, SQL_NTS);

    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
        {
                // Allocate memory for the statement handle
                retcode = SQLAllocStmt (hDBC, &hStmt);

                // Prepare the SQL statement by assigning it to the statement handle
                retcode = SQLPrepare (hStmt, szSqlStr, strlen ( (const char * ) szSqlStr ));

                // Execute the SQL statement handle
                retcode = SQLExecute (hStmt);

                // Project only column 2 which is the regions
                SQLBindCol (hStmt, 2, SQL_C_CHAR, szModel, sizeof(szModel), &cbModel);

                // Get row of data from the result set defined above in the statement
                retcode = SQLFetch (hStmt);

                while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
                    {
                    printf ("\t%s\n", szModel); // Print row (model)
                    retcode = SQLFetch (hStmt); // Fetch next row from result set
                    }

                    // Free the allocated statement handle
                    SQLFreeStmt (hStmt, SQL_DROP);

                    // Disconnect from datasource
                    SQLDisconnect (hDBC);
            }

            // Free the allocated connection handle
            SQLFreeConnect (hDBC);

            // Free the allocated ODBC environment handle
            SQLFreeEnv (hEnv);
            return;
}
Avatar of Dancindan84
Dancindan84
Flag of Canada image

ASKER

Essentially all of the classes done up already that I'd like to use this with revolve around "string", so I'm going to have to either convert them all to use UCHAR [] instead, or do a conversion somewhere. If I can do that conversion _once_ here, it will make things much simpler.
ASKER CERTIFIED SOLUTION
Avatar of Sys_Prog
Sys_Prog
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Basically when u say

UCHAR *ptr = ( UCHAR *)    str.c_str()

It stores the "starting address of the memory where the string in str is stored" in ptr

Thus, ptr also points to the same memory location as that of the string in str

Now, somehow, if str gets modifed, then ptr would again point to the same location (thus having new value OR may be some garbage because the STL string may allocate a new memory to store the new value if the value may be bigger)

The following code shows an example

int main(int argc, char* argv[])
{
      UCHAR *ptr ;
      string s = "Trial" ;
      ptr = (UCHAR * ) s.c_str () ;
      cout << endl << ptr ;
      
      s = "Hello" ;
    cout << endl << ptr ;
    system("pause");
      return 0;
}
 

Amit
Avatar of AlexFM
AlexFM

The best function prototype in your case is:

void ODBCConnection(const char* szSqlStr)
{
    cout << szSqlStr;
    ...

    retcode = SQLPrepare (hStmt, szSqlStr, strlen (szSqlStr ));
    ...
}

Caller may pass to this function [const] char*, unsigned char*, char[], unsigned char[], std::string or CString. If compiler doesn't like caller code, make casting there. std::string should be passed by the way described by Sys_Prog (c_str). CString has i's own const char* operator.
Declaration of ODBCConnection function by such way shows that function gets constant pointer to string, it doesn't change it. You may use also Windows alias for const char*:

void ODBCConnection(LPCSTR szSqlStr)

The following code shows how to cope up if your original string is going to be changed

int main(int argc, char* argv[])
{
      UCHAR *ptr ;
      string s = "Trial" ;
      
       ptr = new UCHAR [s.size ()+1] ;         // allocate sufficient memory
 
        strncpy ( (char * ) ptr, s.c_str(), s.size() ) ;           // Copy the data from string to the newly allocated memory
        ptr [s.size()+1] = '\0' ;                                         // Null terminate the string
      cout << endl << ptr ;
      
      s = "Hello" ;                   // Modify the original string version
    cout << endl << ptr ;          // The ptr version unaffected
    system("pause");
      return 0;
}


Amit
That first answer was exactly what I needed. The scope of the strings being sent is pretty narrow. Just built with the statements, sent and then go out of scope. Thanks again. Makes my life much easier.