SQL Statements Not Executing

Pages: 123
Incidentally, connecting to a database poses no problems if your folder path has spaces in it. So far, the only problem I've encountered with spaces in the folder path is with creating a database.

So for my purposes, this won't be an issue, as I plan to distribute my databases with my main app so that all I will have to do is connect to them, never create them, albeit creating them is good to know.
One other thing for those of you who are having typecast problems...

If you rename your .cpp file to plain .c this will generally solve all your typecast problems related to this SQL matter and the MS examples, and such like, at least in MS VS 2008, 2010.
Last edited on
Thank you. It's a shame there is more information on MS Access and C++. This took a lot of digging and hard work!!!!! Thank you Freddie1 and Lamblion.
Actually, I am the one who is indebted to both of you. I added virtually nothing to the matter except my errors! -:)

So my thanks to BOTH of you, as well as the poster who pointed me to MS example!
Say Lamblion, if you are still following this thread - which we really, really hijacked from poor struggling DSTR3A, did you finally resolve that date issue you mentioned? You said, I think, that it was working for you but the dates were coming out mangled or something? If there is a problem I'd like to try to fix it. That example is something I started working on a long time ago (Win 95 times, I think) when I was struggling to figure out ODBC myself, so I kind of want to keep it current.

I'll say this about the date issue. When I first wrote that code I was using this struct from
SqlTypes.h

1
2
3
4
5
6
7
8
9
#ifndef	__SQLDATE
#define	__SQLDATE
/* transfer types for DATE, TIME, TIMESTAMP */
typedef struct tagDATE_STRUCT
{
        SQLSMALLINT    year;
        SQLUSMALLINT   month;
        SQLUSMALLINT   day;
} DATE_STRUCT;


Several years later I started working with SQL Server and I discovered that my date stuff wasn't working at all. So there went quite a few hours as I remember trying to savy the meaning of the rather cryptic error codes I was getting from SQLGetDiagRecord(). Eventually I found I could get the dates into and out of SQL Server by using this struct...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef struct tagTIMESTAMP_STRUCT
{
        SQLSMALLINT    year;
        SQLUSMALLINT   month;
        SQLUSMALLINT   day;
        SQLUSMALLINT   hour;
        SQLUSMALLINT   minute;
        SQLUSMALLINT   second;
        SQLUINTEGER    fraction;
} TIMESTAMP_STRUCT;

#if (ODBCVER >= 0x0300)
typedef TIMESTAMP_STRUCT	SQL_TIMESTAMP_STRUCT;
#endif  /* ODBCVER >= 0x0300 */ 


The added benifit of using TIMESTAMP_STRUCT was that this one worked with both MS Access and SQL Server, so it was a no brainer to just adopt that for both.

I believe the example code I posted was using these latest types, and if its not working in Access 2010 I'd like to get to the bottom of the problem. At work we're not using Access 2010 yet, but time seems to have a way of going on, you know.
Last edited on
freddie1: I'm still following the thread, but I never even tried to fix the dates, as that wasn't really important to me. I'll go back through it later and see if I can determine what is causing the error, but I am just happy to be able to access the DB now.

In fact, I've already incorporated the basics of the ODBC/SQL into my Win32 program, but all I know how to do thus far is access the records and put the text in edit/combo/list boxes, but I don't yet know how to move forward/backward in a record, and so on, but I suspect the SQL API link that I posted earlier will have all of those commands.
The way I learned ODBC was through my 'find' of it on the MSDN CD I got with either Visual Studio 5 or 6. I believe its likely the online version of that you are referring to above. This was the path to it on the CD....


MSDN Library Visual Studio 6.0\Platform SDK\Database And Messaging Services\Microsoft Data bAccess SDK\Microsoft Open Database Connectivity (ODBC)


So that shows at least how Microsoft catagorizes it.

Also, I had found and bought an old textbook on it from Amazon.com. It was so old it prtained to 16 bit ODBC for Windows 3.0 or 3.1 or something, but nonetheless there was a lot of useful concepts in it.

You guys are doing a lot better than I did; it took me months to figure it out enough to get data into and out of databases with any sense of certainty that it would work.

I went through three stages in my learning of it. The first stage was just getting it to work at all. During that stage my code looked a lot like what DSTRA3A posted. I was having all the connection code right in my main procedures with code to extract records, insert records, etc. I was declaring piles of un-needed variables just like what DSTR3A is doing now, etc. It was pretty ugly stuff, but I was just glad to get it to work.

As an aside, it was during that stage of my learning in the late 90s that I discovered I could use the ODBC Api with PowerBASIC too. That was a tremendously stunning achievement for me, and I can still remember holding my breath after translating the ODBC declares from C over to PowerBASIC, running them and praying to God a SQL_SUCCESS return code would show up on the console after executing the program. It was in that time frame too that Microsoft was coming out with .NET and its abandonment of Visual Basic 6 looked like an inevitable outcome. For you see, I had started out my database work with Visual Basic 4 and I had written many large database type applications using a technology known as DAO, i.e., 'Data Access Objects'. I still fondly remember those days. DAO was awesome, truely awesome. I'm actually still maintaining some of those apps where I work. Anyway, I couldn't hack .NET and was casting about for another programming language at the time. I was thinking of adopting C, because I always dabbled in C, but I didn't know enough C or PowerBASIC either, for that matter, to create the extremely rich user interfaces with database access, grids, complex ActiveX components, so on and so forth, that I could easily create with Visual Basic. But when I got ODBC working in C and PowerBASIC, I'd at least put a pretty big chink in the edifice of things I previously couldn't do in C or PowerBASIC. Also, while Microsoft had all its wizards and crap in C++ to fairly easily provide those things to C++ coders, on a philosophical level I could never bring myself to resort to any of that stuff. I like to write all my own code and understand every subtle nuance of every line of code.

Anyway, in stage #2 of my learning process I decided this whole ugly ODBC coding thing could be cleaned up quite a bit by developing sensible wrapper functions and attempting to modularize the various processes of connecting to the database, doing i/o, and closing and releasing resources. It was during that stage that I created structs in C and Types in PowerBASIC to hold the various connection handles, and I create connection and disconnect functions that allowed me to simply do something like ...

ODBCConnect(Sql);
if(Sql.blnConnected==TRUE)
(
//do stuff
)
else
printf("Connection Failure Smuck!\n");

Modularization is a powerful concept in cleaning up code, and at that point I really began to 'roll' with ODBC. I was starting to get good at it and I liked it.

Stage #3 of my learning of it was to recognize that C++ was a better way to go than C and I ought to just make an ODBC class out of my various ODBC related structs and global functions whose only use was to work on those structs. That really is the whole concept of classes and why C++ and OOP is in many ways 'cooler' than C. So I did that in both C++ and PowerBASIC and I'm pretty happy with the way it turned out. You know, in a lot of ways ADO - ActiveX Data Objects, is also a very good way to go. I believe Andy Weskin recommended that to you early on. ADO was a successor to DAO but I never used it a real lot, although I have used it some in both PowerBASIC and Visual Basic. I'll say its one
heck of a lot easier to use it in PowerBASIC than in C++ though. But in any case I've stuck with ODBC I guess because of all the work I put into figuring it out, and the recollection of how good it felt to tackle such a difficult subject and finally get it working. Also, it goes along
with my philosophy of creating small, fast apps. I don't need any external Dlls to use it, but that's true of ADO also. In many ways ADO is a logical technology for me to adopt because I'm big time into COM (ADO is COM based), but I guess the other considerations have overridden that for me, and I've stuck with ODBC for database accees work.
Last edited on
The reason we're learning faster is because we have you to show us the way; otherwise it would be almost hopeless.

Does this link gve me what I need to learn how to move forward/backward, etc???

http://msdn.microsoft.com/en-us/library/aa198053(v=SQL.80).aspx
I can't figure out why the date isn't working. I have tried increasing the buffer size from 8 to 12, etc., but I can't figure it out.

Also, your program is creating TWO databases, i.e., "TestData.mdb" and "TestData.laccdb"

Notice the "l" preceding the "accdb" in the above, even though I've checked and there is no ".laccdb" anywhere in the code.

I want to emphasize, even though we're on this issue, is the above link I posted good enough for me to figure out how to advance through records?

Anyway, here is the out put from your code --

1
2
3
4
5
6
7
8
9
10
11
12
13
Sql.strDBQ = C:\Programming\VS_2008\Win_Console\database02\Debug\TestData.mdb
Sql.blnConnected        = True
Sql.szCnOut             = DBQ=C:\Programming\VS_2008\Win_Console\database02\Debu
g\TestData.mdb;Driver={Microsoft Access Driver (*.mdb, *.accdb)};DriverId=25;FIL
=MS Access;MaxBufferSize=2048;PageTimeout=5;
Sql.strConnectionString = DRIVER=Microsoft Access Driver (*.mdb, *.accdb);DBQ=C:
\Programming\VS_2008\Win_Console\database02\Debug\TestData.mdb;
blnMakeTable() Succeeded!
                                                         SQLExecute(hStmt)
iId      Double           Date           String           0=SQL_SUCCESS
========================================================================
  sql.dr.szErrCode = ╠╠╠╠╠╠╠╠╠╠☺
  sql.dr.szErrMsg  =

Wow! I don't believe I know as much as I should Lamblion! It appears to me my program is working really, really badly on your system, and I'd dearly love to figure out why. My guess is the program is actually crashing. The reason I say that is that 'l' you are seeing is likely a locking database file. Access does that to help itself understand that a connection is open to the database and a user is using it (the user would be my program). After a user successfully closes the file the database driver deletes that locking file. If that locking file remains it means something has rather badly errored out and crashed and the database connection is hanging open.

If you would, could you post the exact code you are running? I know I've posted several versions, and I'd like to start off on the same exact page you are on.

Also, can you open the database file without the 'l'? If so, what is in it? Did the table1 get successfully created? If so, were the four records correctly written into the table?

That's where I'd really have to start to try to get to the bottom of the problem.

In terms of your question about moving backwards and forewards through the recordset, I'd really rather get to the bottom of my program's difficulties before tackling that, but since you are interested in that topic, I'll try to address it briefly.

First off, that's complicated. All database drivers are different, and if my memory serves me correctly, the Microsoft Access Driver only supports foreward only cursors, i.e., recordsets. Maybe someone with more or better knowledge than I can correct me on that if they know better, as its been some time since I looked into it. But if I'm right on that point, what that means is that once you select multiple rows of data with a SELECT SQL statement, you will be positioned on the 1st row of data, and can only move foreward through the data one row at a time through SQLFetch() statements until you reach the end of your data. I suspect you might be disappointed to hear that, but its really not all that bad, at least in my opinion. Let me explain why.

In applications serving as front ends to databases, the graphical user interface provided usually has grids on it and such that display database data. In that case the logical thing to do is populate the grid with all the data from some database table, query, or view that the user selected based on whatever the program does or whatever. Therefore, the 'design pattern' usually followed in such a scenario is to open the database in the message handling procedure, select all the rows of data necessary from the database, write it into the grid where the underlying functionality of the grid will allocate memory for it at the start or as its being written in, close the cursor and database, then exit the message handling function.

Let me explain why such a design pattern is best. First, in multi-user situations in a client-server model you may have many clients connected across a network to a centralized database. If piles of clients are all maintaining open connections to the database it overloads the network. In the case of Microsoft Access, its really only safe to maintain a few open connections at a time. The best thing to do is open and close the connection immediately as you get your data out. This likely will only take milliseconds.

One of the problems Visual Basic had back in the 90s was that it provided grid ActiveX controls that were know as 'bound' controls, i.e., they maintained a constantly open connection to the underlying database. It clogged networds up pretty bad. In IT terminology, the design didn't 'scale' well.

So really, the design pattern to follow in my opinion is to locally 'cache' the data in the client after one of these fast retrieval operation of which I just spoke. By 'cache' I mean read it into arrays, dynamically allocated memory with pointers, or, perhaps best, just what I described with grids. The grid will automatically allocate and maintain the memory, and the database connection can be closed. This is known in the vernacular as a 'disconnected recordset'.

While it certainly helps the network load situation, it raises other issues for the client application and the coder of that application, i.e., YOU.

Is the data editable by the user, or is it only for display purposes? If only for display purposes your done. Your job was easy!

However, if the data is editable (like in a grid control) and your intention is to reconcile any changes the user makes with the undertlying database, then you are in deep s***! You are then going to have to track in some way what the user did to the data and somehow write those changes back to the underlying database.

There is a lot to it.

To determine if a database driver supports multi-directional cursors I believe you use the SQLGetInfo function. Look it up at MSDN. I printed the whole function documentation out years ago and stuck it in a binder somewhere. I forget how big the documentation on it is - it filled the binder. 50 pages? A 100? I forget. Actually, years ago I printed out the whole ODBC documentation. Its enough to kill a good horse.
Okay, I figured out how to go to each record by incrementing/deincrementing the row count, so that's not a big deal.

As to your other question, NO I cannot access the "l" database with Access 2010, even when I rename it to plain "accdb", so it's obviously corrupt. I CAN however access the .mdb database with Access 2010.

Here is the entire code of main.cpp (next post) --

I have to break it up into sections because the board is telling me the text lenght is too long --
Last edited on
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
#include <windows.h>
#include <stdio.h>
#include <odbcinst.h>
#include <sql.h>
#include <sqlext.h>
#include "MySql.h"

//#pragma warning (default, 1, disable)

unsigned int iInstallerError()
{
 DWORD pErr;
 char szErrMsg[512];
 WORD  cbMsgBuffer=512;
 WORD  cbRet;
 WORD  wErrNum=1;

 while(SQLInstallerError(wErrNum,&pErr,szErrMsg,cbMsgBuffer,&cbRet)!=SQL_NO_DATA)
 {
  printf("wErrNum    = %d\t",wErrNum);
  printf("szErrMsg = %s\n",szErrMsg);
  wErrNum++;
 };

 return (unsigned int)pErr;
}
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
unsigned int iCreateDB(char const* szDBName)    //To create a Microsoft Access Database from
{                                               //scratch, you use SQLConfigDataSource().  I
 char szCreate[256];                            //believe if the database already exists at the
                                                //specific location SQLInstallerError() returns
 strcpy_s(szCreate,sizeof(szCreate),"CREATE_DB=");                 //'11'.
 strcat_s(szCreate,sizeof(szCreate),szDBName);
 if(SQLConfigDataSource(0,ODBC_ADD_DSN,"Microsoft Access Driver (*.mdb, *.accdb)",szCreate))
    return TRUE;
 else
    return iInstallerError();
}

int GetRecordCount(SQL& Sql)
{
 unsigned int iRecCt=0;
 char szQuery[128];
 SQLHSTMT hStmt;
 long iJnk;

 strcpy_s(szQuery,sizeof(szQuery),"SELECT Count(*)  As RecordCount From Table1;");
 SQLAllocHandle(SQL_HANDLE_STMT,Sql.hConn,&hStmt);
 SQLBindCol(hStmt,1,SQL_C_ULONG,&iRecCt,0,&iJnk);
 if(SQLExecDirect(hStmt,(SQLCHAR*)szQuery,SQL_NTS)!=SQL_SUCCESS)
 {
    SQLGetDiagRec(SQL_HANDLE_STMT,hStmt,1,Sql.szErrCode,&Sql.iNativeErrPtr,Sql.szErrMsg,512,&Sql.iTextLenPtr);
    SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
    return -1;
 }
 else
 {
    SQLFetch(hStmt);
    SQLCloseCursor(hStmt);
    SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
    return iRecCt;
 }
}
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
TIMESTAMP_STRUCT ParseDate(char* szDate, char* szFormat, char* szDelimiter)
{
 UINT i=0,j=0,k=0;
 TIMESTAMP_STRUCT ts;
 char buf[8][24];             //buf[0] for month, buf[1] for day, buf[2] for year
 char* p;

 memset(buf,0,sizeof(buf));  //zero out buf[]
 p=szDate;
 for(i=0;i<strlen((char*)szDate);i++)
 {
     if(*p!=*szDelimiter)
     {
        buf[j][k++]=*p;
        buf[j][k+1]='\0';
     }
     else
     {
        j++;
        k=0;
     }
     p++;
 }
 if(!_stricmp((char*)szFormat,"MDY"))
 {
    ts.month=(short)atoi(buf[0]);
    ts.day=(short)atoi(buf[1]);
    ts.year=(short)atoi(buf[2]);
 }
 if(!_stricmp((char*)szFormat,"DMY"))
 {
    ts.day=(short)atoi(buf[0]);
    ts.month=(short)atoi(buf[1]);
    ts.year=(short)atoi(buf[2]);
 }
 if(!_stricmp((char*)szFormat,"YMD"))
 {
    ts.year=(short)atoi(buf[0]);
    ts.month=(short)atoi(buf[1]);
    ts.day=(short)atoi(buf[2]);
 }

 return ts;
}


void MkDate(TIMESTAMP_STRUCT& ts, char* szBuffer)
{
 char szMonth[4],szDay[4],szYear[8];

 sprintf_s(szMonth,"%u",ts.month);
 sprintf_s(szDay,"%u",ts.day);
 sprintf_s(szYear,"%u",ts.year);
 strcpy_s(szBuffer,sizeof(szBuffer),szMonth);
 strcat_s(szBuffer,sizeof(szBuffer),"/");
 strcat_s(szBuffer,sizeof(szBuffer),szDay);
 strcat_s(szBuffer,sizeof(szBuffer),"/");
 strcat_s(szBuffer,sizeof(szBuffer),szYear);

 return;
}


UINT blnMakeTable(SQL& Sql)          //Uses SQL Create Table statement to add table
{                                    //to database represented by sql->hConn
 char szQuery[256];
 SQLHSTMT hStmt;

 strcpy_s(szQuery,sizeof(szQuery),"CREATE TABLE Table1 (Id LONG  NOT NULL PRIMARY KEY, Float_Point DOUBLE, Date_Field DATETIME, Text_Field CHAR(30));");
 SQLAllocHandle(SQL_HANDLE_STMT,Sql.hConn,&hStmt);
 if(SQLExecDirect(hStmt,(SQLTCHAR*)szQuery,SQL_NTS)==0)
 {
    SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
    return(TRUE);
 }
 else
    return(FALSE);
}


UINT blnInsert(SQL& sql)
{
 char* szStr[]={(char*)"My Birthday",(char*)"Walk On Moon?",(char*)"Some String",(char*)"April Fools Day"};
 char* szDate[]={(char*)"11/15/1952",(char*)"6/30/1969",(char*)"1/1/2006",(char*)"4/1/2006"};
 double dblNum[]={3.14159,1.23456,15.1234,0.54321};
 char  szQuery[100],szString[32],szBuffer[128];       //Let me give you a hint about something.  If you decide
 SQLINTEGER iNts=SQL_NTS;                             //to use raw ODBC as your database access methodology, the
 UINT i,id,iRet=FALSE;                                //hard part is SQLBindParameter() for inserting prepared
 TIMESTAMP_STRUCT ts;                                 //SQL statements, and SQLBindCol() for selecting data.  These
 SQLINTEGER iJnk;                                     //will inevitably take you some time to learn.  I chose an
 SQLHSTMT hStmt;                                      //integer, a double, a data, and a char string so as to get
 double dbl;                                          //you started on the most common data types.

 if(SQLAllocHandle(SQL_HANDLE_STMT,sql.hConn,&hStmt)==SQL_SUCCESS)
 {
    strcpy_s((char*)szQuery,sizeof(szQuery),"INSERT INTO Table1(Id, Float_Point, Date_Field, Text_Field) VALUES(?,?,?,?);");
    printf("                                                         SQLExecute(hStmt)\n");
    printf("iId      Double           Date           String           0=SQL_SUCCESS\n");
    printf("========================================================================\n");
    if(SQLPrepare(hStmt,(SQLTCHAR*)szQuery,SQL_NTS)==SQL_SUCCESS)
    {
       SQLBindParameter(hStmt,1,SQL_PARAM_INPUT,SQL_C_LONG,SQL_INTEGER,0,0,&id,0,&iJnk);
       SQLBindParameter(hStmt,2,SQL_PARAM_INPUT,SQL_C_DOUBLE,SQL_DOUBLE,0,0,&dbl,0,&iJnk);
       SQLBindParameter(hStmt,3,SQL_PARAM_INPUT,SQL_C_TYPE_DATE,SQL_TYPE_TIMESTAMP,16,0,&ts,0,&iJnk);
       SQLBindParameter(hStmt,4,SQL_PARAM_INPUT,SQL_C_TCHAR,SQL_CHAR,31,0,szString,32,&iNts);
       for(i=0;i<4;i++)
       {
           id=i+1, dbl=dblNum[i];
           ts=ParseDate(szDate[i],(char*)"mdy",(char*)"/");
           strcpy_s(szString,sizeof(szString),szStr[i]);
           if(SQLExecute(hStmt)==SQL_SUCCESS)
           {
              memset(szBuffer,0,128);
              printf("%-6u%8.2f           %-12.10s  %-20s%6u\n",id,dbl,szDate[i],szString,SQL_SUCCESS);
           }
           else
           {
              SQLGetDiagRec(SQL_HANDLE_STMT,hStmt,1,sql.szErrCode,&sql.iNativeErrPtr,sql.szErrMsg,512,&sql.iTextLenPtr);
              printf("  sql.dr.szErrCode = %s\n",sql.szErrCode);
              printf("  sql.dr.szErrMsg  = %s\n",sql.szErrMsg);
              SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
              return FALSE;
           }
       }
       iRet=TRUE;
       printf("\n");
    }
    SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
 }

 return iRet;
}

UINT blnDumpData(SQL& sql)
{
 char szQuery[100],szBuffer[128],szDate[12];
 SQLTCHAR szString[20];
 TIMESTAMP_STRUCT ts;
 SQLINTEGER iJnk;
 SQLHSTMT hStmt;
 double dblNum;
 UINT iId;

 if(SQLAllocHandle(SQL_HANDLE_STMT,sql.hConn,&hStmt)==SQL_SUCCESS)
 {
    strcpy_s(szQuery,sizeof(szQuery),"SELECT Table1.Id,Table1.Float_Point,Table1.Date_Field,Table1.Text_Field FROM Table1;");
    SQLBindCol(hStmt,1,SQL_C_ULONG,&iId,0,&iJnk);
    SQLBindCol(hStmt,2,SQL_C_DOUBLE,&dblNum,0,&iJnk);
    SQLBindCol(hStmt,3,SQL_C_TYPE_DATE,&ts,0,&iJnk);
    SQLBindCol(hStmt,4,SQL_C_TCHAR,szString,20,&iJnk);
    if(SQLExecDirect(hStmt,(SQLTCHAR*)szQuery,SQL_NTS)==SQL_SUCCESS)
    {
       printf("iId      Double           Date           String           0=SQL_SUCCESS\n");
       printf("========================================================================\n");
       do
       {
          if(SQLFetch(hStmt)==SQL_NO_DATA)
             break;
          memset(szBuffer,0,128);
          MkDate(ts,szDate);
          printf("%-6u%8.2f           %-12.10s  %-20s%6u\n",iId,dblNum,szDate,szString,SQL_SUCCESS);
       }  while(TRUE);
    }
    SQLCloseCursor(hStmt);
    SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
    return TRUE;
 }

 return FALSE;
}


int main()
{

 char szBuffer[512];
 std::string s1;
 SQL Sql;

 Sql.strDriver="Microsoft Access Driver (*.mdb, *.accdb)";
 GetCurrentDirectory(512,szBuffer);
 s1=szBuffer;
 Sql.strDBQ=s1+"\\"+"TestData.mdb";
 printf("Sql.strDBQ = %s\n",Sql.strDBQ.c_str());
 if(iCreateDB(Sql.strDBQ.c_str())==TRUE)
 {
    Sql.ODBCConnect();
    if(Sql.blnConnected==TRUE)
    {
       printf("Sql.blnConnected        = True\n");
       printf("Sql.szCnOut             = %s\n",Sql.szCnOut);
       printf("Sql.strConnectionString = %s\n",Sql.strConnectionString.c_str());
       if(blnMakeTable(Sql))
       {
          printf("blnMakeTable() Succeeded!\n");
          if(blnInsert(Sql))
          {
             printf("blnInsert() Succeeded!\n");
             unsigned int iCount=GetRecordCount(Sql);
             printf("iCount = %u\n\n",iCount);
             blnDumpData(Sql);
          }
       }
       Sql.ODBCDisconnect();
    }
    else
    {
        printf("Sql.blnConnected  = %d\n",Sql.blnConnected);
        printf("Sql.iNativeErrPtr = %ld\n",(SQLINTEGER)Sql.iNativeErrPtr);
        printf("Sql.szErrCode     = %s\n",Sql.szErrCode);
        printf("Sql.szErrMsg      = %s\n",Sql.szErrMsg);
    }
 }
 else
 {
    printf("Sql.blnConnected  = %d\n",Sql.blnConnected);
    printf("iCreateDB() Failed, i.e., we couldn't create the Access Database.  Nicht Gut!\n");
 }
 getchar();

 return 0;
}
Last edited on
When you open TestData.mdb, what is in it? Is table1 there? That corrupted output says it successfully create the table. Is it there? If it is there, can you open the table? If you can open it, are the four records in it? I really need to know at what exact point the failure is occurring. My guess based on what you posted is that the table1 table was successfully created, but there was a total failure to insert any data. In otherv words, my guess is the point of failure is blnInsert().


Okay, I figured out how to go to each record by incrementing/deincrementing the row count, so that's not a big deal.


I don't understand what you mean by that. In some ways its difficult to communicate like this. I don't know what you mean by row count. As far as I know (as I described above), there is no such thing as a row count. When you select a bunch of rows from a table with a SELECT statement you end up with a 'cursor'. Its positioned at the 1st record. The variables you bound to the cursor with SQLBindCol will contain the values of the database fields in that first row you are positioned on. You at that point can use the variables in your code or ignore them at your discretion. However, in terms of that cursor you can only do one thing with it, and that is call SQLFetch() to move to the next record. There is no 'row count' from which you can say to the cursor, 'OK row count, I now want to see row #10' - at which point the omnipotent 'row count' object moves you to row #10. Then you say, 'OK row count, cursor, whatever, Take me back to row #5!. If you have been able to do that then I assure you it isn't I who am teaching you, bit rather you need to be teaching me!
Thanks for posting the code back Lamblion. I know its a pain. I wish they allowed somewhat larger posts in one post.
To your second question, I used the MSDN example and incremented their variable rowCount on each pass, like this --

1
2
3
4
5
while (SQL_SUCCEEDED(rc))
{
     do stuff...
     rowCount++;
}


then I just fetch the appropriate record with whatever my index var==rowCount. IOW, I have a global variable called rowQuoteCnt, and when I click on a certain button I apply a number to that. If rowCount==rowQuoteCnt, then I display that record using the fetch routine.

To your first question, yes, Access 2010 opens TestData.mdb, but NOT TestData.laccdb or the renamed TestData.accdb.

TestData.mdb contains these fields in Access 2010 --

1. ID
2. Float_Point
3. Date_Field
4. Text_Field

It contains no records, however, but I don't think it's supposed to.
I just discovered something else...

When I open TestData.mdb with Access 2010, it AUTOMATICALLY deletes TestData.laccdb.

This leads me to believe that the ONLY reason that TestData.laccdb is created is because there are no records in TestData.mdb.

I suspect that putting at least one record in there would stop TestData.laccdb from being created.
Unfortunately, we're not communicating too well Lamblion. Its probably my fault. In any case, this is what the output should look like from that program...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Sql.strDBQ = C:\Code\CodeBlks\MkAccessDB\TestData.mdb
Sql.blnConnected        = True
Sql.szCnOut             = DBQ=C:\Code\CodeBlks\MkAccessDB\TestData.mdb;Driver={Microsoft Access Driver (*.mdb, *.accdb)};DriverId=25;FIL=MS Access;MaxBufferSize=2048;PageTimeout=5;
Sql.strConnectionString = DRIVER=Microsoft Access Driver (*.mdb, *.accdb);DBQ=C:\Code\CodeBlks\MkAccessDB\TestData.mdb;
blnMakeTable() Succeeded!
                                                         SQLExecute(hStmt)
iId      Double           Date           String           0=SQL_SUCCESS
========================================================================
1         3.14           11/15/1952    My Birthday              0
2         1.23           6/30/1969     Walk On Moon?            0
3        15.12           1/1/2006      Some String              0
4         0.54           4/1/2006      April Fools Day          0

blnInsert() Succeeded!
iCount = 4

iId      Double           Date           String           0=SQL_SUCCESS
========================================================================
1         3.14           11/15/1952    My Birthday              0
2         1.23           6/30/1969     Walk On Moon?            0
3        15.12           1/1/2006      Some String              0
4         0.54           4/1/2006      April Fools Day          0


I have come to a conclusion though. I'm convinced at this point that I'll not be able to make further progress on this problem until I can acquire a setup exactly like yours so I can research this problem. I'm not sure how I'm going to do that. I'll have to give that some thought. But that's my problem - not yours.

In terms of your further progress at ODBC I think you should rely on the documentation rather than anything of mine because the future for you is Access 2010 and beyond, and it appears to me that rather than even fooling with code I ought to study the release notes and other documentation from Microsoft so as to learn what they've changed with Access 2010 in terms of how it affects ODBC.

I'm quite certain some very significant changes have occurred as a result of playing with the code you just copied for me (it won't run, by the way).

Getting back to that 'l' file - all that is is a text file. I haven't opened one in ages, but if I recall, all that's in it is the computer name possibly with network path of the client presently using the database. It isn't a 2nd copy of the database by any means.
I believe the laccdb is a lock file for the database.
Pages: 123