/* 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 */ #define WIN32_LEAN_AND_MEAN #include #include #define vsnprintf _vsnprintf #define snprintf _snprintf #include #include #include "../lib/api_system.h" #include #include "../cvs_string.h" #include "../ServerIO.h" #include #include #include "MssqlConnection.h" #include "MssqlRecordset.h" CMssqlField::CMssqlField() { data = NULL; } CMssqlField::~CMssqlField() { if(data) free(data); } CMssqlField::operator int() { switch(ctype) { case SQL_C_WCHAR: { int ret=0; swscanf((const wchar_t *)data,L"%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; } } CMssqlField::operator long() { switch(ctype) { case SQL_C_WCHAR: { long ret=0; swscanf((const wchar_t *)data,L"%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; } } CMssqlField::operator unsigned() { switch(ctype) { case SQL_C_WCHAR: { unsigned ret=0; swscanf((const wchar_t *)data,L"%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; } } CMssqlField::operator unsigned long() { switch(ctype) { case SQL_C_WCHAR: { unsigned long ret=0; swscanf((const wchar_t *)data,L"%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; } } CMssqlField::operator __int64() { switch(ctype) { case SQL_C_WCHAR: { __int64 ret=0; swscanf((const wchar_t *)data,L"%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; } } CMssqlField::operator const char *() { switch(ctype) { case SQL_C_WCHAR: tmpstr = cvs::narrow((const wchar_t*)data); return tmpstr.c_str(); 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; } } CMssqlField::operator const wchar_t *() { switch(ctype) { case SQL_C_WCHAR: return (const wchar_t*)data; 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; } } /**********************************************************************/ CMssqlRecordset::CMssqlRecordset() { m_hStmt = NULL; m_bEof = true; } CMssqlRecordset::~CMssqlRecordset() { Close(); } bool CMssqlRecordset::Init(CMssqlConnection *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,(SQLWCHAR*)(const wchar_t *)cvs::wide(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; nm_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 = 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_WCHAR; fldlen = m_sqlfields[n].size; break; case SQL_DECIMAL: ctype = SQL_C_WCHAR; 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_WCHAR; 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 CMssqlRecordset::Close() { if(m_hStmt) SQLFreeStmt(m_hStmt,SQL_DROP); m_hStmt = NULL; m_bEof = true; return true; } bool CMssqlRecordset::Closed() const { if(!m_hStmt) return false; return true; } bool CMssqlRecordset::Eof() const { return m_bEof; } bool CMssqlRecordset::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* CMssqlRecordset::operator[](size_t item) const { if(item>=(size_t)m_num_fields) return NULL; return (CSqlField*)&m_sqlfields[item]; } CSqlField* CMssqlRecordset::operator[](int item) const { if(item<0 || item>=m_num_fields) return NULL; return (CSqlField*)&m_sqlfields[item]; } CSqlField* CMssqlRecordset::operator[](const char *item) const { cvs::wide _item(item); for(size_t n=0; n<(size_t)m_num_fields; n++) if(!wcsicmp(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 CMssqlRecordset::GetStmtError() { SQLWCHAR state[6]; SQLINTEGER error; SQLSMALLINT size = 512,len; m_parent->m_lastrsError.resize(size); SQLWCHAR *pmsg = (SQLWCHAR*)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); }