As I'm feeling unusally generous, I've put the source code for my SQL plug-in here :
// sql.cpp : Defines the initialization routines for the DLL.
//
/*
This source file is (C) Nicholas Kingsley 2002-2003.
All rights reserved. Whilst the source code is FREEWARE, I retain the copyright on the code.
Please inform me of any bug-fixes, speed improvements etc
Send any comments to : nickk@nildram.co.uk
*/
#define SQL_EXPORTS
#include "stdafx.h"
#include "sql.h"
#include "afxdb.h"
#include "sql.hpp"
#include "globstruct.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CDatabase database;
CRecordset *recSet=NULL;
CDBVariant varRecordToReturnTo;
GlobStruct* g_pGlob = NULL;
typedef struct __ERROR {
int flags;
DWORD mem;
DWORD size;
} __ERROR;
struct __ERROR error;
#define ISVALID(x) ((x)==NULL ? false : true)
#define IsEmpty(x) ((x)==NULL || ((x)->IsEOF() && (x)->IsBOF()) ? true : false)
/////////////////////////////////////////////////////////////////////////////
// CSqlApp
BEGIN_MESSAGE_MAP(CSqlApp, CWinApp)
//{{AFX_MSG_MAP(CSqlApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSqlApp construction
CSqlApp::CSqlApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
error.flags=ERROR_TOSCREEN;
error.mem=0;
error.size=0;
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CSqlApp object
CSqlApp theApp;
void Constructor(void)
{
// Create memory here
}
void Destructor(void)
{
// Free memory here
}
void ReceiveCoreDataPtr(LPVOID pCore)
{
// Get Core Data Pointer here
g_pGlob = (GlobStruct*)pCore;
}
void __processErrorMessage(int errNum,const char *errText,char *where)
{
if (error.flags & ERROR_TOMEM)
{
LPSTR ptr;
int size;
size=sizeof(errNum);
ptr=(LPSTR) error.mem;
// Put in the error number
ZeroMemory(ptr,error.size);
memcpy(ptr,(char *) &errNum,size);
memcpy((LPSTR) (ptr+size),errText,error.size-1);
}
if (error.flags & ERROR_TOSCREEN)
{
MessageBox(NULL,errText,where,MB_OK | MB_ICONWARNING);
}
}
void SQL_SetError(int flags,DWORD mem,DWORD size)
{
error.flags=flags;
error.mem=mem;
error.size=size;
}
DWORD SQL_Connect(LPSTR connectString,int options)
{
TRY
{
int flags;
flags=0;
flags|=(options & OPEN_OPENEXCLUSIVE ? CDatabase::openExclusive : 0);
flags|=(options & OPEN_READONLY ? CDatabase::openReadOnly : 0);
flags|=(options & OPEN_CURSORLIB ? CDatabase::useCursorLib : 0);
flags|=(options & OPEN_NODIALOG ? CDatabase::noOdbcDialog : 0);
flags|=(options & OPEN_DIALOG ? CDatabase::forceOdbcDialog : 0);
if (database.OpenEx(_T(connectString),flags))
{
return ((DWORD) true);
}
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_Connect");
}
END_CATCH
return ((DWORD) false);
}
DWORD SQL_Disconnect(void)
{
if (ISVALID(recSet))
{
delete recSet;
}
database.Close();
return ((DWORD) true);
}
DWORD SQL_ExecuteSQL(LPSTR sql)
{
register bool cont;
if ((error.flags & ERROR_NOERRORCHK)==0)
{
cont=(SQL_GetStatus(STATUS_ISOPEN,0) && sql ? true : false);
}
else
{
cont=(sql ? true : false);
}
if (cont)
{
TRY
{
database.ExecuteSQL(_T(sql));
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_ExecuteSQL");
return ((DWORD) false);
}
END_CATCH
}
return ((DWORD) false);
}
DWORD SQL_ConnectTable(LPSTR tableName,int openType,int options)
{
recSet=new CRecordset(&database);
TRY
{
if (ISVALID(recSet))
{
register unsigned int flags1,flags2;
flags1=AFX_DB_USE_DEFAULT_TYPE;
flags1|=(openType & OPEN_DYNASET ? CRecordset::dynaset : 0);
flags1|=(openType & OPEN_SNAPSHOT ? CRecordset::snapshot : 0);
flags1|=(openType & OPEN_DYNAMIC ? CRecordset::dynamic : 0);
flags1|=(openType & OPEN_FORWARDONLY ? CRecordset::forwardOnly : 0);
flags2=CRecordset::none;
flags2|=(options & OPEN2_APPENDONLY ? CRecordset::appendOnly : 0);
flags2|=(options & OPEN2_READONLY ? CRecordset::readOnly : 0);
flags2|=(options & OPEN2_BULKADD ? CRecordset::optimizeBulkAdd : 0);
flags2|=(options & OPEN2_MULTROWFETCH ? CRecordset::useMultiRowFetch : 0);
flags2|=(options & OPEN2_SKIPDEL ? CRecordset::skipDeletedRecords : 0);
flags2|=(options & OPEN2_USEBOOKMARK ? CRecordset::useBookmarks : 0);
flags2|=(options & OPEN2_NODIRTY ? CRecordset::noDirtyFieldCheck : 0);
flags2|=(options & OPEN2_EXECUTEDIR ? CRecordset::executeDirect : 0);
flags2|=(options & OPEN2_EXTENDEDFETCH ? CRecordset::useExtendedFetch : 0);
flags2|=(options & OPEN2_ALLOCMULTI ? CRecordset::userAllocMultiRowBuffers : 0);
if (recSet->Open(flags1,_T(tableName),flags2)==0)
{
return ((DWORD) false);
}
}
else
{
return ((DWORD) false);
}
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_ConnectTable");
return ((DWORD) false);
}
END_CATCH
return ((DWORD) true);
}
DWORD SQL_IsBOF(void)
{
return ((DWORD) (ISVALID(recSet) && SQL_GetStatus(STATUS_ISOPEN,0) ? recSet->IsBOF() : true));
}
DWORD SQL_IsEOF(void)
{
return ((DWORD) (ISVALID(recSet) && SQL_GetStatus(STATUS_ISOPEN,0) ? recSet->IsEOF() : true));
}
DWORD SQL_IsDeleted(void)
{
return ((DWORD) (ISVALID(recSet) && SQL_GetStatus(STATUS_ISOPEN,0) ? recSet->IsDeleted() : true));
}
DWORD SQL_MoveFirst(void)
{
if (ISVALID(recSet) && SQL_GetStatus(STATUS_ISOPEN,0))
{
TRY
{
if (IsEmpty(recSet))
{
// Both end of file, so dont do anything
return ((DWORD) false);
}
recSet->MoveFirst();
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_MoveFirst");
return ((DWORD) false);
}
END_CATCH
return ((DWORD) true);
}
return ((DWORD) false);
}
DWORD SQL_MoveLast(void)
{
if (ISVALID(recSet) && SQL_GetStatus(STATUS_ISOPEN,0))
{
if (IsEmpty(recSet))
{
// Both end of file, so dont do anything
return ((DWORD) false);
}
TRY
{
recSet->MoveLast();
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_MoveLast");
return ((DWORD) false);
}
END_CATCH
return ((DWORD) true);
}
return ((DWORD) false);
}
unsigned __int64 SQL_FieldCount(void)
{
return ((unsigned __int64) (!ISVALID(recSet) ? 0 : recSet->GetODBCFieldCount()));
}
unsigned __int64 SQL_RecordCount(void)
{
unsigned __int64 count;
count=0;
if (ISVALID(recSet) && SQL_GetStatus(STATUS_ISOPEN,0))
{
TRY
{
if (SQL_MoveFirst())
{
while (!SQL_IsEOF())
{
if (!SQL_IsDeleted())
{
count++;
}
SQL_MoveNext();
}
}
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_RecordCount");
return ((unsigned __int64) 0);
}
END_CATCH
}
return ((unsigned __int64) count);
}
void SQL_GetFieldValue(LPSTR name,DWORD ptr)
{
CString strValue;
LPSTR addr;
if (ISVALID(recSet) && SQL_GetStatus(STATUS_ISOPEN,0))
{
if ((addr=(LPSTR) ptr)!=NULL)
{
if (!IsEmpty(recSet))
{
TRY
{
recSet->GetFieldValue(_T(name),strValue);
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_GetFieldValue");
return;
}
END_CATCH
strcpy(addr,strValue);
}
else
{
}
}
}
}
DWORD SQL_MoveNext(void)
{
if (ISVALID(recSet))
{
if (!IsEmpty(recSet) && SQL_GetStatus(STATUS_ISOPEN,0))
{
TRY
{
recSet->MoveNext();
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_MoveNext");
return ((DWORD) false);
}
CATCH(CMemoryException, m)
{
__processErrorMessage(-1,"Error","SQL_MoveNext");
return ((DWORD) false);
}
END_CATCH
return ((DWORD) true);
}
}
return ((DWORD) false);
}
DWORD SQL_MovePrev(void)
{
if (ISVALID(recSet))
{
if (!IsEmpty(recSet) && SQL_GetStatus(STATUS_ISOPEN,0))
{
TRY
{
recSet->MovePrev();
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_MovePrev");
return ((DWORD) false);
}
END_CATCH
return ((DWORD) true);
}
}
return ((DWORD) false);
}
DWORD SQL_Delete(void)
{
if (ISVALID(recSet) && SQL_GetStatus(STATUS_ISOPEN,0))
{
if (IsEmpty(recSet) || SQL_IsDeleted() || !recSet->CanUpdate())
{
// Both end of file, so dont do anything
return ((DWORD) false);
}
TRY
{
recSet->Delete();
recSet->Requery();
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_Delete");
return ((DWORD) false);
}
END_CATCH
return ((DWORD) true);
}
return ((DWORD) false);
}
DWORD SQL_GetConnect(DWORD pOldString)
{
register LPSTR pReturnString=NULL;
CString temp;
register int len;
// Delete old string
if(pOldString) g_pGlob->CreateDeleteString ( (DWORD*)&pOldString, 0 );
// Return string pointer
temp=database.GetConnect();
len=temp.GetLength()+1;
g_pGlob->CreateDeleteString ((DWORD*) &pReturnString, len);
ZeroMemory(pReturnString,len);
memcpy(pReturnString,temp,len-1);
return ((DWORD) pReturnString);
}
DWORD SQL_GetDatabaseName(DWORD pOldString)
{
register LPSTR pReturnString=NULL;
CString temp;
register int len;
// Delete old string
if(pOldString) g_pGlob->CreateDeleteString ( (DWORD*)&pOldString, 0 );
// Return string pointer
temp=database.GetDatabaseName();
len=temp.GetLength()+1;
g_pGlob->CreateDeleteString ((DWORD*) &pReturnString, len);
ZeroMemory(pReturnString,len);
memcpy(pReturnString,temp,len-1);
return ((DWORD) pReturnString);
}
DWORD SQL_GetTableName(DWORD pOldString)
{
register LPSTR pReturnString=NULL;
CString temp;
register int len;
// Delete old string
if(pOldString) g_pGlob->CreateDeleteString ( (DWORD*)&pOldString, 0 );
if (ISVALID(recSet))
{
// Return string pointer
temp=recSet->GetTableName();
len=temp.GetLength()+1;
}
else
{
len=0;
}
g_pGlob->CreateDeleteString ((DWORD*) &pReturnString, len);
if (len)
{
ZeroMemory(pReturnString,len);
memcpy(pReturnString,temp,len-1);
}
return ((DWORD) pReturnString);
}
DWORD SQL_GetStatus(int which,DWORD ptr)
{
void *pv;
pv=(void *) ptr;
switch (which) {
case STATUS_ISOPEN : // Is database open ?
return ((DWORD) database.IsOpen() ? true : false);
break;
case STATUS_TRANSACT : // Can transact ?
return ((DWORD) database.CanTransact() ? true : false);
break;
case STATUS_UPDATE : // Can update ?
return ((DWORD) database.CanUpdate() ? true : false);
break;
case STATUS_APPEND : // Can append ?
return ((DWORD) ISVALID(recSet) ? recSet->CanAppend() : false);
break;
case STATUS_BOOKMARK : // Can bookmark ?
return ((DWORD) ISVALID(recSet) ? recSet->CanBookmark() : false);
break;
case STATUS_RESTART : // Can restart ?
return ((DWORD) ISVALID(recSet) ? recSet->CanRestart() : false);
break;
case STATUS_SCROLL : // Can scroll ?
return ((DWORD) ISVALID(recSet) ? recSet->CanScroll() : false);
break;
case STATUS_TRANSACT2: // Can record transact ?
return ((DWORD) ISVALID(recSet) ? recSet->CanTransact() : false);
break;
case STATUS_UPDATE2 : // Can record update ?
return ((DWORD) ISVALID(recSet) ? recSet->CanUpdate() : false);
break;
case STATUS_DIRTY : // Is the field dirty ?
case STATUS_NULL : // Is the field NULL
case STATUS_NULLABLE : // Is the field NULLable ?
if (ISVALID(recSet))
{
TRY
{
switch (which) {
case STATUS_DIRTY : return (recSet->IsFieldDirty(pv));
break;
case STATUS_NULL : return (recSet->IsFieldNull(pv));
break;
case STATUS_NULLABLE : return (recSet->IsFieldNullable(pv));
break;
};
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_Status");
}
END_CATCH
}
break;
};
return (STATUS_NOTKNOWN);
}
void SQL_GetSetBookmark(bool set)
{
if (ISVALID(recSet) && recSet->CanBookmark())
{
if (set)
{
// Set a bokmark
recSet->GetBookmark(varRecordToReturnTo);
}
else
{
recSet->SetBookmark(varRecordToReturnTo);
}
}
}
void SQL_SetAbsPosition(long rows)
{
if (ISVALID(recSet))
{
TRY
{
recSet->SetAbsolutePosition(rows);
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_SetAbsPosition");
}
END_CATCH
}
}
long SQL_GetCurrentRecordPos(void)
{
CRecordsetStatus rStatus;
if (ISVALID(recSet))
{
TRY
{
recSet->GetStatus(rStatus);
}
CATCH(CDBException, e)
{
// The error code is in e->m_nRetCode
__processErrorMessage(e->m_nRetCode,(LPCTSTR) e->m_strError,"SQL_CurrentRecordPos");
return (AFX_CURRENT_RECORD_UNDEFINED);
}
END_CATCH
return (rStatus.m_lCurrentRecord);
}
return (AFX_CURRENT_RECORD_UNDEFINED);
}