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

📄 selectexe.c

📁 一个c语言开发的小型的dbms系统
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#include "struct.h"

#define	BUFSIZE 1024	//缓冲区大小
#define TABNUM	20		//最大的表数目
#define COLNUM	100		//最大的列数目
#define	CONNUM	20		//最大的条件数目

int		is_a_table_dropped(char *table);
void	ReadARecord(char *Buff,struct _fieldval *fv);//读一条记录
int		Condition();								//处理where子句
int		init();										//初始化函数
int		destory();									//结束处理函数
int		GetTabID(char *tname);						//从表字典表得到表id
int		GetTabAddr(char *tname);					//从表字典表得到表在数据文件中得起始块地址
int		GetTabColNum(char *tname);					//从表字典表得到表中字段数目
int		GetTabRowNum(char *tname);					//从表字典表得到表中元组个数
int		GetTabRowLen(char *tname);					//从表字典表得到表中元组的实际存储长度
char *	GetTabName(int tid);						//从表字典表得到表名
int		GetColID(char *fname);						//从列字典表得到字段id
int		GetColType(int fid);						//从列字典表得到字段类型
char *	GetColName(int fid);						//从列字典表得到字段名
int		GetColTabID(int fid);						//从列字典表得到字段所在表的表id
int		LocateTField(int fid);							
FILE	*CreateTmpFile(char *FileName);				//返回临时文件名
int		Pretreat(char *tname);						//单表优化
char	*MergeTab(char *tname,char *tname1);		//对两个表做连接操作
int		stringcmp(const char *s1, const char *s2);	//字符串比较
//void	readdic(struct tab_dic_type *tab,int *tab_num,struct col_dic_type *col,int *col_num)

struct	tab_dic_type	TabDic[TABNUM];//={{"student",1,0,5,3,30},{"sc",2,1,3,3,20}};
struct	col_dic_type	ColDic[COLNUM];//={{1,"sname",1,1,8},{1,"sno",2,1,8},{1,"ssex",3,1,2},{1,"age",4,2,4},{1,"deptno",5,1,8},{2,"sno",6,1,8},{2,"cno",7,1,8},{2,"grade",8,2,4}};

struct	tab_dic_type	TTabDic1,TTabDic2,NullTabDic={"",0,0,0,0,0};				//template table dictionary
struct	_fieldval		*fv,Tfield[COLNUM];		//Tfield存放涉及表的所有列 
struct	_selectstruct	Tselect;	
struct  _deletestruct	Tdelete;

char	Buf[BUFSIZE];
FILE	*fp;				//数据文件指针
//FILE	fp1,fp2;
char	TabName[TABNUM][100];//涉及的表的名称
int		TfileNum;			//临时文件的数量
int		TabNum=0;			//涉及的表的数量
long	RecNum=0;			//临时表的记录数
long	ColNum=0;			//涉及的表的列数
long	TabMax,ColMax;
int		JoinField[TABNUM][2];//等值连接的列的名称
int		JoinFieldNum=0;

//select主程序
int select(struct _selectstruct *Pselect)
{
	int			i,j;
	int			ColID;
	char		*tfile;
	FILE		*tfp;
	int			selected=0;
	struct		_selectedtables	*Ptable;	
	struct		_selectedfields	*Pfield;
	char SqlBuf[256];
	int len,bufPos;

	Tselect = *Pselect;	

	//initialize,do some things suck as open file
	init();		

	//单表优化
	Pretreat(TabName[0]);		
	tfile = "Data0.tmp";

	//笛卡尔基:把多表连接转化成二元连接
	for (i=1;i<TabNum;i++)
	{
		tfile = MergeTab(TabName[i],tfile);		
	}
	if ((tfp=fopen(tfile,"ab+"))==NULL)
	{
printf("tfile\n");
		printf("Can't open data file:%s\n",tfile);
		exit(2);
	}

	//输出表头信息
	Pfield = Tselect.sf;
	if (stringcmp(Pfield->field,"*") == 0)	// field like "*"
	{
		for(i=0;i<ColNum;i++)
			printf("%s.%s\t",GetTabName(GetColTabID(Tfield[i].col_id)),GetColName(Tfield[i].col_id));
	}
	else
		while (Pfield!=NULL)
		{
			printf("%s.%s\t",Pfield->table,Pfield->field);
			Pfield = Pfield->next_sf;
		}
	printf("\n");

	//输出字段
	for (i=0;i<TTabDic2.row_num;i++)
	{
		Pfield = Tselect.sf;
		fread(Buf,TTabDic2.row_len,1,tfp);
		ReadARecord(Buf,Tfield);
		if (Condition()==1) 
		{
			//get a field chosen
			if (stringcmp(Pfield->field,"*") == 0)	//output all fields
			{
				for (j=0;j<ColNum;j++)
				{
					if (Tfield[j].type==0)
						printf("%d\t",Tfield[j].intval);
					else{
						//printf("%s\t",Tfield[j].charval);
						strcpy(SqlBuf,Tfield[j].charval);
						len=strlen(SqlBuf);
						bufPos=0;
						while(bufPos<len){
							if (SqlBuf[bufPos]=='_'){
								SqlBuf[bufPos]=' ';
							}
							if (SqlBuf[bufPos]=='#'){
								SqlBuf[bufPos]=',';
							}
							if (SqlBuf[bufPos]=='&'){
								SqlBuf[bufPos]='.';
							}
							bufPos++;
						   
						}
						printf("%s\t",SqlBuf);
					}
				}//end for
			}
			else		//choose field to output
			{
				while (Pfield!=NULL)
				{
					ColID = GetColID(Pfield->field);
					for (j=0;j<ColNum;j++)
					{
						//if field be chosen
						if (ColID == Tfield[j].col_id)
						{
							if (Tfield[j].type==0)
								printf("%d\t",Tfield[j].intval);
							else
								printf("%s\t",Tfield[j].charval);
						}	
					}//end for
					Pfield = Pfield->next_sf ;
				}
			}
			printf("\n");
			selected++;
		}//end if condition
	}//end for
	printf("\n	%d records selected!\n",selected);

	destory();
	return(0);
}

//从tfp指针所指的文件中读一条记录到fv
void ReadARecord(char *Buff,struct _fieldval *fv)
{
	int		i,*ip,num=0;

	for(i=0;i<ColNum;i++)
	{
		if (fv[i].type == 0)  
		{
			ip =(int *)(&Buff[num]);
			fv[i].intval = *ip;
			num+=5;
		}
		else
		{
			fv[i].charval = Buff+num;
			num+=fv[i].length+1;
		}
	}
}

/******************************************************************************
								处理where子句
	采用后序扁历的方法,用S[]栈存储节点(指针),Tval[]存储计算的结果,Tmp[]来标示
左右子女是否已处理过。sp为S[]和Tmp[]的指针,tp为Tval[]的指针。
*******************************************************************************/
int Condition()
{
	struct	_conditions		*S[CONNUM];
	struct	_fval			Tval[CONNUM];
	int		sp=0,tp=-1,Tmp[CONNUM];
	int		i;


	//没有条件
	if (Tselect.cons == NULL) return(1);

	//有条件: 后续遍历
	S[sp]=Tselect.cons;
	Tmp[sp] = 2;

	while (sp>=0) 
	{
		if (Tmp[sp] == 2)		//未处理节点,左子女进栈
		{
			Tmp[sp] = 1;
			S[sp+1] = S[sp]->left ;
			sp++;
			if (S[sp]->left == NULL) 
				Tmp[sp] = 0;
			else
				Tmp[sp] =2;
			continue;
		}
		else if (Tmp[sp] == 1)	//右子女进栈
		{
			Tmp[sp] = 0;
			S[sp+1] = S[sp]->right ;
			sp++;
			if (S[sp]->left == NULL) 
				Tmp[sp] = 0;
			else
				Tmp[sp] =2;
			continue;
		}
		else					//处理节点
		{
			/*	先判断comp_op操作符: 'a'(表示AND)、'o'(表示OR)、d'='、'<'、'>'等
				如果是叶节点则判断type:'3'表示子段、'1'表示字符串值、'0'表示整型值*/
			switch (S[sp]->comp_op)
			{
				case	'a':
				{
					tp--;
					if ((Tval[tp].iVal !=0) && (Tval[tp+1].iVal !=0))
						Tval[tp].iVal = 1;
					else
						Tval[tp].iVal =0;
					Tval[tp].type = 1;
					break;
				}
				case	'o':
				{
					tp--;
					if ((Tval[tp].iVal !=0) || (Tval[tp+1].iVal !=0))
						Tval[tp].iVal = 1;
					else
						Tval[tp].iVal =0;
					Tval[tp].type = 1;
					break;
				}
				case	'=':
				{
					tp--;
		//			if (Tval[tp].type != Tval[tp+1].type) printf("Error:'=' 类型不符!\n");
					if (Tval[tp+1].type==3) 
						Tval[tp+1].type=1;
					if (Tval[tp].type==3) 
						Tval[tp].type=1;
									
					switch (Tval[tp].type)
					{
						case	1:
				
							{
								if (stringcmp(Tval[tp].szVal,Tval[tp+1].szVal) == 0)
									Tval[tp].iVal = 1;
								else
									Tval[tp].iVal =0;
								break;
							}
						case	0:
							{
								if (Tval[tp].iVal == Tval[tp+1].iVal )
									Tval[tp].iVal = 1;
								else
									Tval[tp].iVal =0;
								break;
							}
						default: break;
					}
					Tval[tp].type = 1;
					break;
				}
				case	'>':
				{
					tp--;
					if (Tval[tp].type != Tval[tp+1].type) printf("Error:'>' 类型不符!\n");
					switch (Tval[tp].type)
					{
						case	1:
						
							{
								if (stringcmp(Tval[tp].szVal,Tval[tp+1].szVal) > 0)
									Tval[tp].iVal = 1;
								else
									Tval[tp].iVal =0;
								break;
							}
						case	0:
							{
								if (Tval[tp].iVal > Tval[tp+1].iVal )
									Tval[tp].iVal = 1;
								else
									Tval[tp].iVal =0;
								break;
							}
						default: break;
					}
					Tval[tp].type = 1;
					break;
				}
				case	'<':
				{
					tp--;
					if (Tval[tp].type != Tval[tp+1].type) printf("Error:'<' 类型不符!\n");
					switch (Tval[tp].type)
					{
						case	1:
							{
								if (stringcmp(Tval[tp].szVal,Tval[tp+1].szVal) < 0)
									Tval[tp].iVal = 1;
								else
									Tval[tp].iVal =0;
								break;
							}
						case	0:
							{
								if (Tval[tp].iVal < Tval[tp+1].iVal )
									Tval[tp].iVal = 1;
								else
									Tval[tp].iVal =0;
								break;
							}
						default: break;
					}
					Tval[tp].type = 1;
					break;
				}
				default:	//叶节点,把值保存下来,入Tval[]
				{
					tp++;
					switch (S[sp]->type)
					{
						case	'2':	//field:把子段名称换成相应的值
						{
							i = LocateTField(S[sp]->intval);
							if (GetColType(S[sp]->intval)==1)
							{
								Tval[tp].type = 1;
								strcpy(Tval[tp].szVal,Tfield[i].charval);
//								Tval[tp].szVal = Tfield[i].charval;
							}
							else
							{
								Tval[tp].type = 0;
								Tval[tp].iVal = Tfield[i].intval;
							}
							break;
						}
						case	'1':	//string
						{
							Tval[tp].type =1;
							strcpy(Tval[tp].szVal,S[sp]->value); 
							break;
						}
						case	'0':	//int
						{
							Tval[tp].type =0;
							Tval[tp].iVal = S[sp]->intval ;
							break;
						}
						default: break;
					}
				}
			}
			sp--;	//出栈
		}
	}

	return(Tval[0].iVal);
}

//初始化函数
int	init()
{
	struct	_selectedtables	*Ptable;	
	struct	_conditions		*Pcon,*S[255];
	int		sp=0,i;
	char	sTmp[TABNUM];
	int		iR,j;
	
	fp = NULL;			//数据文件指针
	TfileNum=0;			//临时文件的数量
	TabNum=0;			//涉及的表的数量
	RecNum=0;			//临时表的记录数
	ColNum=0;			//涉及的表的列数
	TabMax = 0;
	ColMax = 0;
	for (i=0;i<BUFSIZE;i++) Buf[i]=0;
    for (i=0;i<TABNUM;i++)	strcpy(TabName[i],"");//涉及的表的名称

	read_dic(TabDic,&TabMax,ColDic,&ColMax);

	//初始化表名
	Ptable = Tselect.st;
	while (Ptable != NULL) 
	{
		strcpy(TabName[TabNum++],Ptable->table);
		Ptable = Ptable->next_st ;
	}

	//选择记录数少的作为驱动表
	iR = GetTabRowNum(TabName[0]);
	strcpy(sTmp,TabName[0]);
	for (i=0,j=0;i<TabNum;i++)
		if (GetTabRowNum(TabName[i]) < iR) 
		{
			iR = GetTabRowNum(TabName[i]);
			j = i;
		}
	strcpy(TabName[0],TabName[j]);
	strcpy(TabName[j],sTmp);
	
	/*初始化where子句中涉及的字段
	  采用广度扁历的方法*/
	Pcon = Tselect.cons;
	if (Pcon != NULL) 
	{
		S[sp] = Pcon;
		while (sp>=0)
		{
			Pcon = S[sp];
			if (Pcon->left != NULL)		//非叶节点
			{
				S[sp] = Pcon->right ;
				S[++sp] = Pcon->left ;
				switch (Pcon->comp_op)
				{
					case '=':
					{
						if (Pcon->left->type == '0' && Pcon->right->type == '0' && stringcmp(Pcon->left->value,Pcon->right->value)==0 )
						{
							JoinField[JoinFieldNum][0] = GetColID(Pcon->left->value);
							JoinField[JoinFieldNum][1] = GetColID(Pcon->right->value);
							JoinFieldNum++;
						}
						break;
					}
					case 'a':
					{
						if (Pcon->left->type == '0' && Pcon->right->type !=0)
						{
							;
						}
						break;
					}
					default:
					{
					}
				}
			}
			else					//叶节点
			{
				if (S[sp]->type == '2')
				{
					for (i=0;i<ColMax;i++)
						if (stringcmp(S[sp]->value,ColDic[i].col_name)==0)
						{
							if (S[sp]->table != NULL)
							{
								if (ColDic[i].tab_id == GetTabID(S[sp]->table))
								{
									S[sp]->intval = ColDic[i].col_id;
									S[sp]->table = GetTabName(GetColTabID(ColDic[i].col_id));
									break;
								}
							}
							else
							{
								S[sp]->intval = ColDic[i].col_id;
								break;
							}
						}
	
				}
				sp--;
			}
		}
	}

	TTabDic1 = NullTabDic;
	TTabDic2 = NullTabDic;

	//open data file
	if ((fp=fopen("DATABASE","ab+"))==NULL)
	{
	
		printf("Can't open data file\n");
		exit(1);
	}

	return(0);
}

//结束处理函数
int destory()
{
	fclose(fp);
}

//从表字典表得到表id
int		GetTabID(char *tname)
{
	int		i,j=0;
	for (i=0;i<TabMax;i++)
		if (stringcmp(tname,TabDic[i].tab_name)==0)
		{
			j = TabDic[i].tab_id;
			break;
		}
	return(j);
}

//从表字典表得到表在数据文件中得起始块地址
int		GetTabAddr(char *tname)
{
	int		i,j=0;
	for (i=0;i<TabMax;i++)
		if (stringcmp(tname,TabDic[i].tab_name)==0)
		{
			j = TabDic[i].first_free_block;
			break;
		}
	return(j);
}

//从表字典表得到表中字段数目
int		GetTabColNum(char *tname)
{
	int		i,j=0;
	for (i=0;i<TabMax;i++)
		if (stringcmp(tname,TabDic[i].tab_name)==0)
		{
			j = TabDic[i].col_num;
			break;
		}
	return(j);
}

//从表字典表得到表中元组个数
int		GetTabRowNum(char *tname)
{
	int		i,j=0;
	for (i=0;i<TabMax;i++)
		if (stringcmp(tname,TabDic[i].tab_name)==0)
		{
			j = TabDic[i].row_num;
			break;
		}
	return(j);
}

//从表字典表得到表中元组的实际存储长度
int		GetTabRowLen(char *tname)
{
	int		i,j=0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -