📄 table.cpp
字号:
// Table.cpp : implementation file
//
#include "stdafx.h"
#include "miniSQL.h"
#include "MainFrm.h"
#include "Table.h"
#include "SelDoc.h"
#include "SelView.h"
#include "BPTree.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
extern CMiniSQLApp theApp;
//////////////////////////////////////////////////////////////
// CEntry
//////////////////////////////////////////////////////////////
// Macro used in table.cpp
#define for_each_REC(DO) { \
CEntry REC( attr.attr ); \
for( long NO = tableAPI->FirstRec(); NO != -1; \
NO = tableAPI->NextRec(NO) ) { \
tableAPI->ReadRec( NO, &REC ); \
{ DO } } }
#define for_each_RES(DO) { \
CEntry REC( attr.attr ); \
long NO; \
for( int i = 0; i < RES.GetCount(); i++ ){ \
tableAPI->ReadRec( NO = RES.GetAt( RES.FindIndex(i) ), &REC ); \
{ DO } } }
#define for_each_BPT(DO) { \
for( int i = attr.index_num - 1; i >= 0; i-- ){ \
CBPTree BPT( attr.index_table[i] ); \
{ DO } } }
#define IEtoE( IE, E ) \
CEntryAttr E##NA( convert( IE.first ) ); \
E##NA.rearrange(); \
CEntry E( E##NA ); \
convert( E, IE );
//////////////////////////////////////////////////////////////
void CEntryAttr::push( const CItemAttr& item )
{
if( num == FIELD_NUM - 1 )
throw Error( FIELD_NUM_EXCEED, FIELD_NUM, CString(" ") );
attr[ num++ ] = item;
}
void CEntryAttr::rearrange()
{
int i;
for( length = i = 0; i < num; i++ )
attr[i].offset = length, length += attr[i].type.size;
}
int CEntryAttr::index( const char* str ) const
{
for( int i = num - 1; i >= 0; i-- )
if( !::strncmp( attr[i].name, str, FIELD_NAME_LEN ) )
break;
return i;
}
//////////////////////////////////////////////////////////////
// CValue
CValue::~CValue()
{
}
void CValue::in( const double& num )
{
GET_NULL( ptr ) = false;
switch( type.id )
{
case _INT : GET_INT( ptr ) = (int)num; break;
case _LONG : GET_LONG( ptr ) = (long)num; break;
case _FLOAT : GET_FLOAT( ptr ) = num; break;
case _DATE : GET_DATE( ptr ) = (long)num; break;
default : throw Error( IN_TYPE_ERROR, (int)type.id, CString("") );
}
}
void CValue::out( double& num ) const
{
if( GET_NULL( ptr ) )
return;
switch( type.id )
{
case _INT : num = GET_INT( ptr ); break;
case _LONG : num = GET_LONG( ptr ); break;
case _FLOAT : num = GET_FLOAT( ptr ); break;
case _DATE : num = GET_DATE( ptr ); break;
default : throw Error( OUT_TYPE_ERROR, (int)type.id, CString("") );
}
}
void CValue::in( const char* str )
{
if( *str == -1 )
{
GET_NULL( ptr ) = true;
return;
}
GET_NULL( ptr ) = false;
switch( type.id )
{
case _INT :
case _LONG :
case _FLOAT :
{
double temp;
if( ::sscanf( str, "%lf", &temp ) != 1 )
throw Error( IN_VALUE_ERROR, 0, str );
in( temp );
break;
}
case _STRING :
{
size_t size = type.size - sizeof( bool ) - 1;
strncpy( GET_STR( ptr ), str, size );
GET_STR( ptr )[size] = 0;
break;
}
case _DATE :
{
struct tm temp;
if( ::sscanf( str, "%d/%d/%d",
&temp.tm_year, &temp.tm_mon, &temp.tm_mday ) != 3 )
throw Error( IN_VALUE_ERROR, 0, str );
temp.tm_hour = temp.tm_min = temp.tm_sec = temp.tm_isdst = 0;
temp.tm_mon--; //month starts from 0
temp.tm_year -= 1900; //year starts from 1900
if( ( GET_DATE( ptr ) = ::mktime( &temp ) ) == -1 ) //change into time_t
throw Error( IN_VALUE_ERROR, 0, str );
break;
}
default : throw ( IN_TYPE_ERROR, (int)type.id, CString("") );
}
}
void CValue::out( char* str, size_t n ) const
{
CString sstr;
if( GET_NULL( ptr ) )
{
strncpy( str, "<NULL>", n );
str[ n - 1 ] = '\0';
return;
}
switch( type.id )
{
case _INT :
case _LONG :
case _FLOAT :
{
double num;
out( num );
sstr.Format( "%g", num );
strncpy( str, (LPTSTR)(LPCTSTR) sstr, n );
str[ n - 1 ] = '\0';
break;
}
case _STRING :
{
strncpy( str, GET_STR( ptr ), n );
str[ n - 1 ] = '\0';
break;
}
case _DATE :
{
struct tm *tmptr = localtime( &GET_DATE( ptr ) );
sstr.Format( "%d/%d/%d",
tmptr->tm_year + 1900, tmptr->tm_mon + 1, tmptr->tm_mday );
strncpy( str, (LPTSTR)(LPCTSTR) sstr, n );
str[ n - 1 ] = '\0';
break;
}
default : throw Error( OUT_TYPE_ERROR, (int)type.id, CString("") );
}
if( strlen( str ) >= n )
throw Error( OUT_VALUE_ERROR, 0, str );
}
bool CValue::operator < ( const CValue& rhs ) const
{
if( this->type.id != rhs.type.id )
throw Error( TYPE_MATCH_ERROR, 0, CString("") );
if( this->null() || rhs.null() )
return !this->null() && rhs.null();
if( this->type.id == _STRING )
return strcmp( GET_STR( this->ptr ), GET_STR( rhs.ptr ) ) < 0;
else
{
double an, bn;
this->out( an );
rhs.out( bn );
return an < bn;
}
}
bool CValue::operator == ( const CValue& rhs ) const
{
if( this->type.id != rhs.type.id )
throw Error( TYPE_MATCH_ERROR, 0, CString("") );
if( this->null() || rhs.null() )
return this->null() && rhs.null();
if( this->type.id == _STRING )
return !strcmp( GET_STR( this->ptr ), GET_STR( rhs.ptr ) );
else
{
double an, bn;
this->out( an );
rhs.out( bn );
return an == bn;
}
}
//////////////////////////////////////////////////////////////
// CEntry
bool CEntry::operator < ( const CEntry& rhs ) const
{
int i, j;
for( i = j = 0; i < this->attr.num && j < rhs.attr.num; i++, j++ )
{
if( (*this)[i] < rhs[j] )
return true;
if( rhs[j] < (*this)[i] )
return false;
}
return i == this->attr.num && j != rhs.attr.num;
}
bool CEntry::operator == ( const CEntry& rhs ) const
{
if( this->attr.num != rhs.attr.num )
return false;
for( int i = 0; i < this->attr.num; i++ )
if( !( (*this)[i] == rhs[i] ) )
return false;
return true;
}
//////////////////////////////////////////////////////////////
// CTable
CTable::CTable( const char* tname, const CEntryAttr& rattr )
{
m_tname = tname;
attr.attr = rattr;
attr.index_num = 0;
attr.attr.rearrange();
tableAPI = new CFileAPI( tname, ".msl", attr.attr.length, sizeof( CTableAttr ), true );
SaveAttr();
}
CTable::CTable( const char* tname )
{
m_tname = tname;
tableAPI = new CFileAPI( tname, ".msl" );
LoadAttr();
//check index
for( int i = attr.index_num - 1; i >= 0; i-- )
{
CFileStatus status;
CString path = theApp.dir;
path = path + "\\" + attr.index_table[i] + ".bpt";
if( !CFile::GetStatus( path, status ) )
{
CString str;
str.Format( "The index \"%s.bpt\" is not existed.\nMaybe the file is removed or corrupted!",
attr.index_table[i] );
AfxMessageBox( str, MB_OK | MB_ICONSTOP );
remove_index( attr.index_table[i] );
CMainFrame* pMainFrm = ( CMainFrame* )AfxGetMainWnd();
pMainFrm->m_FileBar.DropIndex( tname, attr.index_table[i] );
}
}
}
CTable::~CTable()
{
if( tableAPI )
{
SaveAttr();
delete tableAPI;
}
}
CEntryAttr CTable::convert( const STR_LIST& name_list )
{
if( !name_list.GetCount() )
return attr.attr;
CEntryAttr ret;
for( int i = 0; i < name_list.GetCount(); i++ )
ret.push( attr.attr.attr[ attr.attr.index( (LPCTSTR)name_list.GetAt( name_list.FindIndex( i ) ) ) ] );
return ret;
}
void CTable::convert( CEntry& E, const STR_PAIR& IE )
{
if( !IE.first.GetCount() )
{
if( IE.second.GetCount() != attr.attr.num )
throw Error( ERROR_ATTR_NUM, attr.attr.num, _T("") );
for( int i = 0; i < attr.attr.num; i++ )
E[i].in( (LPCTSTR)IE.second.GetAt( IE.second.FindIndex(i) ) );
}
else
for( int i = 0; i < IE.first.GetCount(); i++ )
E[ IE.first.GetAt( IE.first.FindIndex(i) ) ].in(
(LPCTSTR)IE.second.GetAt( IE.second.FindIndex(i) ) );
}
void CTable::insert( const STR_PAIR& IE )
{
CEntry E( attr.attr );
convert( E, IE );
long pos = tableAPI->AllocRec();
tableAPI->WriteRec( pos, &E );
for_each_BPT( BPT.insert( E, pos ); )
}
void CTable::close()
{
tableAPI->Close();
delete tableAPI;
tableAPI = 0;
}
void CTable::drop()
{
for( int i = attr.index_num - 1; i >= 0; i-- )
drop_index( attr.index_table[i] );
tableAPI->Drop();
delete tableAPI;
tableAPI = 0;
}
void CTable::search( RESULT& res )
{
Message("Using sequential search!");
for( long NO = tableAPI->FirstRec(); NO != -1; NO = tableAPI->NextRec(NO) )
res.AddTail( NO );
}
void CTable::search( RESULT& res, const STR_PAIR& equ )
{
IEtoE( equ, entry );
for_each_BPT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -