I'm trying to create a new record in an empty recordset. Each time I try to
call AddNew I get an error.
I'm using VC 6.0 with the ADO C++ Extensions.
The error I get is: 0x80040E21
This translates to: Errors Occurred
(Duh! The guy that came up with that one
should be given an award....)
To test this functionality, I was using one of Microsoft's examples
verbatum. (i.e. if you enter their code as it is written in their help file
and point it at an empty table in a database then the code fails!!!)
The code section I started with is the 'AddNew' example given in MS's MDAK
2.5 Visual C++ examples. The only change I made was to point it to my SQL
Server database. The example works if you use a populated database table,
but
fails on an empty database table. I've tracked it down to learn enough to
know
that if the recordset is empty (i.e. the Open command returns no rows from a
table with rows, or the opened table is empty) then the AddNew command
fails.
Rob Kerr
Digital Sandbox
The full extent of the code gets a bit long, but here it is (ignore the
file:// junk):
#import "C:\Program Files\Common Files\System\ADO\msado15.dll" \
no_namespace rename("EOF", "EndOfFile")
#include <ole2.h>
#include <stdio.h>
#include "conio.h"
#include "AddNewX.h"
/* File declaration */
inline void TESTHR(HRESULT x) {if FAILED(x) _com_issue_error(x);};
void AddNewX(void);
void PrintProviderError(_ConnectionPtr pConnection);
///////////////////////////////////////////////////////////
// //
// Main Function //
// //
///////////////////////////////////////////////////////////
void main()
{
if(FAILED(::CoInitialize(NULL)))
return;
AddNewX();
::CoUninitialize();
Quote:
}
///////////////////////////////////////////////////////////
// //
// AddNewX Function //
// //
///////////////////////////////////////////////////////////
void AddNewX(void)
{
// Define ADO object pointers.
// Initialize pointers on define.
_RecordsetPtr pRstEmployees = NULL;
_ConnectionPtr pConnection = NULL;
/* Define Other variables
IADORecordBinding *picRs = NULL; /* Interface Pointer declared. */
CEmployeeRs emprs; /* C++ class object */
HRESULT hr = S_OK;
_bstr_t strCnn("Provider=sqloledb;Data Source=(local); Initial
Catalog=spdbpro;User Id=sa;Password=;");
_bstr_t strId;
_bstr_t strMessage;
try
{
/* Open a connection */
TESTHR(pConnection.CreateInstance(__uuidof(Connection)));
hr = pConnection->Open(strCnn,"","",NULL);
/* Open employee table. */
TESTHR(pRstEmployees.CreateInstance(__uuidof(Recordset)));
/* You have to explicitly pass the Cursor type and LockType */
/* to the Recordset here. */
pRstEmployees->Open("employee",
_variant_t((IDispatch *) pConnection,true),
adOpenKeyset,adLockOptimistic,adCmdTable);
/* Open an IADORecordBinding interface pointer which we'll use */
/* for Binding Recordset to a class. */
TESTHR(pRstEmployees->QueryInterface(
__uuidof(IADORecordBinding),(LPVOID*)&picRs));
/* Bind the Recordset to a C++ Class here */
TESTHR(picRs->BindToRecordset(&emprs));
// Get data from the user.The employee id must be formatted as
// first,middle and last initial,five numbers,then M or F to
// signify the gender.For example,the employee id for
// Bill A. Sorensen would be "BAS55555M".
printf("Enter Employee Id: ");scanf("%s",emprs.m_sz_empid);
strId = emprs.m_sz_empid;
printf("Enter First Name: ");scanf("%s",emprs.m_sz_fname);
printf("Enter Last Name:");scanf("%s",emprs.m_sz_lname);
/* Proceed if the user actually entered something */
/* for the id, the first and the last name. */
if(strcmp(emprs.m_sz_empid,"") &&
strcmp(emprs.m_sz_fname,"") &&
strcmp(emprs.m_sz_lname,""))
{
/* This adds a new record to the table */
/* if (FAILED(hr = picRs->AddNew(&emprs))) */
/* _com_issue_error(hr); */
TESTHR(picRs->AddNew(&emprs));
/* Show the newly added data */
printf("New Record: %s %s %s \n",
emprs.lemp_empidStatus == adFldOK ?
emprs.m_sz_empid : "<NULL>",
emprs.lemp_fnameStatus == adFldOK ?
emprs.m_sz_fname : "<NULL>",
emprs.lemp_lnameStatus == adFldOK ?
emprs.m_sz_lname : "<NULL>");
}
else
printf("Please enter an employee id, first name "
"and last name.\n");
/* Delete the new record because this is a demonstration. */
pConnection->Execute("DELETE FROM EMPLOYEE WHERE emp_id ="
"'" + strId + "'",NULL,adCmdText);
/* Release the IADORecordset Interface here */
if (picRs)
picRs->Release();
// Clean up objects before exit.
pRstEmployees->Close();
pConnection->Close();
}
catch(_com_error &e)
{
// Notify the user of errors if any.
_variant_t vtConnect = pRstEmployees->GetActiveConnection();
// GetActiveConnection returns connect string if connection
// is not open, else returns Connection object.
switch(vtConnect.vt)
{
case VT_BSTR:
printf("Error:\n");
printf("Code = %08lx\n", e.Error());
printf("Message = %s\n", e.ErrorMessage());
printf("Source = %s\n", (LPCSTR) e.Source());
printf("Description = %s\n", (LPCSTR) e.Description());
break;
case VT_DISPATCH:
PrintProviderError(vtConnect);
break;
default:
printf("Errors occured.");
break;
}
}
Quote:
}
///////////////////////////////////////////////////////////
// //
// PrintProviderError Function //
// //
///////////////////////////////////////////////////////////
void PrintProviderError(_ConnectionPtr pConnection)
{
// Print Provider Errors from Connection object.
// pErr is a record object in the Connection's Error collection.
ErrorPtr pErr = NULL;
long nCount = 0;
long i = 0;
if( (pConnection->Errors->Count) > 0)
{
nCount = pConnection->Errors->Count;
// Collection ranges from 0 to nCount -1.
for(i = 0; i < nCount; i++)
{
pErr = pConnection->Errors->GetItem(i);
printf("\n\t Error number: %x\t%s",
pErr->Number, (LPCSTR)pErr->Description);
}
}
Quote:
}
AddNewX.h:
#include "icrsint.h"
/* This Class extracts empid, fname and lastname */
class CEmployeeRs : public CADORecordBinding
{
BEGIN_ADO_BINDING(CEmployeeRs)
/* Column empid is the 1st field in the recordset */
ADO_VARIABLE_LENGTH_ENTRY2(1, adVarChar, m_sz_empid,
sizeof(m_sz_empid), lemp_empidStatus, TRUE)
ADO_VARIABLE_LENGTH_ENTRY2(2, adVarChar, m_sz_fname,
sizeof(m_sz_fname), lemp_fnameStatus, TRUE)
ADO_VARIABLE_LENGTH_ENTRY2(4, adVarChar, m_sz_lname,
sizeof(m_sz_lname), lemp_lnameStatus, TRUE)
END_ADO_BINDING()
public:
CHAR m_sz_empid[10];
ULONG lemp_empidStatus;
CHAR m_sz_fname[40];
ULONG lemp_fnameStatus;
CHAR m_sz_lname[41];
ULONG lemp_lnameStatus;
Quote:
};