MS ADO General Questions

Hello!

I've been getting into database interaction recently, and thought I'd try my hand at using ADO and C++ to talk to MS SQL Server '08. Until now I've been using pyodbc and Python 3.3, so this is a bit of a jump for me.

My questions are:

- As far as connection strings go, is this correct?

1
2
3
_bstr_t sequelserver = ("Server=" + servername + ";Database=" + dbname + ";Trusted_Connection=yes;").c_str();
CnnPtr->Provider = "SQLNCLI10";
CnnPtr->Open(sequelserver, "", "", adConnectUnspecified);


Everything I've seen seems to use the "Data Source" keywords instead of "Server", but it looks like that's for older versions of SQL Server. It runs alright, so I'm assuming the connection is being made, but I haven't executed any queries yet, so I can't be sure that it's working properly.

- Which brings me to my second question, how in the world do you run simple queries with this library? I've been looking at the http://msdn.microsoft.com/en-us/library/windows/desktop/ms677554(v=vs.85).aspx sample code, but it looks like a jumbled mess. I guess not being used to C++ is probably part of the issue though.

From what I can gather, in order to execute simple queries, you need a connection pointer object, a recordset pointer object, and a command pointer object.

So I created these 3 and then wrote this:

1
2
3
4
5
CmdPtr = NULL;
AdvQuery = AdQry.c_str(); // regular sql query
CmdPtr->CommandType = adCmdText;
CmdPtr->CommandText = AdvQuery;
RecPtr = CmdPtr->Execute(NULL, NULL, adCmdText);


Will this work? Do I just display the contents of the recordset then? The example code used requery to set the contents of the recordset....

All help greatly appreciated per usual!
I just dug up an ancient Ado program I had and recompiled and rerun it and it still works. I used Win 7 64 bit but compiled as x86. Its a console mode program and it connects to an old Microsoft Access DB Microsoft used to provide with its Visual Studio products and likely still does. Anyway, you'll need to change the hardcoded paths I used. It shows how to execute queries though and the debug output writes a small recordset to the console. Here's the code...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//kernel32.lib ole32.lib oleaut32.lib uuid.lib
#include <oleauto.h>
#include <stdio.h>
#include "adoint.h"

const CLSID CLSID_Connection  = {0x00000514,0x0000,0x0010,{0x80,0x00,0x00,0xAA,0x00,0x6D,0x2E,0xA4}};
const CLSID CLSID_Recordset   = {0x00000535,0x0000,0x0010,{0x80,0x00,0x00,0xAA,0x00,0x6D,0x2E,0xA4}};
const IID   IID_IConnection   = {0x00000550,0x0000,0x0010,{0x80,0x00,0x00,0xAA,0x00,0x6D,0x2E,0xA4}};
const IID   IID_Recordset     = {0x00000556,0x0000,0x0010,{0x80,0x00,0x00,0xAA,0x00,0x6D,0x2E,0xA4}};

int main()
{
 wchar_t szConnection[]=L"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\Program Files (x86)\\Microsoft Visual Studio\\VB98\\Biblio.mdb";
 //wchar_t szConnection[]=L"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\Program Files\\Microsoft Visual Studio\\VB98\\Biblio.mdb";
 _ADOConnection* pConnection=NULL;
 _ADORecordset* pRecordset=NULL;
 BSTR strConnection=NULL;
 ADOFields* pFields=NULL;
 ADOField* pField1=NULL;
 ADOField* pField2=NULL;
 BSTR strTable=NULL;
 LONG lngState=0;
 HRESULT hr;

 hr=CoInitialize(NULL);
 if(SUCCEEDED(hr))
 {
    hr=CoCreateInstance(CLSID_Connection,NULL,CLSCTX_INPROC_SERVER,IID_IConnection,(void**)&pConnection);
    if(SUCCEEDED(hr))
    {
       printf("CoCreateInstance(pConnection) Succeeded!\t pConnection = %u\n",(unsigned)pConnection);
       strConnection=SysAllocString(szConnection);
       if(strConnection)
       {
          wprintf(L"strConnection = %s\n",strConnection);
          hr=pConnection->put_ConnectionString(strConnection);
          if(SUCCEEDED(hr))
          {
             hr=pConnection->Open(strConnection,NULL,NULL,0);
             if(SUCCEEDED(hr))
             {
                printf("pConnection->Open() Succeeded!\n");
                hr=pConnection->get_State(&lngState);
                if(SUCCEEDED(hr))
                {
                   hr=CoCreateInstance(CLSID_Recordset,NULL,CLSCTX_INPROC_SERVER,IID_Recordset,(void**)&pRecordset);
                   if(SUCCEEDED(hr))
                   {
                      printf("CoCreateInstance(pRecordset) Succeeded\tpRecordset = %u\n",(unsigned)pRecordset);
                      hr=pRecordset->put_CursorLocation(adUseClient);
                      if(SUCCEEDED(hr))
                      {
                         VARIANT vSource;
                         VariantInit(&vSource);
                         strTable=SysAllocString(L"Authors");
                         if(strTable)
                         {
                            printf("strTable Successfully Allocated!\n");
                            vSource.bstrVal=strTable;
                            vSource.vt=VT_BSTR;
                            VARIANT vConnection;
                            VariantInit(&vConnection);
                            vConnection.punkVal=pConnection;
                            vConnection.vt=VT_UNKNOWN;
                            hr=pRecordset->Open(vSource,vConnection,adOpenKeyset,adLockOptimistic,0);
                            if(SUCCEEDED(hr))
                            {
                               printf("pRecordset->Open(vSource) Succeeded!\n");
                               hr=pRecordset->get_Fields(&pFields);
                               if(SUCCEEDED(hr))
                               {
                                  printf("pRecordset->get_Fields(&pFields) Succeeded!\n");
                                  long lngRecCt=0;
                                  pRecordset->get_RecordCount(&lngRecCt);
                                  printf("lngRecCt = %d\n\n",(int)lngRecCt);
                                  VARIANT vIndex;
                                  VariantInit(&vIndex);
                                  for(unsigned int i=1; i<=10; i++)
                                  {
                                      vIndex.lVal=0, vIndex.vt=VT_I4;
                                      hr=pFields->get_Item(vIndex,&pField1);
                                      if(SUCCEEDED(hr))
                                      {
                                         VARIANT vValue;
                                         VariantInit(&vValue), vValue.vt=VT_EMPTY;
                                         hr=pField1->get_Value(&vValue);
                                         long lValue=vValue.lVal;
                                         printf("%d\t",(int)lValue);
                                      }
                                      vIndex.lVal=1, vIndex.vt=VT_I4;
                                      hr=pFields->get_Item(vIndex,&pField2);
                                      if(SUCCEEDED(hr))
                                      {
                                         VARIANT vValue;
                                         VariantInit(&vValue), vValue.vt=VT_EMPTY;
                                         hr=pField2->get_Value(&vValue);
                                         if(vValue.vt==VT_BSTR)
                                         {
                                            wprintf(L"%s\n",vValue.bstrVal);
                                            SysFreeString(vValue.bstrVal);
                                         }
                                      }
                                      pRecordset->MoveNext();
                                  }
                                  pFields->Release();
                               }
                               pRecordset->Close();
                            }
                            SysFreeString(strTable);
                         }
                      }
                      pRecordset->Release();
                   }
                }
                pConnection->Close();
             }
          }
          SysFreeString(strConnection);
       }
       pConnection->Release();
    }
    CoUninitialize();
 }
 getchar();

 return 0;
}

/*
_ADOConnection* pConnection=NULL;
_ADORecordset* pRecordset=NULL;
ADOFields* pFields=NULL;
ADOField* pField1=NULL;
ADOField* pField2=NULL;
*/

/*
CoCreateInstance(pConnection) Succeeded!         pConnection = 34980264
strConnection = Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program Files (x86)\Microsoft Visual Studio\VB98\Biblio.mdb
strConnOut = Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program Files (x86)\Microsoft Visual Studio\VB98\Biblio.mdb
pConnection->Open() Succeeded!
adStateOpen = 1
CoCreateInstance(pRecordset) Succeeded  pRecordset = 46344992
strTable Successfully Allocated!
pRecordset->Open(vSource) Succeeded!
pRecordset->get_Fields(&pFields) Succeeded!
lngRecCt = 6246

1       Jacobs, Russell
2       Metzger, Philip W.
3       Boddie, John
4       Sydow, Dan Parks
6       Lloyd, John
8       Thiel, James R.
10      Ingham, Kenneth
12      Wellin, Paul
13      Kamin, Sam
14      Gaylord, Richard
*/
Note that the include "AdiInt.h" refers to a standard Microsoft include. Its actually an auto-generated include generated by the MIDL compiler running on AdoInt.idl I'd suspect.
Here are two connection strings that have worked for me using ODBC and SQL Server ...

1
2
szCnOut = DRIVER=SQL Server;SERVER=NRFORSILW53\SQLEXPRESS;UID=;Trusted_Connection=Yes;WSID=NRFORSILW53;DATABASE=SaleData
szCnOut = DRIVER=SQL Server;SERVER=nrforbofsqls02;UID=SaleAdmin;Trusted_Connection=No;PWD=SaleAdmin%01;DATABASE=SaleData


Over the years I've experimented a lot with ADO, mostly because COM interests me. However, in all my production work I use ODBC. I wrote my own class to encapsulate some of the nastiness of ODBC away, so its not that hard for me.
Last edited on
I had toyed with the idea of writing my own wrapper class for using ODBC, kind of like nanodbc but decided it would ultimately be easier on me when I needed more complex functions to just use ADO. At least, I'm hoping so anyway, my only concern being the potential performance loss, but that's not so big of a deal. Thank you for the sample code! It looks like my connection string should be good to go!
Topic archived. No new replies allowed.