LwQuery() | constuctor |
~LwQuery() | destructor |
void SetDatabase( CDatabase* pDatabase) | Set the database handle to a CDatabase object which encapsulates the ODBC connection |
RETCODE ExecDirect( LPCTSTR statement) | Execute an arbitrary sql statement; on success the function returns SQL_SUCCESS, otherwise one of the return codes defined in <sql.h>. If statement contains question mark placeholders it is obligatory to bind a host variable for each placeholder (see below) before calling ExecDirect(). |
RETCODE Close() | Finish the statement and release all its resources. |
LwQuery query;
CString statement;
query.SetDatabase( &db);
statement = _T(
" create table person\n"
" (\n"
"
lfnbr
int
not null,\n"
"
name
char(32)
null ,\n"
"
birthdte
datetime
null ,\n"
"
balance
decimal(8,2)
null ,\n"
" constraint
pk_person primary key (lfnbr)\n"
" )\n"
);
nRetCode = query.ExecDirect( statement);
nRetCode = query.ExecDirect(
_T("insert into person( lfnbr,
name, birthdte, balance) values( 1, 'Jack', '1964-03-24', 5432.19)"));
nRetCode = query.ExecDirect(
_T("insert into person( lfnbr,
name, birthdte, balance) values( 2, 'Jill', '2004-05-21', 1234.56)"));
RETCODE GetRowsAffected( SQLLEN& nRowCount) | Gets the number of affected rows. Only for such statements as delete or update which do not return a result set. For other statements which return a result set (e.g. select) the row count may be set for some drivers and for other drivers not. |
short GetODBCFieldCount() const | Gets the number of columns in the result set. Can also be used to check whether there is a result set at all. |
short GetFieldIndexByName(LPCTSTR lpszFieldName) | Returns the 0-based column index which corresponds to the column named lpszFieldName, -1 if no column name matches. |
void GetODBCFieldInfo( short nIndex, CODBCFieldInfo& fieldinfo) |
Retrieves information about column type and size. See Visual Studio / MFC help for further information on CODBCFieldInfo. |
BOOL GetODBCFieldInfo( LPCTSTR lpszName, CODBCFieldInfo& fieldinfo) |
Retrieves information about column type and size. See Visual Studio / MFC help for further information on CODBCFieldInfo. Returns FALSE if no column with name lpszName exists. |
RETCODE Fetch() | Fetches the next row of the resultset. If successful it returns SQL_SUCCESS or SQL_SUCCESS_WITH_INFO. If there are no more rows in the result (after the last row) set it returns SQL_NO_DATA_FOUND. No explicit column binding! |
void GetFieldValue( short nIndex, CString& sValue) | Retrieves the value of the specified column in the current row. Most sql data types can be converted to CString. |
BOOL GetFieldValue( LPCTSTR lpszName, CString& sValue ) |
Retrieves the value of the specified column in the current row. Most sql data types can be converted to CString. Returns FALSE if no column with name lpszName exists. |
BOOL GetFieldValue( short nIndex, long& lValue) | Retrieve the value of the specified column in the current row into a variable of the respective type. Returns FALSE if the sql type of the column cannot be converted into that type. See the conversion matrix in Visual Studio help. |
BOOL GetFieldValue( short nIndex, int& iValue) | |
BOOL GetFieldValue( short nIndex, short& siValue) | |
BOOL GetFieldValue( short nIndex, UINT64& ui64Value) | |
BOOL GetFieldValue( LPCTSTR lpszName, long& lValue) |
Retrieve the value of the specified column in the current row into a variable of the respective type. Returns FALSE if no column with name lpszName exists or if the sql type of the column cannot be converted into int. See the conversion matrix in Visual Studio help. |
BOOL GetFieldValue( LPCTSTR lpszName, int& iValue) |
|
BOOL GetFieldValue( LPCTSTR lpszName, short& siValue) |
|
BOOL GetFieldValue( LPCTSTR lpszName, UINT64& ui64Value) |
|
BOOL GetFieldValue( short nIndex, CByteArray& ba) |
Retrieve binary or varbinary column data from the current row into a CByteArray variable. The ByteArray size fits the length of the (var)binary data in the database field. Returns FALSE if no column with name lpszName exists. |
BOOL GetFieldValue( LPCTSTR lpszName, CByteArray& ba) |
|
void GetFieldValue( short nIndex, LwDBVariant& varValue, short nFieldType = DEFAULT_FIELD_TYPE) |
Retrieve the value of the specified
column in the current row into a variable of type LwDBVariant.
LwDBVariant is a helper class derived from CDBVariant which
supports additional data types, formatting into string, assignment
and comparison operators. Returns FALSE if no column with name
lpszName exists. Actually all GetFieldValue() functions, except those for CString, CstringA, CStringW, internally use this functions and cache the data in a protected member which is an array of LwDBVariants. |
BOOL GetFieldValue( LPCTSTR lpszName, LwDBVariant& varValue, short nFieldType = DEFAULT_FIELD_TYPE) |
|
void GetCurrentRow( LwDataRow& currentRow); | Read all fields from the current row into a LwDataRow array. LwDataRow is derived of CArray of LwDBVariants. |
BOOL IsFieldInit( short nIndex) | If TRUE the data field in the current row has been read and value or null indicator is initialized. |
BOOL IsFieldNull( short nIndex) | If TRUE column with nIndex has been read and holds the db null value. |
RETCODE SQLMoreResults() |
ODBC allows multiple result sets for one query. After reading the last row of a result set SQLMoreResults() asks whether there is another result set pending. Return value SQL_SUCCESS (or SQL_SUCCESS_WITH_INFO) means there is another result set to be read. SQL_NO_DATA_FOUND means all result sets have already been read. SQLMoreResults() also re-initializes the ODBCFieldInfos according to the new result set. |
nRetCode = query.ExecDirect(_T("select *
from person"));
short colcount = query.GetODBCFieldCount();
// if we have a result set colcount will be
> 0 (even if the result holds 0 rows!)
if (colcount > 0)
{
// optional: retrieve
information on the columns of the result set
// this is not mandatory for the
subsequent retrieval of the column values
for (short col=0; col <
colcount; col++)
{
LwFieldInfo
fieldinfo;
query.GetODBCFieldInfo( col, fieldinfo);
printf(_T("columnn name:\t%s\nSQL
type:\t%0d\nPrecision:\t%0d\nScale:\t%0d\nNullable:\t%0d\n\n"),
//
// meta data from ODBC:
fieldinfo.m_strName,
// CString m_strName;
fieldinfo.m_nSQLType,
// SWORD m_nSQLType; (see "SQL
data type codes" in <sql.h>
fieldinfo.m_nPrecision,
// SQLULEN m_nPrecision;
fieldinfo.m_nScale,
// SWORD
m_nScale;
fieldinfo.m_nNullability
// SWORD m_nNullability;
);
}
// now we retrieve data by
iterating over the rows of result set
for (nRetCode = query.Fetch();
nRetCode != SQL_NO_DATA; nRetCode = query.Fetch())
{
// the
current row is in the buffer
short col =
0;
long lfnbr =
0;
query.GetFieldValue( col++, lfnbr); // adressing the
column by its index 0
CString sName;
query.GetFieldValue(_T("name"), sName); // adressing
the column by its column name
LwDBVariant varBirthDte;
// variant
data type LwDBVariant is an extension of CDBVariant
// and can be
used if the column data type is unknown or no appropriate
GetFieldValue() member available
query.GetFieldValue((short) 2, varBirthDte);
printf(_T("Nr. %0d\t%s\n"), lfnbr, (LPCTSTR) sName);
}
}
The BindParameter functions replace the question marks by host
variables of various types. The binding is always done by
call-by-reference. For normal sql statements these parameters are of
InputOutputType SQL_PARAM_INPUT. They stay unchanged by the execution of
the sql statement.
When working with stored procedure parameters may be of InputOutputType
SQL_PARAM_OUTPUT or SQL_PARAM_INPUT_OUTPUT meaning the stored procedure
call may use their value and assign a new value to the host variable
when executed.
If a statement contains N question mark placeholders the parameters are
numbered 1 to N. 0 is reserved for the RETCODE of the query.
RETCODE Prepare( LPCTSTR statement) | Set an arbitrary SQL statement which is to be executed. The statement may contain question marks as placeholders for variables which have to be bound to the statement according to their types and the sql type in the statement. For details see the conversion matrix in Visual Studio help. |
RETCODE BindParameter( SQLUSMALLINT ParameterNumber, short& nParamValue, SQLSMALLINT InputOutputType = SQL_PARAM_INPUT) |
Host variable is of C++ type short (16 bit integer) which corresponds to the ODBC sql type SQL_SMALLINT. |
RETCODE BindParameter( SQLUSMALLINT ParameterNumber, int& nParamValue, SQLSMALLINT InputOutputType = SQL_PARAM_INPUT) |
Host variable is of C++ type int (32 bit integer) which corresponds to the ODBC sql type SQL_INTEGER. |
RETCODE BindParameter( SQLUSMALLINT ParameterNumber, long& nParamRef, SQLSMALLINT InputOutputType = SQL_PARAM_INPUT) |
Host variable is of C++ type long (32 bit integer) which corresponds to the ODBC sql type SQL_INTEGER. |
RETCODE BindParameter( SQLUSMALLINT ParameterNumber, __int64& nParamRef, SQLSMALLINT InputOutputType = SQL_PARAM_INPUT) |
Host variable is of C++ type __int64 (64 bit integer) which corresponds to the ODBC sql type SQL_BIGINT. |
RETCODE BindParameter( SQLUSMALLINT ParameterNumber, double& sParamRef, SQLSMALLINT InputOutputType = SQL_PARAM_INPUT) |
Host variable is of C++ type double. Length in memory of double is 64 bit integer. It maybe used for ODBC sql types SQL_DOUBLE but also for SQL_DECIMAL, SQL_NUMERIC, or SQL_FLOAT. |
RETCODE BindParameter( SQLUSMALLINT ParameterNumber, TIMESTAMP_STRUCT& tsParamRef, SQLSMALLINT InputOutputType = SQL_PARAM_INPUT) |
Host variable is a TIMESTAMP_STRUCT. It can be used for sql
types SQL_DATETIME. |
RETCODE BindParameter( SQLUSMALLINT ParameterNumber, CString& sParamRef, SQLLEN strlen = 0, SQLSMALLINT InputOutputType = SQL_PARAM_INPUT) |
Host variable is of MFC class CString. Length in memory depends. It maybe used for ODBC sql types SQL_CHAR, SQL_VARCHAR, SQL_WCHAR, SQL_WVARCHAR. For SQL_PARAM_INPUT_OUTPUT and SQL_PARAM_OUTPUT the CString buffer must be big enough to receive the maximal possible length to be wriiten. The buffer length has to be set in the strlen parameter. |
void SetParamLenIndicator( SQLUSMALLINT ParameterNumber, SQLLEN lenInd) | Set special parameter values, e.g. SQL_NTS (Null terminated string), SQL_NULL_DATA (for null value), SQL_DEFAULT_PARAM (only for stored procedure calls). |
Execute() | Execute the statement which was previously set with SetStatement(). If you want to execute the same statement with different parameter values, it is sufficient to assign the new values to the already bound host variables and call Execute() again. This is also more performant than building new query strings and calling them by ExecuteDirect(). |
long lfnbr = 3;
CString sName = _T("Joe");
TIMESTAMP_STRUCT tsBirthDte;
tsBirthDte.year = 2006;
tsBirthDte.month = 7;
tsBirthDte.day = 12;
tsBirthDte.hour = 0;
tsBirthDte.minute = 0;
tsBirthDte.second = 0;
tsBirthDte.fraction = 0;
double balance = 234.56;
// To free old bindings, always close previous query
when working with parameter binding.
query.Close();
query.SetStatement(
_T("insert into person( lfnbr,
name, birthdte, balance) values( ?, ?, ?, ?)"));
// Parameter binding
// -----------------
short par = 1;
query.BindParameter( par++, lfnbr);
query.BindParameter( par++, sName);
query.BindParameter( par++, tsBirthDte);
query.BindParameter( par++, balance);
// Remark: ExecDirect() works with parameter binding,
too.
nRetCode = query.Execute();
ASSERT( nRetCode == SQL_SUCCESS || nRetCode ==
SQL_SUCCESS_WITH_INFO);
query.Close();
RETCODE SetParamValue( SQLUSMALLINT ParameterNumber, long nParamValue, SQLSMALLINT InputOutputType = SQL_PARAM_INPUT) | LwQuery creates the host variable on the heap and holds it until the Close() member function is called. |
RETCODE SetParamValue( SQLUSMALLINT ParameterNumber, double dParamValue, SQLSMALLINT InputOutputType = SQL_PARAM_INPUT) | |
RETCODE SetParamValue( SQLUSMALLINT ParameterNumber, TIMESTAMP_STRUCT ParamValue, SQLSMALLINT InputOutputType = SQL_PARAM_INPUT) | LwQuery creates a TIMESTAMP_STRUCT host variable on the heap, assigns the dtParamValue to it and holds the host variable until the Close() member function is called. |
RETCODE SetParamValue( SQLUSMALLINT ParameterNumber, LPCTSTR lpszValue, SQLSMALLINT InputOutputType = SQL_PARAM_INPUT) | LwQuery creates a CString host variable on the heap, assigns the LPCTSTR value and holds the host variable until the Close() member function is called. |
query.Prepare(
_T("insert into person(
lfnbr, name, birthdte, balance) values( ?, ?, ?, ?)"));
// internal parameter binding
// --------------------------
par = 1;
query.SetParamValue( par++, (long) 4);
query.SetParamValue( par++, _T("Jim"));
query.SetParamValue( par++, tsBirthDte);
query.SetParamValue( par++, 3523.17);
// Execute uses the above parameters.
nRetCode = query.Execute();
ASSERT( nRetCode == SQL_SUCCESS || nRetCode ==
SQL_SUCCESS_WITH_INFO);
// free resources
// --------------
query.Close();
BOOL GetParamValue( SQLUSMALLINT ParameterNumber, long& nParamValue); | If a parmeter of fitting type is bound (implicitly or explicitly) its value is copied to nParamValue and the function returns TRUE; otherwise it returns FALSE. |
BOOL GetParamValue( SQLUSMALLINT ParameterNumber, double& dParamValue); | |
BOOL GetParamValue( SQLUSMALLINT ParameterNumber, TIMESTAMP_STRUCT& tsParamValue); | |
BOOL GetParamValue( SQLUSMALLINT ParameterNumber, CString& sValue); |
query.Prepare("{CALL testproc(?,?,?,?,?)}");
// internal parameter binding
// --------------------------
par = 1;
query.SetParamValue( par++, (long) 1);
long lVal = 2;
query.SetParamValue( par++, lVal,
SQL_PARAM_INPUT_OUTPUT);
query.SetParamValue( par++, _T("ABC"));
CString sVal = _T("DEF");
query.SetParamValue( par++, sVal,
SQL_PARAM_INPUT_OUTPUT);
long lRetVal = 0;
query.SetParamValue( par++, lRetVal,
SQL_PARAM_INPUT_OUTPUT);
// Execute uses the above parameters.
nRetCode = query.Execute();
ASSERT( nRetCode == SQL_SUCCESS || nRetCode ==
SQL_SUCCESS_WITH_INFO);
query.GetParamValue( 2, lVal); //
--> 3
query.GetParamValue( 4, sVal); //
--> "ABCDEF"
// free resources
// --------------
query.Close();
While this article describes the LwQuery class the code includes some more headers and source files with classes and functions used by LwQuery:
Maybe I'll write someday another article on these classes.