AddNew on an empty Recordset fails in MS C++ AddNew Example 
Author Message
 AddNew on an empty Recordset fails in MS C++ AddNew Example

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:
};



Tue, 24 Sep 2002 03:00:00 GMT  
 AddNew on an empty Recordset fails in MS C++ AddNew Example
Hello Robert,

Here are my two cents:  the MS ADO wrapper classes suck.....!  In particular I
hate how they bind variables to the recordset -- I'm always changing my
database designs, and tend to avoid ordinal mapping for fear it will break when
I change the database.

I've got a wrapper class with an AddNew() example on my website at
www.ADOPro.com.  Download the library and compile the sample....if you have any
problems let me know & I'll try to help you through them....

Paul



Wed, 02 Oct 2002 03:00:00 GMT  
 
 [ 2 post ] 

 Relevant Pages 

1. Problems with AddNew on an empty recordset.

2. ODBC: tricky AddNew in an empty Recordset ??

3. IADORecordBinding.AddNew() fails on empty table

4. Can't AddNew to an empty table with RecordBinding in ADO2.5

5. DAO recordset AddNew and Update

6. AddNew() in Recordset problem, please help!

7. RecordSet::AddNew() Problem

8. Recordset AddNew()

9. AddNew() in Recordset problem, please help!

10. DAO multiple Addnew's requires closing and reopening of Recordset

11. Why Recordset can't AddNew()

12. DAO AddNew Recordset SQL Server not equal Access attached tables

 

 
Powered by phpBB® Forum Software