List:Commits« Previous MessageNext Message »
From:pharvey Date:July 20 2006 11:59pm
Subject:Connector/ODBC 5 commit: r455 - trunk/examples/CPP/7/ADO
View as plain text  
Modified:
   trunk/examples/CPP/7/ADO/main.cpp
Log:
C++ ADO example now works on MS SQL Server and MySQL

Modified: trunk/examples/CPP/7/ADO/main.cpp
===================================================================
--- trunk/examples/CPP/7/ADO/main.cpp	2006-07-20 16:25:25 UTC (rev 454)
+++ trunk/examples/CPP/7/ADO/main.cpp	2006-07-20 23:59:17 UTC (rev 455)
@@ -1,3 +1,28 @@
+/*! 
+    \file       main.cpp
+    \author     Peter Harvey <pharvey@stripped>
+                Copyright MySQL AB 2004-2006 Released under GPL.
+    \version    Connector/ODBC v5
+    \date       2006
+    \brief      Demonstrates ADO in use via C++.
+
+                It is probably safe to say that ADO is seldom used via C++ while ADO is
often used by 
+                Visual Basic. The result is that it can sometimes be very difficult to
find information
+                on how to do some things with ADO in C++. For example; sending binary
'down the pipe'
+                via CreateParameter.
+
+                This file has been created in the hope that it may answer questions by
those wishing
+                to 'go down this path'.
+
+    \note       Before using this code you will want to;
+                - create the tbAdo table (see code comments later in this file)
+                - create the insAdo stored procedure (see code comments later in this
file)
+                - create a DSN (to tbAdo and insAdo)
+                - alter the connection information in the code below
+
+    \warning    Do not use this in a production environment or in any environment where
you may suffer
+                grief if things go horribly wrong. Use at your own risk.
+*/
 #include <oledb.h>
 #include <msdadc.h>
 #include <msdaguid.h>
@@ -22,54 +47,60 @@
 	no_namespace \
 	rename( "EOF", "EndOfFile") 
 
+// handle a HRESULT return type
 inline void TESTHR( HRESULT x ) { if FAILED(x) _com_issue_error(x); };
-IDataConvert *pDataConvert  = NULL;
+
+// global connect
 _ConnectionPtr pConnection  = NULL;
+char *pszConnectionString   = "ado2";
+char *pszUserID             = "root";
+char *pszPassword           = "pharvey";
 
-#define DB_MSSQL
+// sample data
+UCHAR   pData[]   = "12345678901234567890123456789012345678901234567890";  
+int     nDataLen  = 10; // data truncation errors if this is larger than strlen pData or
size of column
 
-#ifdef DB_MYSQL
-char *pszConnectionString   = "NorthwindMySQL";
-#elif defined( DB_ACCESS )
-char *pszConnectionString   = "NorthwindAccess";
-#elif defined( DB_MSSQL )
-char *pszConnectionString   = "Northwind";
-#endif
-char *pszUserID             = "root";
-char *pszPassword           = "mysql";
-
+/*!
+    \brief  Print the providers errors.
+*/
 void doPrintProviderError( _ConnectionPtr pConnection )
 {
-    // Print Provider Errors from Connection object.
-    // pErr is a record object in the Connection's Error collection.
     ErrorPtr  pErr = NULL;
 
-    if( (pConnection->Errors->Count) > 0)
+    // do we have errors?
+    if ( pConnection->Errors->Count > 0 )
     {
         long nCount = pConnection->Errors->Count;
 
-        // Collection ranges from 0 to nCount -1.
-        for(long i = 0; i < nCount; i++)
+        // for each error - print error
+        for ( long n = 0; n < nCount; n++ )
         {
-            pErr = pConnection->Errors->GetItem(i);
-            printf("Error number: %x\t%s\n", pErr->Number,
(LPCSTR)pErr->Description);
+            pErr = pConnection->Errors->GetItem( n );
+            printf( "Error #: %x\t%s\n", pErr->Number, (LPCSTR)pErr->Description );
         }
     }
 }
 
+/*!
+    \brief  Print COM error.
+*/
 void doPrintComError( _com_error &e )
 {
-    _bstr_t bstrSource(e.Source());
-    _bstr_t bstrDescription(e.Description());
+    _bstr_t bstrSource( e.Source() );
+    _bstr_t bstrDescription( e.Description() );
 
-    // Print Com errors.  
-    printf("Error\n");
-    printf("\tCode = %08lx\n", e.Error());
-    wprintf( L"\tCode meaning = %s\n", e.ErrorMessage());
-    printf("\tSource = %s\n", (LPCSTR) bstrSource);
-    printf("\tDescription = %s\n", (LPCSTR) bstrDescription);
+    printf( "Error\n" );
+    printf( "\tCode = %08lx\n", e.Error() );
+    wprintf( L"\tCode meaning = %s\n", e.ErrorMessage() );
+    printf( "\tSource = %s\n", (LPCSTR)bstrSource );
+    printf( "\tDescription = %s\n", (LPCSTR)bstrDescription );
 }
 
+/*!
+    \brief  Print record-set.
+
+            This prints all data in the record-set in a generic fashion.
+*/
 bool doPrintRecordset( _RecordsetPtr pRecordset )
 {
     /* field names */
@@ -91,6 +122,11 @@
     return true;
 }
 
+/*!
+    \brief  Connect.
+
+            This will connect to the data source.
+*/
 bool doConnect()
 {
     try
@@ -109,26 +145,22 @@
     return true;
 }
 
-bool doSelectBoundParameterChar()
+/*!
+    \brief  Print all data in tbAdo.
+*/
+bool doSelect()
 {
     _CommandPtr     pCommand            = NULL;
     _ParameterPtr   pParameter          = NULL;
     _RecordsetPtr   pRecordset          = NULL;  
-    VARIANT         variant;
 
     try
     {
         TESTHR( pCommand.CreateInstance( __uuidof( Command ) ) );
         pCommand->ActiveConnection = pConnection;
-        pCommand->CommandText = "SELECT * FROM orders WHERE CustomerID = ? ORDER BY
OrderID";
+        pCommand->CommandText = "SELECT * FROM tbAdo";
         pCommand->CommandType = adCmdText;
 
-        variant.vt      = VT_BSTR;
-        variant.bstrVal = _bstr_t( "WELLI" );
-
-        pParameter = pCommand->CreateParameter( _bstr_t( "CustomerID" ), adChar,
adParamInput, 6, variant );
-        pCommand->Parameters->Append( pParameter );
-
         pRecordset = pCommand->Execute( NULL, NULL, adCmdText ); 
 
         doPrintRecordset( pRecordset );
@@ -140,124 +172,93 @@
         return false;
     }
 
-    return true;
-}
 
-bool doSelectBoundParameterInteger()
-{
-    _CommandPtr     pCommand            = NULL;
-    _ParameterPtr   pParameter          = NULL;
-    _RecordsetPtr   pRecordset          = NULL;  
-    VARIANT         variant;
-
-    try
-    {
-        TESTHR( pCommand.CreateInstance( __uuidof( Command ) ) );
-        pCommand->ActiveConnection = pConnection;
-        pCommand->CommandText = "SELECT * FROM orders WHERE EmployeeID = ? ORDER BY
OrderID";
-        pCommand->CommandType = adCmdText;
-
-        variant.vt    = VT_I2;
-        variant.iVal  = 4;
-
-        pParameter = pCommand->CreateParameter( "EmployeeID", adInteger, adParamInput,
sizeof(int), variant );
-        pCommand->Parameters->Append( pParameter );
-
-        pRecordset = pCommand->Execute( NULL, NULL, adCmdText ); 
-
-        doPrintRecordset( pRecordset );
-    }
-    catch ( _com_error &e )
-    {
-        doPrintProviderError( pConnection );
-        doPrintComError( e );
-        return false;
-    }
-
-
     return true;
 }
 
-bool doSelect()
-{
-    _CommandPtr     pCommand            = NULL;
-    _ParameterPtr   pParameter          = NULL;
-    _RecordsetPtr   pRecordset          = NULL;  
+/*!
+    \brief  Use CreateParameter on an INSERT statement.
 
-    try
-    {
-        TESTHR( pCommand.CreateInstance( __uuidof( Command ) ) );
-        pCommand->ActiveConnection = pConnection;
-        pCommand->CommandText = "SELECT * FROM categories";
-        pCommand->CommandType = adCmdText;
+            This will show CreateParameter in use on an INSERT statement
+            with a variety of column data types.
 
-        pRecordset = pCommand->Execute( NULL, NULL, adCmdText ); 
+    \note   Needs the following table to work...
 
-        doPrintRecordset( pRecordset );
-    }
-    catch ( _com_error &e )
-    {
-        doPrintProviderError( pConnection );
-        doPrintComError( e );
-        return false;
-    }
+            MSSQL
+            -----
+            CREATE TABLE `tbAdo` 
+            (
+              `bin` BINARY(50),
+              `txt` TEXT,
+              `n` INTEGER,
+              `vc` VARCHAR(50)
+            )
 
-
-    return true;
-}
-
-bool doInsertBoundParameterBinary()
+            MySQL
+            -----
+            CREATE TABLE `tbAdo` 
+            (
+              `bin` BINARY(50),
+              `txt` TEXT,
+              `n` INTEGER UNSIGNED,
+              `vc` VARCHAR(50)
+            )
+            ENGINE = InnoDB;
+*/
+bool doCreateParameterInsert()
 {
     _CommandPtr     pCommand            = NULL;
     _ParameterPtr   pParameter          = NULL;
-#ifndef DB_MSSQL
     VARIANT         variant1;
-#endif
-    VARIANT         variant2;
     VARIANT         variant3;
     VARIANT         variant4;
-    const char *    pBinary = "binary data here";
 
+    SAFEARRAY FAR * pArray;
+    SAFEARRAYBOUND  arrayBound[1];
+
+    arrayBound[0].lLbound    = 0;
+    arrayBound[0].cElements  = nDataLen;
+
     try
     {
+        // our INSERT statement
         TESTHR( pCommand.CreateInstance( __uuidof( Command ) ) );
         pCommand->ActiveConnection = pConnection;
-#ifdef DB_MSSQL
-        pCommand->CommandText = "INSERT INTO categories VALUES( ?, ?, ? )";
-#else
-        pCommand->CommandText = "INSERT INTO categories VALUES( ?, ?, ?, ? )";
-#endif
+        pCommand->CommandText = "INSERT INTO tbAdo VALUES( ?, ?, ?, ? )";
         pCommand->CommandType = adCmdText;
 
-#ifndef DB_MSSQL
-        variant1.vt    = VT_I2;
-        variant1.iVal  = 1867;
-        pParameter = pCommand->CreateParameter( "CategoryID", adInteger, adParamInput,
sizeof(int), variant1 );
+        // BINARY
+        pArray = SafeArrayCreate( VT_UI1, 1, arrayBound );
+        for ( long n = 0; n < nDataLen; n++ )
+        {
+            SafeArrayPutElement( pArray, &n, &(pData[n]) );
+        }
+
+        variant1.vt     = VT_ARRAY|VT_UI1;
+        variant1.parray = pArray;
+        pParameter      = pCommand->CreateParameter( "bin", adBinary, adParamInput,
nDataLen, variant1 );
         pCommand->Parameters->Append( pParameter );
-#endif
 
-        variant2.vt      = VT_BSTR;
-        variant2.bstrVal = _bstr_t( "Eighteen sixty seven" );
-        pParameter = pCommand->CreateParameter( "CategoryName", adChar, adParamInput,
20, variant2 );
+        // TEXT (we use same data as BINARY - because we can)
+        pParameter      = pCommand->CreateParameter( "txt", adChar, adParamInput,
nDataLen, variant1 );
         pCommand->Parameters->Append( pParameter );
 
-        variant3.vt      = VT_BSTR;
-        variant3.bstrVal = _bstr_t( "a fine year" );
-        pParameter = pCommand->CreateParameter( "Description", adChar, adParamInput,
11, variant3 );
+        // INTEGER
+        variant3.vt    = VT_I2;
+        variant3.iVal  = 1867;
+        pParameter = pCommand->CreateParameter( "n", adInteger, adParamInput,
sizeof(int), variant3 );
         pCommand->Parameters->Append( pParameter );
 
-        variant4.vt     = VT_BLOB;
-        variant4.pbVal  = (BYTE*)pBinary;
-//        variant4.vt      = VT_BSTR;
-//        variant4.bstrVal = _bstr_t( pBinary );
-        pParameter = pCommand->CreateParameter( "Picture", adLongVarBinary,
adParamInput, 17 + 1, variant4 );
+        // VARCHAR
+        variant4.vt      = VT_BSTR;
+        variant4.bstrVal = _bstr_t( "test" );
+        pParameter = pCommand->CreateParameter( "vc", adChar, adParamInput, 5,
variant4 );
         pCommand->Parameters->Append( pParameter );
 
-//        pParameter->AppendChunk( variant4 );
-
+        // execute statement
         pCommand->Execute( NULL, NULL, adCmdText ); 
 
-        
+//        SafeArrayDestroy( variant4 );
 
     }
     catch ( _com_error &e )
@@ -271,44 +272,78 @@
     return true;
 }
 
-bool doInsertBoundParameterBinary2()
+/*!
+    \brief  Use CreateParameter on a stored procedure.
+
+            This shows CreateParameter in use on a stored procedure with a variety of 
+            column data types.
+
+    \note   This needs the following stored procedure to work...
+
+            MSSQL
+            ------
+            CREATE PROCEDURE insAdo @bin BINARY(50), @txt TEXT, @n INT, @vc VARCHAR(50)
AS
+        	    INSERT INTO tbAdo VALUES( @bin, @txt, @n, @vc )
+
+            MySQL
+            -----
+            CREATE PROCEDURE `northwind`.`insAdo` ( IN bin BINARY(50), IN txt TEXT, IN n
INT, IN vc VARCHAR(50) )
+            BEGIN
+                 INSERT INTO tbAdo VALUES( @bin, @txt, @n, @vc );
+            END
+
+*/
+bool doCreateParameterProcedure()
 {
     _CommandPtr     pCommand            = NULL;
     _ParameterPtr   pParameter          = NULL;
-    VARIANT         variant2;
+    VARIANT         variant1;
+    VARIANT         variant3;
     VARIANT         variant4;
 
     SAFEARRAY FAR * pArray;
-    SAFEARRAYBOUND arrayBound[1];
+    SAFEARRAYBOUND  arrayBound[1];
+
     arrayBound[0].lLbound    = 0;
-    arrayBound[0].cElements  = 7;
+    arrayBound[0].cElements  = nDataLen;
 
-    UCHAR pBinary[] = "binary";
-
     try
     {
+        // our stored procedure statement
         TESTHR( pCommand.CreateInstance( __uuidof( Command ) ) );
         pCommand->ActiveConnection = pConnection;
-        pCommand->CommandText = "insCategories";
+        pCommand->CommandText = "insAdo";
         pCommand->CommandType = adCmdStoredProc;
 
-        variant2.vt      = VT_BSTR;
-        variant2.bstrVal = _bstr_t( "Eighteen sixty seven" );
-        pParameter = pCommand->CreateParameter( "@vcName", adChar, adParamInput, 20,
variant2 );
-        pCommand->Parameters->Append( pParameter );
-
+        // BINARY
         pArray = SafeArrayCreate( VT_UI1, 1, arrayBound );
-        for ( long n = 0; n < variant4.parray->rgsabound->cElements; n++ )
+        for ( long n = 0; n < nDataLen; n++ )
         {
-            SafeArrayPutElement( pArray, &n, &(pBinary[n]) );
+            SafeArrayPutElement( pArray, &n, &(pData[n]) );
         }
 
-        variant4.vt     = VT_ARRAY|VT_UI1;
-        variant4.parray = pArray;
+        variant1.vt     = VT_ARRAY|VT_UI1;
+        variant1.parray = pArray;
+        pParameter      = pCommand->CreateParameter( "bin", adBinary, adParamInput,
nDataLen, variant1 );
+        pCommand->Parameters->Append( pParameter );
 
-        pParameter = pCommand->CreateParameter( "@binPicture", adBinary, adParamInput,
variant4.parray->rgsabound->cElements, variant4 );
+        // TEXT (we use same data as BINARY - because we can)
+        pParameter      = pCommand->CreateParameter( "txt", adChar, adParamInput,
nDataLen, variant1 );
         pCommand->Parameters->Append( pParameter );
 
+        // INTEGER
+        variant3.vt    = VT_I2;
+        variant3.iVal  = 1867;
+        pParameter = pCommand->CreateParameter( "n", adInteger, adParamInput,
sizeof(int), variant3 );
+        pCommand->Parameters->Append( pParameter );
+
+        // VARCHAR
+        variant4.vt      = VT_BSTR;
+        variant4.bstrVal = _bstr_t( "test" );
+        pParameter = pCommand->CreateParameter( "vc", adChar, adParamInput, 5,
variant4 );
+        pCommand->Parameters->Append( pParameter );
+
+        // execute statement
         pCommand->Execute( NULL, NULL, adCmdStoredProc ); 
 
 //        SafeArrayDestroy( variant4 );
@@ -324,6 +359,12 @@
     return true;
 }
 
+
+/*!
+    \brief  Disconnect.
+
+            This will disconnect from the data source.
+*/
 bool doDisconnect()
 {
     try
@@ -345,6 +386,8 @@
     \brief  main
 
             This is the 'main' entry point to this program - it all starts here.
+
+    \todo   We need to do a better job of cleaning up after our processing.
 */
 void main()
 {
@@ -357,11 +400,10 @@
     /* do it */
     if ( doConnect() )
     {
-//        doSelectBoundParameterChar();
-//        doSelectBoundParameterInteger();
-//        doSelect();
-        doInsertBoundParameterBinary2();
-//        doSelect();
+        doSelect();
+        doCreateParameterInsert();
+        doCreateParameterProcedure();
+        doSelect();
         doDisconnect();
     }
 

Thread
Connector/ODBC 5 commit: r455 - trunk/examples/CPP/7/ADOpharvey21 Jul