📄 selectexe.c
字号:
#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 + -