1180 lines
19 KiB
C++
1180 lines
19 KiB
C++
//-----------------------------------------------------------------------------+
|
|
// Copyright (C), 1998-2007, Beijing Tangent Software Co. Ltd.
|
|
// = FileName : DbfUtility.cpp
|
|
// = Version : ver2.0
|
|
// = Author : wlw
|
|
// = CreateDate : 2002-09-09
|
|
// = Description: Dbf工具类的定义
|
|
// = Maintainers:
|
|
//
|
|
//-----------------------------------------------------------------------------+
|
|
/*
|
|
Copyright?2002, Alexey Dolgachov
|
|
mail: alxsoft@gazinter.net
|
|
web: http://www.alxsoft.narod.ru
|
|
*/
|
|
#include "StdAfx.h"
|
|
#include "DbfUtility.h"
|
|
#include "TAString.h"
|
|
#include "TUString.h"
|
|
#include "TSqlCondition.h"
|
|
#include "TSqlQuiry.h"
|
|
|
|
#if ADS>15
|
|
#include <fstream>
|
|
#else
|
|
#include <fstream.H>
|
|
#endif
|
|
|
|
FieldInfo::FieldInfo(const TCHAR *n, int t, int l, int d)
|
|
{
|
|
InitClear();
|
|
if (n)
|
|
{
|
|
name = _strdup(_AS(n));
|
|
}
|
|
|
|
type = t;
|
|
len = l;
|
|
dec = d;
|
|
}
|
|
|
|
FieldInfo::FieldInfo(const FieldInfo &src)
|
|
{
|
|
InitClear();
|
|
*this = src;
|
|
}
|
|
|
|
FieldInfo::~FieldInfo()
|
|
{
|
|
if (name)
|
|
{
|
|
free(name);
|
|
}
|
|
}
|
|
|
|
FieldInfo& FieldInfo::operator= (const FieldInfo &src)
|
|
{
|
|
if (name)
|
|
{
|
|
free(name);
|
|
}
|
|
|
|
if (src.name)
|
|
{
|
|
name = _strdup(src.name);
|
|
}
|
|
else
|
|
{
|
|
name = NULL;
|
|
}
|
|
|
|
type = src.type;
|
|
len = src.len;
|
|
dec = src.dec;
|
|
return *this;
|
|
}
|
|
|
|
void FieldInfo::InitClear()
|
|
{
|
|
name = NULL;
|
|
type = 0;
|
|
len = 0;
|
|
dec = 0;
|
|
}
|
|
|
|
int FieldInfo::operator !()
|
|
{
|
|
return !name;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// CodeBase -- Database classs
|
|
CodeBase::CodeBase()
|
|
{
|
|
d4init(this);
|
|
open_error = 0;
|
|
safety = 0;
|
|
auto_open = 0; // for auto open index
|
|
exclusive = 0;
|
|
read_only = 0;
|
|
read_lock = 0;
|
|
lock_attempts = -1;
|
|
}
|
|
|
|
CodeBase::~CodeBase()
|
|
{
|
|
d4close_all(this);
|
|
d4init_undo(this);
|
|
}
|
|
|
|
DbfTable * CodeBase::Open(const TCHAR *szFile)
|
|
{
|
|
TCHAR szShortPath[256] = _T("");
|
|
if (GetShortPathName(szFile, szShortPath, 256) == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return(DbfTable *) d4open(this, _AS(szShortPath));
|
|
}
|
|
|
|
DbfTable * CodeBase::Create(const TCHAR *szFile, const FieldInfo *pFieldArray)
|
|
{
|
|
return (DbfTable *)d4create(this, (char *)_AS(szFile), (FIELD4INFO *)pFieldArray, NULL);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Recordset class
|
|
DbfTable::DbfTable()
|
|
{
|
|
|
|
}
|
|
|
|
FieldInfo * DbfTable::GetFieldInfo()
|
|
{
|
|
return (FieldInfo *)d4field_info(this);
|
|
}
|
|
|
|
int DbfTable::GetFieldNum()
|
|
{
|
|
return d4num_fields(this);
|
|
}
|
|
|
|
FieldContent * DbfTable::GetFieldContent(const TCHAR *szFieldName)
|
|
{
|
|
return (FieldContent *)d4field(this, (char *)_AS(szFieldName));
|
|
}
|
|
|
|
// n=0, 1, 2, ..., base on ZERO
|
|
FieldContent * DbfTable::GetFieldContent(int n)
|
|
{
|
|
return (FieldContent *)d4field_j(this, n+1);
|
|
}
|
|
|
|
void DbfTable::Close()
|
|
{
|
|
d4close(this);
|
|
}
|
|
|
|
void DbfTable::AppendBegin()
|
|
{
|
|
d4append_start(this,0);
|
|
d4blank(this);
|
|
}
|
|
|
|
void DbfTable::AppendEnd()
|
|
{
|
|
d4append(this);
|
|
}
|
|
|
|
void DbfTable::Delete()
|
|
{
|
|
d4delete(this);
|
|
}
|
|
|
|
void DbfTable::Recall()
|
|
{
|
|
d4recall(this);
|
|
}
|
|
|
|
BOOL DbfTable::Pack()
|
|
{
|
|
return !d4pack(this);
|
|
}
|
|
|
|
// Iteration
|
|
int DbfTable::MoveFirst(int bSkipDeleted)
|
|
{
|
|
int nRet = (d4top(this) == 0 ? TRUE : FALSE);
|
|
if (IsDeleted() && bSkipDeleted)
|
|
{
|
|
nRet = MoveNext(bSkipDeleted);
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
int DbfTable::MoveLast(int bSkipDeleted)
|
|
{
|
|
int nRet = (d4bottom(this) == 0 ? TRUE : FALSE);
|
|
if (IsDeleted() && bSkipDeleted)
|
|
{
|
|
nRet = MovePrev(bSkipDeleted);
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
int DbfTable::MoveNext(int bSkipDeleted)
|
|
{
|
|
while (1)
|
|
{
|
|
d4skip(this, 1L);
|
|
if (IsEOF() || !bSkipDeleted)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (!IsDeleted())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (!IsEOF());
|
|
}
|
|
|
|
int DbfTable::MovePrev(int bSkipDeleted)
|
|
{
|
|
while(1)
|
|
{
|
|
d4skip(this, -1L);
|
|
if (IsBOF() || !bSkipDeleted)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (!IsDeleted())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return (!IsBOF());
|
|
}
|
|
|
|
void DbfTable::Move(long offset, int bSkipDeleted)
|
|
{
|
|
if (offset)
|
|
{
|
|
long nStep = offset / abs(offset);
|
|
if (IsBOF() && offset > 0)
|
|
{
|
|
MoveFirst(bSkipDeleted);
|
|
offset--;
|
|
}
|
|
|
|
if (IsEOF() && offset < 0)
|
|
{
|
|
MoveLast(bSkipDeleted);
|
|
offset++;
|
|
}
|
|
|
|
for (long i = offset; i != 0L; i -= nStep)
|
|
{
|
|
if (nStep > 0)
|
|
{
|
|
MoveNext(bSkipDeleted);
|
|
}
|
|
else
|
|
{
|
|
MovePrev(bSkipDeleted);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int DbfTable::IsEOF()
|
|
{
|
|
return d4eof(this);
|
|
}
|
|
|
|
int DbfTable::IsBOF()
|
|
{
|
|
return d4bof(this);
|
|
}
|
|
|
|
int DbfTable::MoveTo(long nRecNo)
|
|
{
|
|
return (d4go(this, nRecNo + 1) == 0);
|
|
}
|
|
|
|
// Now, match method is not supported
|
|
int DbfTable::MoveTo(const TCHAR *szKey, const TCHAR *szValue, int nMethod, int bSkipDeleted)
|
|
{
|
|
for (MoveFirst(bSkipDeleted); !IsEOF(); MoveNext(bSkipDeleted))
|
|
{
|
|
TCString sValue;
|
|
GET_FIELD(this, szKey, sValue);
|
|
|
|
int bEqual = 0;
|
|
if (nMethod == CMP_SENSITIVE)
|
|
{
|
|
bEqual = (_tcscmp(szValue, sValue) == 0);
|
|
}
|
|
else
|
|
{
|
|
bEqual = (_tcsicmp(szValue, sValue) == 0);
|
|
}
|
|
|
|
if (bEqual)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int DbfTable::MoveFirst(const TCHAR *szKey, const TCHAR *szValue, int nMethod, int bSkipDeleted)
|
|
{
|
|
return MoveTo(szKey, szValue, nMethod, bSkipDeleted);
|
|
}
|
|
|
|
int DbfTable::MoveNext(const TCHAR *szKey, const TCHAR *szValue, int nMethod, int bSkipDeleted)
|
|
{
|
|
for (MoveNext(bSkipDeleted); !IsEOF(); MoveNext(bSkipDeleted))
|
|
{
|
|
TCString sValue;
|
|
GET_FIELD(this, szKey, sValue);
|
|
|
|
int bEqual = 0;
|
|
if (nMethod == CMP_SENSITIVE)
|
|
{
|
|
bEqual = (_tcscmp(szValue, sValue) == 0);
|
|
}
|
|
else
|
|
{
|
|
bEqual = (_tcsicmp(szValue, sValue) == 0);
|
|
}
|
|
|
|
if (bEqual)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
long DbfTable::GetPosition()
|
|
{
|
|
return d4recno(this)-1;
|
|
}
|
|
|
|
int DbfTable::IsDeleted()
|
|
{
|
|
return d4deleted(this);
|
|
}
|
|
|
|
BOOL DbfTable::operator !()
|
|
{
|
|
return (IsEOF() || IsBOF());
|
|
}
|
|
|
|
int FieldContent::CompareTo(const FieldContent &otherOne) const
|
|
{
|
|
if (GetFieldType() != otherOne.GetFieldType())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
char cType = GetFieldType();
|
|
if (cType == r4num)
|
|
{
|
|
if (f4decimals((FIELD4 *)this) == 0)
|
|
{
|
|
int n1 = *this, n2 = otherOne;
|
|
if (n1 > n2)
|
|
{
|
|
return 1;
|
|
}
|
|
else if (n1 < n2)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
double n1 = *this, n2 = otherOne;
|
|
if (n1 > n2)
|
|
{
|
|
return 1;
|
|
}
|
|
else if (n1 < n2)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else if (cType == r4str || cType == r4date || cType == r4log)
|
|
{
|
|
const TCHAR * s1 = *this, *s2 = otherOne;
|
|
return _tcscmp(s1, s2);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 求总记录数
|
|
long DbfTable::GetRecordCount(int bSkipDeleted)
|
|
{
|
|
if (!bSkipDeleted)
|
|
{
|
|
return d4reccount(this);
|
|
}
|
|
|
|
long lCount = 0;
|
|
for (MoveFirst(); !IsEOF(); MoveNext())
|
|
{
|
|
lCount ++;
|
|
}
|
|
|
|
return lCount;
|
|
}
|
|
|
|
void FieldInfo::ReleaseArray(FieldInfo *p)
|
|
{
|
|
u4free(p);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// FieldContent
|
|
TCHAR FieldContent::szValue[256] = _T("");
|
|
FieldContent::FieldContent()
|
|
{
|
|
|
|
}
|
|
|
|
FieldContent::operator int () const
|
|
{
|
|
return f4int((FIELD4 *)this);
|
|
}
|
|
|
|
FieldContent::operator double () const
|
|
{
|
|
return f4double((FIELD4 *)this);
|
|
}
|
|
|
|
FieldContent::operator float () const
|
|
{
|
|
return (float)f4double((FIELD4 *)this);
|
|
}
|
|
|
|
FieldContent::operator const TCHAR * () const
|
|
{
|
|
#ifdef _UNICODE
|
|
char buf[256];
|
|
TGh1cpy(buf, f4str((FIELD4 *)this));
|
|
_tcscpy(szValue,TString(buf));
|
|
#else
|
|
TGh1cpy(szValue, f4str((FIELD4 *)this));
|
|
#endif
|
|
return (const TCHAR *)szValue;
|
|
}
|
|
|
|
char FieldContent::GetFieldType() const
|
|
{
|
|
return f4type((FIELD4 *)this);
|
|
}
|
|
|
|
FieldContent & FieldContent::operator = (int i)
|
|
{
|
|
f4assign_int(this, i);
|
|
return *this;
|
|
}
|
|
|
|
FieldContent & FieldContent::operator = (double d)
|
|
{
|
|
f4assign_double(this, d);
|
|
return *this;
|
|
}
|
|
|
|
FieldContent & FieldContent::operator = (const TCHAR *str)
|
|
{
|
|
f4assign(this, (char *)_AS(str));
|
|
return *this;
|
|
}
|
|
|
|
#ifdef __AFXDISP_H__
|
|
// 能正确正确转换的类型: int, double, string, date
|
|
COleVariant FieldContent::AsVariant() const
|
|
{
|
|
COleVariant res;
|
|
char cType=GetFieldType();
|
|
if (cType == r4num)
|
|
{
|
|
if (f4decimals((FIELD4 *)this) == 0)
|
|
{
|
|
res = (long)f4int((FIELD4 *)this);
|
|
}
|
|
else
|
|
{
|
|
res = f4double((FIELD4 *)this);
|
|
}
|
|
}
|
|
else if (cType == r4str)
|
|
{
|
|
const TCHAR* s1 = *this;
|
|
ASSERT(s1 != NULL);
|
|
res = s1;
|
|
}
|
|
else if (cType == r4log)
|
|
{
|
|
res = (long)f4int((FIELD4 *)this);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
FieldContent & FieldContent::operator = (const COleVariant &src)
|
|
{
|
|
int nOleType = V_VT(&src);
|
|
switch(nOleType)
|
|
{
|
|
case VT_BSTR:
|
|
{
|
|
CString cs = V_BSTR(&src);
|
|
const TCHAR *sz = cs;
|
|
*this = sz;
|
|
}
|
|
break;
|
|
case VT_DATE:
|
|
{
|
|
COleDateTime oleDate = V_DATE(&src);
|
|
int nYear = oleDate.GetYear(),
|
|
nMonth = oleDate.GetMonth(),
|
|
nDay = oleDate.GetDay();
|
|
long nDate = nYear * 10000 + nMonth * 100 + nDay;
|
|
TCString sDate(_T("%ld"), nDate);
|
|
*this = sDate;
|
|
}
|
|
break;
|
|
case VT_I4:
|
|
{
|
|
long n1 = V_I4(&src);
|
|
*this = (int)n1;
|
|
}
|
|
break;
|
|
case VT_I2:
|
|
{
|
|
short n1 = V_I2(&src);
|
|
*this = (int)n1;
|
|
}
|
|
break;
|
|
case VT_R8:
|
|
{
|
|
double n1 = V_R8(&src);
|
|
*this = n1;
|
|
}
|
|
break;
|
|
case VT_R4:
|
|
{
|
|
float n1 = V_R4(&src);
|
|
*this = (double)n1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
int TARCH_IMPEXP CompareVariant(const COleVariant &var1, const COleVariant &var2)
|
|
{
|
|
int nType1 = V_VT(&var1), nType2 = V_VT(&var2);
|
|
int nRes = 0;
|
|
if (nType1 == nType2)
|
|
{
|
|
if (nType1 == VT_BSTR)
|
|
{
|
|
CString s1 = V_BSTR(&var1);
|
|
CString s2 = V_BSTR(&var2);
|
|
nRes = _tcscmp(s1, s2);
|
|
}
|
|
else if (nType1 == VT_DATE)
|
|
{
|
|
double d1 = V_DATE(&var1), d2 = V_DATE(&var2);
|
|
int nD1 = (int)d1, nD2 = (int)d2;
|
|
nRes = Compare(nD1, nD2);
|
|
}
|
|
else if (nType1 == VT_I4)
|
|
{
|
|
long n1 = V_I4(&var1), n2 = V_I4(&var2);
|
|
nRes = Compare(n1, n2);
|
|
}
|
|
else if (nType1 == VT_I2)
|
|
{
|
|
short n1 = V_I2(&var1), n2 = V_I2(&var2);
|
|
nRes = Compare(n1, n2);
|
|
}
|
|
else if (nType1 == VT_R8)
|
|
{
|
|
double n1 = V_R8(&var1), n2 = V_R8(&var2);
|
|
nRes = Compare(n1, n2);
|
|
}
|
|
else if (nType1 == VT_R4)
|
|
{
|
|
float n1 = V_R4(&var1), n2 = V_R4(&var2);
|
|
nRes = Compare(n1, n2);
|
|
}
|
|
}
|
|
|
|
return nRes;
|
|
}
|
|
|
|
// 比较两行的大小
|
|
int TARCH_IMPEXP CompareBookmark(COleVariant *g_lstSortFieldContents, const long *bookmark1, const long *bookmark2)
|
|
{
|
|
COleVariant &var1 = g_lstSortFieldContents[(int)(*bookmark1)],
|
|
&var2 = g_lstSortFieldContents[(int)(*bookmark2)];
|
|
|
|
return CompareVariant(var1, var2);
|
|
}
|
|
#endif
|
|
|
|
// 修改: 可以改多个记录
|
|
// 查询: 仅列出最后一个满足条件的记录
|
|
int
|
|
DBFFUN(DbfAccess &kz)
|
|
{
|
|
CodeBase code_base;
|
|
code_base.exclusive = (kz.flag == FLAG_PACK ? 1 : 0);
|
|
|
|
DATA4 *table = code_base.Open(kz.dbfname);
|
|
if (table == NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if (kz.flag == FLAG_PACK)
|
|
{
|
|
d4pack(table);
|
|
return 0;
|
|
}
|
|
|
|
FIELD4 *field;
|
|
int i,len;
|
|
char buf[150] = "", buf1[150] = "";
|
|
FILE *ftext = NULL;
|
|
int retFlag = 0;
|
|
|
|
int dbflen = d4num_fields(table);
|
|
|
|
// 由字段名换算字段序号
|
|
int *keyindex = kz.keynum > 0 ? new int [kz.keynum] : NULL; //如果不指定关键字则查询全部记录
|
|
int *dataindex = kz.datanum > 0 ? new int [kz.datanum] : NULL;
|
|
for (int k = 0; k < kz.keynum; k++)
|
|
{
|
|
if ((keyindex[k] = d4field_number(table, kz.keyFieldName[k])) <= 0)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
for (k = 0; k < kz.datanum; k++)
|
|
{
|
|
if ((dataindex[k] = d4field_number(table, kz.dataFieldName[k])) <= 0)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int isExist = 0;
|
|
if (kz.flag == FLAG_READ || kz.flag == FLAG_WRITE || kz.flag == FLAG_DELETE) // read or modify
|
|
{
|
|
if (kz.flag == FLAG_READ)
|
|
{
|
|
if ((ftext = fopen(kz.resFileName,"w")) == NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
for (d4top(table); !d4eof(table); d4skip(table, 1L))
|
|
{
|
|
if (d4deleted(table))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (i = 0; i < kz.keynum; i++)
|
|
{
|
|
if (keyindex[i] > dbflen)
|
|
{
|
|
if (!kz.flag)
|
|
{
|
|
fclose(ftext);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
field = d4field_j(table,keyindex[i]);
|
|
|
|
// 局部比较, 当最后一字符为*时
|
|
int iLen = strlen(kz.keyinfo[i]);
|
|
int locCmp = (iLen >= 1 && kz.keyinfo[i][iLen - 1] == '*');
|
|
|
|
len = locCmp ? (iLen - 1) : f4len(field);
|
|
TGh3cpy(buf,kz.keyinfo[i],len);
|
|
TGh3cpy(buf1,f4str(field),len);
|
|
if (memcmp(buf,buf1,len))
|
|
{
|
|
break; //本行不满足查询条件
|
|
}
|
|
}
|
|
|
|
if (i == kz.keynum) // Find
|
|
{
|
|
isExist = 1;
|
|
if (kz.flag == FLAG_WRITE) // Write
|
|
{
|
|
for (i = 0; i < kz.datanum; i++)
|
|
{
|
|
if (dataindex[i] > dbflen)
|
|
{
|
|
exit(0);
|
|
}
|
|
|
|
field = d4field_j(table,dataindex[i]);
|
|
len = f4len(field);
|
|
|
|
TGh2cpy(buf,kz.dataIn[i],len);
|
|
if (f4type(field)==r4num && buf[0]) //数值型
|
|
{
|
|
double f = atof(buf);
|
|
f4assign_double(field,f);
|
|
}
|
|
else
|
|
{
|
|
f4assign(field,kz.dataIn[i]);
|
|
}
|
|
}
|
|
|
|
d4flush(table);
|
|
d4unlock(table);
|
|
}
|
|
else if (kz.flag == FLAG_READ) // Read
|
|
{
|
|
for (i = 0; i < kz.datanum; i++)
|
|
{
|
|
if (dataindex[i] > dbflen)
|
|
{
|
|
fclose(ftext);
|
|
exit(0);
|
|
}
|
|
|
|
field = d4field_j(table,dataindex[i]);
|
|
len = f4len(field);
|
|
|
|
TGh1cpy(buf,f4str(field));
|
|
fprintf(ftext,"\"%s\" ",buf);
|
|
}
|
|
|
|
fprintf(ftext,"\n");
|
|
}
|
|
else if (kz.flag == FLAG_DELETE)
|
|
{
|
|
d4delete(table);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ftext && kz.flag == FLAG_READ)
|
|
{
|
|
fclose(ftext);
|
|
}
|
|
}
|
|
|
|
|
|
if (kz.flag == FLAG_APPEND || (kz.flag == FLAG_WRITE && !isExist))
|
|
{
|
|
d4append_start(table,0);
|
|
d4blank(table);
|
|
|
|
for (i = 0; i < kz.datanum; i++)
|
|
{
|
|
if (dataindex[i] > dbflen)
|
|
{
|
|
exit(0);
|
|
}
|
|
|
|
field = d4field_j(table,dataindex[i]);
|
|
len = f4len(field);
|
|
|
|
TGh2cpy(buf,kz.dataIn[i],len);
|
|
if (f4type(field) == r4num && buf[0]) //数值型
|
|
{
|
|
double f = atof(buf);
|
|
f4assign_double(field,f);
|
|
}
|
|
else
|
|
{
|
|
f4assign(field,kz.dataIn[i]);
|
|
}
|
|
}
|
|
|
|
retFlag = d4append(table);
|
|
d4flush(table);
|
|
d4unlock(table);
|
|
}
|
|
|
|
if (keyindex)
|
|
{
|
|
delete keyindex;
|
|
}
|
|
|
|
if (dataindex)
|
|
{
|
|
delete dataindex;
|
|
}
|
|
return retFlag;
|
|
}
|
|
|
|
// keynum >=0 and datanum >0
|
|
DbfAccess:: DbfAccess(const TCHAR *tabName, int isWrite, int kn, int dn)
|
|
: flag(isWrite), keynum(kn), datanum(dn)
|
|
{
|
|
_tcscpy(dbfname, tabName);
|
|
if (keynum < 0 || datanum < 0)
|
|
{
|
|
exit(1);
|
|
}
|
|
|
|
keyFieldName = keynum > 0 ? new char * [keynum] : NULL;
|
|
keyinfo = keynum > 0 ? new char * [keynum] : NULL;
|
|
for (int i = 0; i < keynum; i++)
|
|
{
|
|
keyFieldName[i] = keyinfo[i] = NULL;
|
|
}
|
|
|
|
dataFieldName = datanum > 0 ? new char * [datanum] : NULL;
|
|
for (i = 0; i < datanum; i++)
|
|
{
|
|
dataFieldName[i] = NULL;
|
|
}
|
|
|
|
if (flag == FLAG_WRITE || flag == FLAG_APPEND) // write append
|
|
{
|
|
dataIn = new char * [datanum];
|
|
for (i = 0; i < datanum; i++)
|
|
{
|
|
dataIn[i] = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dataIn = NULL;
|
|
resFileName = NULL;
|
|
}
|
|
}
|
|
|
|
/******************* DbfAccess *****************/
|
|
DbfAccess:: ~DbfAccess()
|
|
{
|
|
for (int i = 0; i < keynum; i++)
|
|
{
|
|
if (keyFieldName[i])
|
|
{
|
|
free(keyFieldName[i]);
|
|
}
|
|
|
|
if (keyinfo[i])
|
|
{
|
|
free(keyinfo[i]);
|
|
}
|
|
}
|
|
|
|
if (keyFieldName)
|
|
{
|
|
delete[] keyFieldName;
|
|
}
|
|
|
|
if (keyinfo)
|
|
{
|
|
delete[] keyinfo;
|
|
}
|
|
|
|
for (i = 0; i < datanum; i++)
|
|
{
|
|
if (dataFieldName[i])
|
|
{
|
|
free(dataFieldName[i]);
|
|
}
|
|
|
|
if (dataFieldName)
|
|
{
|
|
delete[] dataFieldName;
|
|
}
|
|
|
|
if (flag == FLAG_WRITE || flag == FLAG_APPEND)
|
|
{
|
|
for (i = 0; i < datanum; i++)
|
|
{
|
|
if (dataIn[i])
|
|
{
|
|
free(dataIn[i]);
|
|
}
|
|
}
|
|
|
|
if (dataIn)
|
|
{
|
|
delete[] dataIn;
|
|
}
|
|
}
|
|
else if (flag == FLAG_READ)
|
|
{
|
|
if (resFileName)
|
|
{
|
|
free(resFileName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned _stklen = 30000U;
|
|
|
|
static int IsDigit(const char *str)
|
|
{
|
|
int len = strlen(str);
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
if (!isdigit(str[i]))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int operator == (TCStringList &strs1, TCStringList &strs2)
|
|
{
|
|
if (strs1.Length() != strs2.Length())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int len = strs1.Length();
|
|
for (int i = 0; i<len; i++)
|
|
{
|
|
if (_tcscmp(strs1[i], strs2[i]) == 0)
|
|
{
|
|
;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// bugs: if sqlCmd is very long, output fileld more than 10, conditions field>=2
|
|
// syntax: SELECT [<output Fields>]/<*> FROM <dbf file> [<condition>]
|
|
// <condition> := WHERE <field name>=<value>
|
|
// value can't be empty, but can be ''(empty string)
|
|
int TARCH_IMPEXP SqlExec(const TCHAR *sqlcmd, const TCHAR *quiryOut, TDPtrList<TCStringList> *res)
|
|
{
|
|
if (!sqlcmd)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
TSqlQuiry cmd;
|
|
int i = 1;
|
|
|
|
int from = 0, where = 0;
|
|
TCString word(256);
|
|
while (GetStringAtIndex(sqlcmd, i, word))
|
|
{
|
|
if (i==1)
|
|
{
|
|
if (_tcsicmp(word, _T("SELECT")) != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else if (!from && _tcsicmp(word, _T("from")) == 0)
|
|
{
|
|
from = 1;
|
|
}
|
|
else if (!where && _tcsicmp(word, _T("where")) == 0)
|
|
{
|
|
where = 1;
|
|
}
|
|
else
|
|
{
|
|
if (!from) // Specify OutPut field
|
|
{
|
|
if (_tcsicmp(word, _T("DISTINCT")) == 0)
|
|
{
|
|
cmd.isDistinct = 1;
|
|
}
|
|
else
|
|
{
|
|
cmd.outputFields.Append(tstrnew(word));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!where && !cmd.dbfFile)
|
|
{
|
|
cmd.dbfFile = word;
|
|
}
|
|
else if (where) // Condtion is here
|
|
{
|
|
const char *pstr;
|
|
char fieldKey[80] = "", fieldValue[256] = "";
|
|
DataCompare cp;
|
|
|
|
TAString aword(word);
|
|
if ((pstr = strstr(aword, ">=")))
|
|
{
|
|
int n = 0;
|
|
for (const char *p = aword; p != pstr; p++, n++)
|
|
{
|
|
fieldKey[n] = *p;
|
|
}
|
|
|
|
fieldKey[n] = 0;
|
|
strcpy(fieldValue, p+2);
|
|
cp = GREAT_EQUAL;
|
|
}
|
|
else if ((pstr = strchr(aword, '>')))
|
|
{
|
|
int n = 0;
|
|
for (const char *p = aword; p != pstr; p++, n++)
|
|
{
|
|
fieldKey[n] = *p;
|
|
}
|
|
|
|
fieldKey[n] = 0;
|
|
strcpy(fieldValue, p+1);
|
|
cp = GREAT;
|
|
}
|
|
else if ((pstr = strstr(aword, "<=")))
|
|
{
|
|
int n = 0;
|
|
for (const char *p = aword; p != pstr; p++, n++)
|
|
{
|
|
fieldKey[n] = *p;
|
|
}
|
|
|
|
fieldKey[n] = 0;
|
|
strcpy(fieldValue, p+2);
|
|
cp = LITTLE_EQUAL;
|
|
}
|
|
else if ((pstr = strchr(aword, '<')))
|
|
{
|
|
int n = 0;
|
|
for (const char *p = aword; p != pstr; p++, n++)
|
|
{
|
|
fieldKey[n] = *p;
|
|
}
|
|
|
|
fieldKey[n] = 0;
|
|
strcpy(fieldValue, p+1);
|
|
cp = LITTLE;
|
|
}
|
|
else if ((pstr = strstr(aword, "!=")))
|
|
{
|
|
int n = 0;
|
|
for (const char *p = aword; p != pstr; p++, n++)
|
|
{
|
|
fieldKey[n] = *p;
|
|
}
|
|
|
|
fieldKey[n] = 0;
|
|
strcpy(fieldValue, p+2);
|
|
cp = NOT_EQUAL;
|
|
}
|
|
else if ((pstr = strchr(aword, '=')))
|
|
{
|
|
int n = 0;
|
|
for (const char *p = aword; p != pstr; p++, n++)
|
|
{
|
|
fieldKey[n] = *p;
|
|
}
|
|
|
|
fieldKey[n] = 0;
|
|
strcpy(fieldValue, p+1);
|
|
cp = EQUAL;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (!fieldKey[0] || !fieldValue[0])
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
TSqlCondition *condPtr = new TSqlCondition;
|
|
condPtr->fieldName = fieldKey;
|
|
condPtr->opr = cp;
|
|
|
|
int nLen = strlen(fieldValue);
|
|
if (fieldValue[0] == '\'' && nLen > 1 && fieldValue[nLen-1] == '\'')
|
|
{
|
|
condPtr->type = SQL_CHAR;
|
|
char str[256];
|
|
strcpy(str, &fieldValue[1]);
|
|
str[strlen(str) - 1] = 0;
|
|
condPtr->rstring = _strdup(str);
|
|
}
|
|
else if (IsDigit(fieldValue))
|
|
{
|
|
condPtr->type = SQL_INT;
|
|
condPtr->rint = atoi(fieldValue);
|
|
}
|
|
else if (strchr(fieldValue, '.'))
|
|
{
|
|
condPtr->type = SQL_REAL;
|
|
condPtr->rreal= atof(fieldValue);
|
|
}
|
|
else
|
|
{
|
|
condPtr->type = SQL_CHAR;
|
|
condPtr->rstring = _strdup(fieldValue);
|
|
}
|
|
|
|
cmd.conditions.Append(condPtr);
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (cmd.Execute())
|
|
{
|
|
if (quiryOut)
|
|
{
|
|
#if (ADS > 15)
|
|
std::
|
|
#endif
|
|
ofstream fileOut(quiryOut);
|
|
cmd.QuiryOut(fileOut);
|
|
}
|
|
|
|
if (res)
|
|
{
|
|
res->Reset();
|
|
int len = cmd.outbuf.Length();
|
|
for (int k = 0; k < len; k++)
|
|
{
|
|
TCStringList *strList = new TCStringList;
|
|
*strList = *cmd.outbuf[k];
|
|
res->Append(strList);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
return 0;
|
|
} |