Mike Fulton
Mike Fulton

Reputation: 918

Determining if field is NULL

I'm working on an MFC app which does database access using CDatabase and CRecordset classes. The database is not dynamically bound to an MFC-based form or window.

I'm having an issue with detecting when a particular field of a record is NULL.

Most of my code is working fine. I have no problem connecting to the database, issuing queries, and reading back records. However, there are a couple of fields where I am getting garbage strings, and when I check the database it shows me that the fields in question are NULL.

NULL is reasonable in some cases, so rather than preventing it, I need my code to simply handle it correctly. The values returned from GetFieldValue for the fields in question are NOT null, however. I get some random value that is not a valid pointer. Apparently I need to do some sort of test-for-NULL that isn't simply checking the pointer value.

There is a method in the CRecordset class called IsFieldNull but it doesn't seem to work right, or I'm not calling it properly. I've found no good examples online for how this method is used. The documentation says it takes a single parameter, a void pointer that points to a "field data member" but there's no definition of what that's supposed to be. I've seen examples where a zero-based field index is passed, and examples where a string constant with the field name is passed. I've tried both of these ideas and neither seems to work.

In fact, calling CRecordset::IsFieldNull() always makes my code fly off into never-never land.

There is another member of CRecordset called IsFieldStatusNull which is allegedly supposed to take a field index, but I've found that calling it also fails.

Ultimately, my question is, how does one check if a particular field in a CRecordset is NULL?


I don't really think the existing code is relevant to the question but since it's been requested, here it is (simplified to remove the try/catch block):

CDBVariant v;
CRecordset theRecordSet(&theDB); // Pointer to my CDatabase object
query.Format("SELECT B.*, B.photographerWebsite AS website FROM gbm_shootphotographers AS A INNER JOIN gbm_photographers AS B ON A.photographerID=B.photographerID WHERE A.shootID=%d;", shootID );  
BOOL result = theRecordSet.Open(AFX_DB_USE_DEFAULT_TYPE, query );
memset(&v,0,sizeof(CDBVariant)); // Zero it out before retrieving field
// 1
theRecordSet.GetFieldValue("website", v);
// 2
CString website = *v.m_pstring;

For records where the "website" field has data, it's retrieved just fine. The string is exactly as expected. However, for records where "website" is NULL, I"m getting a non-empty string with garbage, or even worse, a bad string pointer. Frankly, I don't understand why it outputs anything to the CDBVariant object for a NULL field, but therein lies the problem.

I've tried calling IsFieldNull and IsFieldStatusNull at both location #1 and location #2. Goes off into the weeds either way.

Upvotes: 2

Views: 3452

Answers (1)

hamstergene
hamstergene

Reputation: 24439

Before accessing data in CDBVariant you must check its m_dwType member.

CDBVariant is a union, which means though technically you can read any member at any time, reading the one you're not supposed to read results in undefined behavior. In your case, you're getting random pointer which may print to garbage string, or crash right away.

Upvotes: 5

Related Questions