/*
CVSNT Generic API
Copyright (C) 2005 Tony Hoyle and March-Hare Software Ltd
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#define vsnprintf _vsnprintf
#define snprintf _snprintf
#endif
#include <stdlib.h>
#include <config.h>
#include "../lib/api_system.h"
#include <string>
#include "../cvs_string.h"
#include "../ServerIO.h"
#undef UNICODE
#include <sql.h>
#include <sqlext.h>
#include "OdbcConnection.h"
#include "OdbcRecordset.h"
COdbcField::COdbcField()
{
data = NULL;
}
COdbcField::~COdbcField()
{
if(data)
free(data);
}
COdbcField::operator int()
{
switch(ctype)
{
case SQL_C_CHAR:
{ int ret=0; sscanf((const char *)data,"%d",&ret); return ret; }
case SQL_C_LONG:
return (int)*(long*)data;
case SQL_C_DOUBLE:
return (int)*(double*)data;
default:
CServerIo::trace(1,"Bogus value return for field %s",name.c_str());
return 0;
}
}
COdbcField::operator long()
{
switch(ctype)
{
case SQL_C_CHAR:
{ long ret=0; sscanf((const char *)data,"%ld",&ret); return ret; }
case SQL_C_LONG:
return (long)*(long*)data;
case SQL_C_DOUBLE:
return (long)*(double*)data;
default:
CServerIo::trace(1,"Bogus value return for field %s",name.c_str());
return 0;
}
}
COdbcField::operator unsigned()
{
switch(ctype)
{
case SQL_C_CHAR:
{ unsigned ret=0; sscanf((const char *)data,"%u",&ret); return ret; }
case SQL_C_LONG:
return (unsigned)*(long*)data;
case SQL_C_DOUBLE:
return (unsigned)*(double*)data;
default:
CServerIo::trace(1,"Bogus value return for field %s",name.c_str());
return 0;
}
}
COdbcField::operator unsigned long()
{
switch(ctype)
{
case SQL_C_CHAR:
{ unsigned long ret=0; sscanf((const char *)data,"%lu",&ret); return ret; }
case SQL_C_LONG:
return (unsigned long)*(long*)data;
case SQL_C_DOUBLE:
return (unsigned long)*(double*)data;
default:
CServerIo::trace(1,"Bogus value return for field %s",name.c_str());
return 0;
}
}
#if defined(_WIN32) || defined(_WIN64)
COdbcField::operator __int64()
{
switch(ctype)
{
case SQL_C_CHAR:
{ __int64 ret=0; sscanf((const char *)data,"%I64d",&ret); return ret; }
case SQL_C_LONG:
return (__int64)*(long*)data;
case SQL_C_DOUBLE:
return (__int64)*(double*)data;
default:
CServerIo::trace(1,"Bogus value return for field %s",name.c_str());
return 0;
}
}
#else
COdbcField::operator long long()
{
switch(ctype)
{
case SQL_C_CHAR:
{ long long ret=0; sscanf((const char *)data,"%Ld",&ret); return ret; }
case SQL_C_LONG:
return (long long)*(long*)data;
case SQL_C_DOUBLE:
return (long long)*(double*)data;
default:
CServerIo::trace(1,"Bogus value return for field %s",name.c_str());
return 0;
}
}
#endif
COdbcField::operator const char *()
{
switch(ctype)
{
case SQL_C_CHAR:
return (const char *)data;
case SQL_C_LONG:
cvs::sprintf(tmpstr,32,"%ld",*(long*)data);
return tmpstr.c_str();
case SQL_C_DOUBLE:
cvs::sprintf(tmpstr,32,"%lf",*(double*)data);
return tmpstr.c_str();
default:
CServerIo::trace(1,"Bogus value return for field %s",name.c_str());
return 0;
}
}
COdbcField::operator const wchar_t *()
{
switch(ctype)
{
case SQL_C_CHAR:
tmpwstr=cvs::wide((const char *)data);
return tmpwstr.c_str();
case SQL_C_LONG:
cvs::swprintf(tmpwstr,32,L"%ld",*(long*)data);
return tmpwstr.c_str();
case SQL_C_DOUBLE:
cvs::swprintf(tmpwstr,32,L"%lf",*(double*)data);
return tmpwstr.c_str();
default:
CServerIo::trace(1,"Bogus value return for field %s",name.c_str());
return 0;
}
}
/**********************************************************************/
COdbcRecordset::COdbcRecordset()
{
m_hStmt = NULL;
m_bEof = true;
}
COdbcRecordset::~COdbcRecordset()
{
Close();
}
bool COdbcRecordset::Init(COdbcConnection *parent, HSTMT hStmt, const char *command)
{
m_bEof = false;
m_parent = parent;
m_hStmt = hStmt;
if(!SQL_SUCCEEDED(m_parent->m_lasterror=SQLExecDirect(m_hStmt,(SQLCHAR*)command,SQL_NTS)))
{
GetStmtError();
return false;
}
if(!SQL_SUCCEEDED(m_parent->m_lasterror = SQLNumResultCols(m_hStmt,&m_num_fields)))
{
GetStmtError();
return false;
}
m_sqlfields.resize(m_num_fields);
for(SQLSMALLINT n=0; n<m_num_fields; n++)
{
SQLRETURN rc;
SQLCHAR szCol[128];
SQLSMALLINT len = sizeof(szCol);
rc = m_parent->m_lasterror = SQLDescribeCol(hStmt,n+1,szCol,sizeof(szCol),&len,&m_sqlfields[n].type,&m_sqlfields[n].size,&m_sqlfields[n].decimal,&m_sqlfields[n].null);
if(!SQL_SUCCEEDED(rc))
{
GetStmtError();
return false;
}
szCol[len]='\0';
m_sqlfields[n].field = n;
m_sqlfields[n].hStmt = m_hStmt;
m_sqlfields[n].name = (char*)szCol;
SQLINTEGER fldlen = 0;
SQLSMALLINT ctype;
switch(m_sqlfields[n].type)
{
case SQL_UNKNOWN_TYPE:
CServerIo::trace(1,"Unable to bind column %s as it is SQL_UNKNOWN_TYPE",(const char *)szCol);
break; // Don't bind
case SQL_CHAR:
case SQL_VARCHAR:
ctype = SQL_C_CHAR;
fldlen = m_sqlfields[n].size;
break;
case SQL_DECIMAL:
ctype = SQL_C_CHAR;
fldlen = m_sqlfields[n].size + m_sqlfields[n].decimal + 1;
break;
case SQL_NUMERIC:
case SQL_INTEGER:
case SQL_SMALLINT:
ctype = SQL_C_LONG;
fldlen = sizeof(long);
break;
case SQL_FLOAT:
case SQL_REAL:
case SQL_DOUBLE:
ctype = SQL_C_DOUBLE;
fldlen = sizeof(double);
break;
case SQL_DATETIME:
ctype = SQL_C_CHAR;
fldlen = 64;
break;
}
m_sqlfields[n].ctype = ctype;
m_sqlfields[n].fldlen = fldlen;
if(m_sqlfields[n].fldlen)
{
m_sqlfields[n].data = malloc(m_sqlfields[n].fldlen);
if(!SQL_SUCCEEDED(m_parent->m_lasterror = SQLBindCol(m_hStmt,n+1,m_sqlfields[n].ctype,m_sqlfields[n].data,m_sqlfields[n].fldlen,&m_sqlfields[n].datalen)))
{
GetStmtError();
CServerIo::trace(1,"Unable to bind column %s due to error",(const char*)szCol);
return false;
}
}
}
if(m_num_fields)
{
if(!Next() && !m_bEof)
return false;
}
return true;
}
bool COdbcRecordset::Close()
{
if(m_hStmt)
SQLFreeStmt(m_hStmt,SQL_DROP);
m_hStmt = NULL;
m_bEof = true;
return true;
}
bool COdbcRecordset::Closed() const
{
if(!m_hStmt)
return false;
return true;
}
bool COdbcRecordset::Eof() const
{
return m_bEof;
}
bool COdbcRecordset::Next()
{
SQLRETURN res;
if(m_bEof)
return false;
m_parent->m_lasterror = res = SQLFetch(m_hStmt);
if(res == SQL_NO_DATA_FOUND)
{
m_bEof = true;
return false;
}
if(!SQL_SUCCEEDED(res))
{
GetStmtError();
return false;
}
return true;
}
CSqlField* COdbcRecordset::operator[](size_t item) const
{
if(item>=(size_t)m_num_fields)
return NULL;
return (CSqlField*)&m_sqlfields[item];
}
CSqlField* COdbcRecordset::operator[](int item) const
{
if(item<0 || item>=m_num_fields)
return NULL;
return (CSqlField*)&m_sqlfields[item];
}
CSqlField* COdbcRecordset::operator[](const char *item) const
{
for(size_t n=0; n<(size_t)m_num_fields; n++)
if(!strcasecmp(m_sqlfields[n].name.c_str(),item))
return (CSqlField*)&m_sqlfields[n];
CServerIo::error("Database error - field '%s' not found in recordset.",item);
return NULL;
}
void COdbcRecordset::GetStmtError()
{
SQLCHAR state[6];
SQLINTEGER error;
SQLSMALLINT size = 512,len;
m_parent->m_lastrsError.resize(size);
SQLCHAR *pmsg = (SQLCHAR*)m_parent->m_lastrsError.data();
if(m_hStmt)
{
for(int i=1; SQL_SUCCEEDED(SQLGetDiagRec(SQL_HANDLE_STMT, m_hStmt, i, state, &error, pmsg, size, &len)); i++)
{
size-=len;
pmsg+=len;
}
}
m_parent->m_lastrsError.resize(512-size);
}
syntax highlighted by Code2HTML, v. 0.9.1