⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 table.cpp

📁 用CJ60Lib界面库制作的SQL数据库客户与服务器程序。
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// 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 + -