(C语言)数据库简单实现
(C语言)数据库简单实现一、数据结构自定义基础数据类型数据字典表数据结构表信息存储列信息存储自定义表信息存储数据块头信息数据项(元组)存储信息过滤表达式结构其他二、全局变量三、宏定义四、CREATE实现SELECT实现函数以及用户界面函数该程序在windows环境,dev c++编译器下正常编译运行,linux下需要自行编写strnicmp()与itoa()由于时间的限制,在块存储结构以及数据字典
(C语言)数据库简单实现
该程序在windows环境,dev c++编译器下正常编译运行,linux下需要自行编写strnicmp()与itoa()
一些问题: 由于时间的限制,在块存储结构以及数据字典表的存储上进行了简化,若之后要实现同步等操作的实现将会出现错误,还有较多的冗余代码,没有抽取封装成单独的函数。SELECT的实现只支持单表查询,WHERE语句只支持一个过滤表达式。其中有部分归并排序和外排序的代码没有完成,但是SELECT中有块内排序的函数。
介绍
该程序是数据库的简单实现,包含INSERT插入操作,CREATE建表操作,SELECT查询操作,在数据结构设计时考虑了DELETE删除操作,所以在Item结构中增加了bool型变量IsDelete标记是否已经删除,因为在postgresql中的DELETE是假删除,所以DELETE操作很容易实现,我也在显示的函数里加入了IsDeleted的判断,有需要自行独立添加相关函数即可。自定义表(ID为10000以上,文件名即为ID)在文件存储中是以块(页)形式存储的,大小为8K,元组的长度是变长的,字符串也是变长存储。
该程序实现的主要难度在于数据结构的设计,指针操作,内存中数据存储理解以及文件操作。
涉及的核心函数主要有:
内存操作 malloc()、free()、memcpy()
文件操作 fopen()、fclose()、fread()、fseek()、fwrite()
总体难度不大。
一、数据结构
自定义基础数据类型
//数据类型标识枚举型
typedef enum {
CHAR=1,
INT=2,
LONG=3,
FLOAT=4,
DOUBLE=5,
BOOL=6,
Type=7 //DataType枚举型标识
}DataType;
typedef enum{
less_than=0,
greater_than=1,
equal_to=2,
not_equal_to=3,
less_equal=4,
greater_equal=5
}CmpOperator;
数据字典表数据结构
表信息存储
//pg_class数据字典表的元组结构体,存储表信息
typedef struct pg_class_tuple{
char TableName[20]; //表名
int ID; //表ID
int ColNum; //列数量
}PC_Tuple;
列信息存储
//pg_attribute数据字典表的元组结构体 ,存储列信息
typedef struct pg_attribute_tuple{
char ColName[20]; //列名
int BelongToID; //归属表的ID
DataType Type; //数据类型标识
int TypeSize; //数据字节长度
int NoOfCol; //列号
bool AbleNull; //是否可以为空,true为可以为空 ??????????字节数为4,不明原因 ,但是不影响正常读写
}PA_Tuple;
自定义表信息存储
数据块头信息
typedef struct PageHeadData{
int lower;//空闲开始位置
int upper;//空闲结束位置
int special;//special开始位置
}PageHeadData;
数据项(元组)存储信息
typedef struct Item{
int tuple_start; //元组位置
int length; //元组长度
bool IsDeleted; //删除标记
}Item;
过滤表达式结构
typedef struct filter{
int ColNo;
CmpOperator CO;
char *Value;
}Filter;
其他
//一些临时中间变量的结构体,只是为了简洁封装
typedef struct Buffer{
char TypeSetBuffer[50];
int MemoryLen;
int CurrentPos;
bool *pBool;
int *pInt;
long *pLong;
float *pFloat;
double *pDouble;
char *pChar;
int Int;
long Long;
float Float;
double Double;
bool Bool;
}Buffer;
二、全局变量
//标记未使用的表ID,当多次建表时可节省调用查找ID是否重复的函数调用
int IsIDOccupied=10000;
块内排序使用
int SortColFlag;
char *page;
存储表列信息,可以去掉,我在函数中都作为参数传入,作为全局变量只是偷懒,不在函数中定义
PC_Tuple *PCT;
PA_Tuple *PAT;
三、宏定义
#define pg_class "1259"
#define pg_attribute "1249"
#define PAGESIZE 8192
#define SPECIAL 8000
四、INSERT实现
//元组的输入函数
void InsertInput()
{
char *Tuple=NULL,TableName[20];
bool *IsNull=NULL;
int ID,InputNum,*ColPos=NULL,i,j,MaxMemoryLen;
Buffer buffer;
PCT=(PC_Tuple*)malloc(sizeof(PC_Tuple));
printf("请输入你要插入的表名称\nInput-->");
scanf("%s",TableName);
for(;strnicmp(TableName,"pg_class",8)==0||
strnicmp(TableName,"pg_attribute",12)==0||
GetTableInfoByName(TableName,PCT)!=1;)
{
printf("您要插入的表不存在,请重新输入,quit退出\nInput-->");
scanf("%s",TableName);
if(strnicmp(TableName,"quit",4)==0)exit(0);
}
PAT=(PA_Tuple*)malloc(sizeof(PA_Tuple)*PCT->ColNum);
if(GetColInfo(PCT->ID,PAT,PCT->ColNum)!=PCT->ColNum)
{
printf("获取的列数与pg_class中的记录不符,表信息错误\n");
exit(1);
}
//对得到的列数据按照NoOfCol排序
qsort(PAT,PCT->ColNum,sizeof(PA_Tuple),Sort_Colnum);
//标记属性是否已输入
ColPos=(int*)malloc(sizeof(int)*PCT->ColNum);
IsNull=(bool*)malloc(sizeof(bool)*PCT->ColNum);
for(i=0,MaxMemoryLen=0;i<PCT->ColNum;i++)
{
MaxMemoryLen+=PAT[i].TypeSize;
}
Tuple=(char*)malloc(sizeof(char)*MaxMemoryLen);
for(getchar(),printf("回车键退出,任意键开始插入元组\nInput-->");
getchar()!='\n';
printf("回车键退出,任意键开始插入元组\nInput-->"))
{
fflush(stdin);
errorloop: printf("CHAR=1,INT=2,LONG=3,FLOAT=4,DOUBLE=5,[0/1]BOOL=6\n");
for(i=0;i<PCT->ColNum;i++)
printf("[%3d.%20s 类型:%2d 是否可以为空:%2d]\n",
PAT[i].NoOfCol,PAT[i].ColName,PAT[i].Type,PAT[i].AbleNull);
printf("\n");
for(i=0,buffer.MemoryLen=0;i<PCT->ColNum;i++)
{
//初始化Tuple空间
if(i==0)memset(Tuple,'\0',buffer.MemoryLen);
//检测各值是否可以为空,可以则让用户输入该值是否空 ,不可则跳过
if(PAT[i].AbleNull==true)
{
printf("该属性值可为空,是否空[0/1]\nInput-->");
scanf("%d",&buffer.Int);
if(buffer.Int==0)IsNull[i]=false;
else if(buffer.Int==1)
{
IsNull[i]=true;
continue;
}
else
{
printf("%s 非法输入\n",PAT[i].ColName);
goto errorloop;
}
}
else if(PAT[i].AbleNull==false)
{
IsNull[i]=false;
}
printf("%s:",PAT[i].ColName);
switch(PAT[i].Type)
{
case BOOL: scanf("%d",&buffer.Int);
if(buffer.Int==0)*((bool*)(Tuple+buffer.MemoryLen))=false;
else if(buffer.Int==1)*((bool*)(Tuple+buffer.MemoryLen))=true;
else
{
printf("%s 非法输入\n",PAT[i].ColName);
goto errorloop;
}
buffer.MemoryLen+=sizeof(bool);
break;
case DOUBLE:scanf("%lf",&buffer.Double);
memcpy((Tuple+buffer.MemoryLen),&buffer.Double,sizeof(double));
buffer.MemoryLen+=sizeof(double);
break;
case FLOAT: scanf("%f",&buffer.Float);
memcpy((Tuple+buffer.MemoryLen),&buffer.Float,sizeof(float));
buffer.MemoryLen+=sizeof(float);
break;
case LONG: scanf("%ld",&buffer.Long);
memcpy((Tuple+buffer.MemoryLen),&buffer.Long,sizeof(long));
buffer.MemoryLen+=sizeof(long);
break;
case INT: scanf("%d",&buffer.Int);
memcpy((Tuple+buffer.MemoryLen),&buffer.Int,sizeof(int));
buffer.MemoryLen+=sizeof(int);
break;
case CHAR: scanf("%s",buffer.TypeSetBuffer);
if((buffer.Int=strlen(buffer.TypeSetBuffer))>=PAT[i].TypeSize)
{
printf("%s输入的字符串溢出\n",PAT[i].ColName);
goto errorloop;
}
strcpy((Tuple+buffer.MemoryLen),buffer.TypeSetBuffer);
buffer.MemoryLen+=sizeof(char)*(buffer.Int+1);
break;
default: printf("错误");i--;
}
printf("位置:%d\n",buffer.MemoryLen);
}
insert(Tuple,IsNull,PCT->ID,PCT->ColNum,sizeof(char)*buffer.MemoryLen);
printf("插入成功!\n");
fflush(stdin);
}
free(PCT);
free(PAT);
free(Tuple);
free(ColPos);
}
//通过表名获取表信息
int GetTableInfoByName(char * TableName,PC_Tuple *PCT)
{
int status=0;
FILE *fp=NULL;
PC_Tuple temp;
int i;
//读写二进制文件
if((fp=fopen(pg_class,"rb"))==NULL)
{
printf("1259打开失败:GetTableInfoByName()\n");
exit(1);
}
//循环遍历pg_class文件,直到找到ID对应的表信息,若直到文件尾仍然未找到,则退出循环
for(i=0;feof(fp)==0;i++)
{
fseek(fp,sizeof(PC_Tuple)*i,SEEK_SET);
if(fread(&temp,sizeof(PC_Tuple),1,fp)==0)break;
if(strnicmp(TableName,temp.TableName,20)==0)
{
*PCT=temp;
status=1;
break;
}
}
if(fclose(fp)!=0)
{
printf("1259关闭失败:GetTableInfoByName()\n");
exit(1);
}
return status;
}
//获取具有空闲空间的页
int GetThePageHaveEnoughSpace(char *Page,int Size,FILE *fp)
{
int i,status=-1;
for(i=0;feof(fp)==0;i++)
{
fseek(fp,PAGESIZE*i,SEEK_SET);
if(fread(Page,PAGESIZE,1,fp)==0)break;
if(((((PageHeadData*)Page)->upper)-(((PageHeadData*)Page)->lower))>=Size)
{
status=i;
return status;
}
}
status=-i;
return status;
}
//按ID检测表是否存在,如存在则返回表信息,返回值为1找到,0为未找到
int GetTableInfo(int ID,PC_Tuple *PCT)
{
int status=0;
FILE *fp=NULL;
PC_Tuple temp;
int i;
//读写二进制文件
if((fp=fopen(pg_class,"rb"))==NULL)
{
printf("1259打开失败:GetTableInfo()\n");
exit(1);
}
//循环遍历pg_class文件,直到找到ID对应的表信息,若直到文件尾仍然未找到,则退出循环
for(i=0;feof(fp)==0;i++)
{
fseek(fp,sizeof(PC_Tuple)*i,SEEK_SET);
if(fread(&temp,sizeof(PC_Tuple),1,fp)==0)break;
if(temp.ID==ID)
{
*PCT=temp;
status=1;
break;
}
}
if(fclose(fp)!=0)
{
printf("1259关闭失败:GetTableInfo()\n");
exit(1);
}
return status;
}
//按ID检测表属性,返回表属性列 ,返回值为找到的列数
int GetColInfo(int ID,PA_Tuple *PAT,int ColNum)
{
FILE *fp=NULL;
PA_Tuple temp;
int i,count;
if((fp=fopen(pg_attribute,"rb"))==NULL)
{
if(fclose(fp)!=0)
{
printf("1249关闭失败:GetColInfo()\n");
exit(1);
}
}
for(i=0,count=0;feof(fp)==0;i++)
{
fseek(fp,sizeof(PA_Tuple)*i,SEEK_SET);
if(fread(&temp,sizeof(PA_Tuple),1,fp)==0)break;
if(temp.BelongToID==ID)
{
PAT[count]=temp;
count++;
if(count==ColNum)break;
}
}
if(fclose(fp)!=0)
{
printf("1249关闭失败:GetColInfo()\n");
exit(1);
}
return count;
}
//qsort()函数调用
int Sort_Colnum(const void *elem1,const void *elem2)
{
PA_Tuple *pac1 =(PA_Tuple*)elem1;
PA_Tuple *pac2 =(PA_Tuple*)elem2;
return (pac1->NoOfCol)-(pac2->NoOfCol);
}
//扩展页
int extend(FILE *fp)
{
char *p=NULL;
int status;
p=(char*)malloc(PAGESIZE);
memset(p,'\0',PAGESIZE);
init_Page(p);
fseek(fp,0,SEEK_END);
if(fwrite(p,PAGESIZE,1,fp)==0)
{
printf("创建新页失败:extend()\n");
}
free(p);
}
//初始化PAGE
void init_Page(char *PAGE)
{
PageHeadData *PHD=NULL;
PHD=(PageHeadData*)malloc(sizeof(PageHeadData));
PHD->lower=sizeof(PageHeadData);
PHD->special=SPECIAL;
PHD->upper=SPECIAL;
memcpy(PAGE,PHD,sizeof(PageHeadData));
free(PHD);
}
//插入函数,用于插入表信息,第一个参数为插入内容,第二个为要插入表的ID
//第三个为插入列个数,第四个为单个元组的尺寸
int insert(void* Tuple,bool *IsNull,int ID,int InputNum,int Size)
{
FILE *fp=NULL;
int i,j,status,ThePageFind;
char *PAGE=NULL;
char str[10];
Item item;
PageHeadData *PHD=NULL;
if(ID==1259)
{
if((fp=fopen(pg_class,"ab+"))==NULL)
{
printf("1259打开失败:insert()\n");
exit(1);
}
if(fwrite((PC_Tuple*)Tuple,Size,1,fp)!=1)
{
printf("1259写入失败:insert()\n");
exit(1);
}
if(fclose(fp)!=0)
{
printf("1259关闭失败:insert()\n");
exit(1);
}
}
else if(ID==1249)
{
if((fp=fopen(pg_attribute,"ab+"))==NULL)
{
printf("1249打开失败:insert()\n");
exit(1);
}
if(fwrite((PA_Tuple*)Tuple,Size,1,fp)!=1)
{
printf("1249写入失败:insert()\n");
exit(1);
}
if(fclose(fp)!=0)
{
printf("1249关闭失败:insert()\n");
exit(1);
}
}
//任意表插入
else
{
if((fp=fopen(itoa(ID,str,10),"rb+"))==NULL)
{
printf("%d 打开失败:insert()\n",ID);
exit(1);
}
PAGE=(char*)malloc(PAGESIZE);
PHD=(PageHeadData*)malloc(sizeof(PageHeadData));
fseek(fp,0,SEEK_END);
if(ftell(fp)==0)
{
printf("PAGE数据消失,请检查文件是否丢失,为保证运行,将开辟新页!\n");
extend(fp);
}
//获取有空闲空间的Page,正数返回值的为第几个page页,负数返回值为找不到,其绝对值为总页数
if((ThePageFind=GetThePageHaveEnoughSpace(PAGE,Size+sizeof(Item)+sizeof(bool)*InputNum,fp))<0)
{
extend(fp);
}
else
{
item.IsDeleted=false;
item.length=Size;
PHD=(PageHeadData*)PAGE;
PHD->upper=PHD->upper-sizeof(char)*item.length-sizeof(bool)*InputNum;
PHD->special=SPECIAL;
item.tuple_start=PHD->upper;
memcpy((PAGE+PHD->lower),&item,sizeof(Item));
PHD->lower+=sizeof(Item);
memcpy((PAGE+PHD->upper),IsNull,sizeof(bool)*InputNum);
memcpy(PAGE+PHD->upper+sizeof(bool)*InputNum,(char*)Tuple,sizeof(char)*Size);
memcpy(PAGE,PHD,sizeof(PageHeadData));
fseek(fp,ThePageFind*PAGESIZE,SEEK_SET);
if(fwrite(PAGE,PAGESIZE,1,fp)!=1)
{
printf("%d 写入失败:insert()",ID);
exit(1);
}
if((fclose(fp))!=0)
{
printf("%d 关闭失败:insert()\n",ID);
exit(1);
}
}
free(PAGE);
}
return 0;
}
//char()输入处理,忽略大小写
int DealWithCharInput(char * pInputChar,int n)
{
int i,count=0;
int Return=0;
if((pInputChar[0]=='C'||pInputChar[0]=='c')&&
(pInputChar[1]=='H'||pInputChar[1]=='h')&&
(pInputChar[2]=='A'||pInputChar[2]=='a')&&
(pInputChar[3]=='R'||pInputChar[3]=='r'))
{
if(pInputChar[4]=='(')
{
for(i=5;pInputChar[i]>='0'&&pInputChar[i]<='9'&&i<n;i++)count++;
for(i=5;pInputChar[i]>='0'&&pInputChar[i]<='9'&&i<n;i++)
{
Return+=(pInputChar[i]-'0')*pow(10,count-1);
count--;
}
return Return;
}
else if(pInputChar[4]=='\0'||pInputChar[4]=='\n')
return 1;
}
else return 0;
}
//通过名字显示表的全部内容
void ShowTable()
{
int i,j,k,ColPos;
FILE *fp=NULL;
Buffer buffer;
char *PAGE=NULL;
PageHeadData *PHD=NULL;
Item *item=NULL;
bool *IsNull=NULL;
char TableName[20];
PAGE=(char*)malloc(sizeof(char)*PAGESIZE);
item=(Item*)malloc(sizeof(Item));
PCT=(PC_Tuple*)malloc(sizeof(PC_Tuple));
printf("请输入你要查看的表名称\nInput-->");
scanf("%s",TableName);
for(;strnicmp(TableName,"pg_class",8)==0||
strnicmp(TableName,"pg_attribute",12)==0||
GetTableInfoByName(TableName,PCT)!=1;)
{
printf("您要查看的表不存在,请重新输入,quit退出\nInput-->");
scanf("%s",TableName);
if(strnicmp(TableName,"quit",4)==0)exit(0);
}
IsNull=(bool*)malloc(sizeof(bool)*PCT->ColNum);
PAT=(PA_Tuple*)malloc(sizeof(PA_Tuple)*PCT->ColNum);
if(GetColInfo(PCT->ID,PAT,PCT->ColNum)!=PCT->ColNum)
{
printf("列信息不全:%d\n",PCT->ID);
exit(1);
}
//给取出的列排序//便于解释
qsort(PAT,PCT->ColNum,sizeof(PA_Tuple),Sort_Colnum);
if((fp=fopen(itoa(PCT->ID,buffer.TypeSetBuffer,10),"rb"))==NULL)
{
printf("%d 打开失败:ShowTable()\n",PCT->ID);
exit(1);
}
//获取每个块
for(i=0;feof(fp)==0;i++)
{
fseek(fp,PAGESIZE*i,SEEK_SET);
if(fread(PAGE,PAGESIZE,1,fp)==0)break;
PHD=(PageHeadData*)PAGE;
//每个元组获取
for(k=0;
(sizeof(PageHeadData)+sizeof(Item)*k)<PHD->lower;
k++)
{
memcpy(item,(Item*)(PAGE+sizeof(PageHeadData)+sizeof(Item)*k),sizeof(Item));
//检测是否已被删除
if(item->IsDeleted==true)continue;
memcpy(IsNull,(bool*)(PAGE+item->tuple_start),PCT->ColNum*sizeof(bool));
buffer.pChar=(char*)malloc(sizeof(char)*(item->length));
memcpy(buffer.pChar,(PAGE+item->tuple_start),PCT->ColNum*sizeof(bool));
memcpy(buffer.pChar,(PAGE+item->tuple_start+PCT->ColNum*sizeof(bool)),sizeof(char)*item->length);
//输出每个属性
for(j=0,ColPos=0;j<PCT->ColNum;j++)
{
printf("%d :",ColPos);
if(IsNull[j]==true)
{
printf("%s[null] ",PAT[j].ColName);
continue;
}
else
{
switch(PAT[j].Type)
{
case BOOL: if(*((int*)(buffer.pChar+ColPos))==1)printf("%s[true] ",PAT[j].ColName);
else printf("%s[true] ",PAT[j].ColName);
ColPos+=sizeof(bool);
break;
case DOUBLE:buffer.pDouble=(double*)(buffer.pChar+ColPos);
printf("%s[%lf] ",PAT[j].ColName,*buffer.pDouble);
ColPos+=sizeof(double);
break;
case FLOAT: buffer.pFloat=(float*)(buffer.pChar+ColPos);
printf("%s[%f] ",PAT[j].ColName,*buffer.pFloat);
ColPos+=sizeof(float);
break;
case LONG: buffer.pLong=(long*)(buffer.pChar+ColPos);
printf("%s[%ld] ",PAT[j].ColName,*buffer.pLong);
ColPos+=sizeof(long);
break;
case INT: buffer.pInt=(int*)(buffer.pChar+ColPos);
printf("%s[%d] ",PAT[j].ColName,*buffer.pInt);
ColPos+=sizeof(int);
break;
case CHAR: printf("%s[%s] ",PAT[j].ColName,(buffer.pChar+ColPos));
ColPos+=(strlen(buffer.pChar+ColPos)+1);
break;
default: printf("错误");i--;
}
}
}
printf("\n");
free(buffer.pChar);
}
}
free(IsNull);
free(PAT);
free(PCT);
free(PAGE);
//free(PHD); //不明白为什么会卡死?? 不需要申请空间,内部地址包含在page,导致重复free
if((fclose(fp))!=0)
{
printf("%d 关闭失败:ShowTable()\n",PCT->ID);
exit(1);
}
}
五、CREATE实现
//展示pg_class
void ShowTableInfo()
{
FILE *fp=NULL;
PC_Tuple temp;
int i;
//读写二进制文件
if((fp=fopen(pg_class,"rb"))==NULL)
{
printf("1259打开失败:ShowTableInfo()\n");
exit(1);
}
printf("+--------------------------------------------------+\n");
printf("| 表名 | 表ID | 属性数 |\n");
printf("+--------------------------------------------------+\n");
//循环遍历pg_class文件,直到找到ID对应的表信息,若直到文件尾仍然未找到,则退出循环
for(i=0;feof(fp)==0;i++)
{
fseek(fp,sizeof(PC_Tuple)*i,SEEK_SET);
if(fread(&temp,sizeof(PC_Tuple),1,fp)!=0)
{
printf("| %21s | %11d | %10d |\n",temp.TableName,temp.ID,temp.ColNum);
}
}
printf("+--------------------------------------------------+\n");
if(fclose(fp)!=0)
{
printf("1259关闭失败:ShowTableInfo()");
exit(1);
}
}
//展示pg_attribute
void ShowColInfo()
{
FILE *fp=NULL;
PA_Tuple temp;
int i;
//读写二进制文件
if((fp=fopen(pg_attribute,"rb"))==NULL)
{
printf("1249打开失败:ShowColInfo()\n");
exit(1);
}
printf("+-------------------------------------------------------------------------------------+\n");
printf("| 列名 | 属于表 | 数据类型 | 字节长度 | 列号 | 可以为空 |\n");
printf("+-------------------------------------------------------------------------------------+\n");
//循环遍历pg_class文件,直到找到ID对应的表信息,若直到文件尾仍然未找到,则退出循环
for(i=0;feof(fp)==0;i++)
{
fseek(fp,sizeof(PA_Tuple)*i,SEEK_SET);
if(fread(&temp,sizeof(PA_Tuple),1,fp)!=0)
{
printf("| %21s | %11d | %10d | %10d | %6d | %10d | \n",
temp.ColName,temp.BelongToID,temp.Type,temp.TypeSize,temp.NoOfCol,temp.AbleNull);
}
}
printf("+-------------------------------------------------------------------------------------+\n");
if(fclose(fp)!=0)
{
printf("1249关闭失败:ShowColInfo()\n");
exit(1);
}
}
//初始化函数,用于创建pg_class与pg_attribute的文件,然后调用两个数据字典表初始化函数来初始化文件
void init()
{
FILE *fp=NULL;
int i;
if((fp=fopen(pg_class,"wb"))==NULL)
{
printf("pg_class文件创建失败:init()\n");
exit(1);
}
if(fclose(fp)!=0)
{
printf("pg_class文件关闭失败:init()\n");
exit(1);
}
if((fp=fopen(pg_attribute,"wb"))==NULL)
{
printf("pg_attribute文件创建失败:init()\n");
exit(1);
}
if(fclose(fp)!=0)
{
printf("pg_attribute文件关闭失败:init()\n");
exit(1);
}
init_Pg_Class();
init_Pg_Attribute();
}
//初始化pg_class字典表
void init_Pg_Class()
{
FILE *fp=NULL;
char *p=NULL;
int i;
int curpos;
//pg_class的属性信息,存储到pg_attribute中
char ColName[3][20]={"table_name","table_id","table_col_name"};
DataType Type[3]={CHAR,INT,INT};
int TypeSize[3]={sizeof(char)*20,sizeof(int),sizeof(int)};
bool *IsNull=NULL;
char PAColName[6][20]={"col_name",
"belong_to_id",
"value_type",
"type_size",
"no_of_col",
"able_null"};
//pg_class的表信息,存储到pg_class中
//printf("\ntest :%s\n",ColName[2]);
PCT=(PC_Tuple*)malloc(sizeof(PC_Tuple));
strcpy(PCT->TableName,"pg_class");
PCT->ID=1259;
PCT->ColNum=3;
insert(PCT,IsNull,1259,3,sizeof(PC_Tuple));
PAT=(PA_Tuple*)malloc(sizeof(PA_Tuple)*PCT->ColNum);
for(i=0;i<(PCT->ColNum);i++)
{
PAT[i].BelongToID=1259;
strcpy(PAT[i].ColName,ColName[i]);
PAT[i].AbleNull=false;
PAT[i].NoOfCol=i+1;
PAT[i].Type=Type[i];
PAT[i].TypeSize=TypeSize[i];
insert(PAT+i,IsNull,1249,6,sizeof(PA_Tuple));
}
free(PCT);
free(PAT);
}
//初始化pg_attribute字典表
void init_Pg_Attribute()
{
FILE *fp=NULL;
int i;
char ColName[3][20]={"table_name","table_id","table_col_num"};
DataType Type[3]={CHAR,INT,INT};
int TypeSize[3]={sizeof(char)*20,sizeof(int),sizeof(int)};
//pg_attribute的属性信息,存储到pg_attribute中
char PAColName[6][20]={"col_name",
"belong_to_id",
"value_type",
"type_size",
"no_of_col",
"able_null"};
DataType PAType[6]={1,2,7,2,2,6};//={INT,CHAR,BOOL,INT,Type,INT,INT};
int PATypeSize[6]={sizeof(char)*20,
sizeof(int),
sizeof(DataType),
sizeof(int),
sizeof(int),
sizeof(bool)};
bool *IsNull=NULL;
//pg_attribute的表信息,存储到pg_class中
PCT=(PC_Tuple*)malloc(sizeof(PC_Tuple));
PCT->ColNum=6;
PCT->ID=1249;
strcpy(PCT->TableName,"pg_attribute");
insert(PCT,IsNull,1259,3,sizeof(PC_Tuple));
PAT=(PA_Tuple*)malloc(sizeof(PA_Tuple)*PCT->ColNum);
for(i=0;i<(PCT->ColNum);i++)
{
PAT[i].BelongToID=1249;
strcpy(PAT[i].ColName,PAColName[i]);
PAT[i].AbleNull=false;
PAT[i].NoOfCol=i+1;
PAT[i].Type=PAType[i];
PAT[i].TypeSize=PATypeSize[i];
insert(PAT+i,IsNull,1249,6,sizeof(PA_Tuple));
}
free(PCT);
free(PAT);
}
//建表函数
int create(char *TableName,PA_Tuple *PAT,int ColNum)
{
FILE *fp=NULL;
char NameAccept[11];
int i;
bool *IsNull=NULL;
PCT=(PC_Tuple*)malloc(sizeof(PC_Tuple));
for(;GetTableInfoByName(TableName,PCT);)
{
printf("该表已存在,退出或重新输入表名[Q/]");
if(getchar()=='Q')
{
exit(1);
}
fflush(stdin);
printf("请输入新的表名:");
scanf("%s",TableName);
}
//查找随机ID是否已存在
for(;GetTableInfo(IsIDOccupied,PCT);IsIDOccupied++);
strcpy(PCT->TableName,TableName);
PCT->ID=IsIDOccupied;
PCT->ColNum=ColNum;
if((fp=fopen(itoa(PCT->ID,NameAccept,10),"wb"))==NULL)
{
printf("%d 文件创建失败:init()\n",PCT->ID);
exit(1);
}
extend(fp);
insert(PCT,IsNull,1259,3,sizeof(PC_Tuple));
for(i=0;i<PCT->ColNum;i++)
{
PAT[i].BelongToID=PCT->ID;
insert(PAT+i,IsNull,1249,6,sizeof(PA_Tuple));
}
free(PCT);
}
//用户自定义建表函数
void User_Create_Table()
{
char TableName[20],TypeInput[20];
int ColNum;
int i;
printf("请输入表名:") ;
scanf("%s",TableName);
printf("有多少属性:");
scanf("%d",&ColNum);
PAT=(PA_Tuple*)malloc(sizeof(PA_Tuple)*ColNum);
for(i=0;i<ColNum;i++)
{
printf("第%d个属性名:",i+1);
scanf("%s",PAT[i].ColName);
ColTypeLoop:
printf("%s 属性类型:",PAT[i].ColName);
scanf("%s",TypeInput);
if(strnicmp(TypeInput,"INT",3)==0)
{
PAT[i].Type=INT;
PAT[i].TypeSize=sizeof(int);
}
else if(strnicmp(TypeInput,"LONG",4)==0)
{
PAT[i].Type=LONG;
PAT[i].TypeSize=sizeof(long);
}
else if(strnicmp(TypeInput,"FLOAT",5)==0)
{
PAT[i].Type=FLOAT;
PAT[i].TypeSize=sizeof(float);
}
else if(strnicmp(TypeInput,"DOUBLE",6)==0)
{
PAT[i].Type=DOUBLE;
PAT[i].TypeSize=sizeof(double);
}
else if(strnicmp(TypeInput,"BOOL",4)==0)
{
PAT[i].Type=BOOL;
PAT[i].TypeSize=sizeof(bool);
}
else if(strnicmp(TypeInput,"Type",4)==0)
{
PAT[i].Type=Type;
PAT[i].TypeSize=sizeof(DataType);
}
else if((PAT[i].TypeSize=DealWithCharInput(TypeInput,10)+1)>0)
{
PAT[i].Type=CHAR;
}
else
{
printf("数据类型错误,请重新输入\n");
goto ColTypeLoop;
}
NullLoop:
printf("%s是否可以为空[false/true]",PAT[i].ColName);
scanf("%s",TypeInput);
if(strnicmp(TypeInput,"true",4)==0) PAT[i].AbleNull=true;
else if(strnicmp(TypeInput,"false",5)==0) PAT[i].AbleNull=false;
else{
fflush(stdin);
printf("输入错误,默认为false,是否重新输入[Y/n]");
if(getchar()=='Y')
{
goto NullLoop;
}
else PAT[i].AbleNull=false;
fflush(stdin);
}
PAT[i].NoOfCol=i+1;
}
create(TableName,PAT,ColNum);
free(PAT);
}
//检测是否为初次运行,若初次运行则调用初始化pg_class和pg_attribute函数
void IsFirstExecutes()
{
//通过只读选项打开pg_class和pg_attribute文件,若打开失败,说明为初次运行软件
bool test_1259=false,test_1249=false;
FILE *fp=NULL;
if((fp=fopen(pg_class,"rb"))!=NULL)test_1259=true;
if(test_1259==true)
{
if(fclose(fp)!=0)
{
printf("文件关闭失败:main()");
exit(1);
}
}
if((fp=fopen(pg_attribute,"rb"))!=NULL)test_1249=true;
if(test_1249==true)
{
if(fclose(fp)!=0)
{
printf("文件关闭失败:main()");
exit(1);
}
}
if(test_1249==false||test_1259==false)
{
init();
}
}
六、SELECT实现
//检测Value是否在Array数组中的函数
int IsValueInArray(int Value,int *Array,int n)
{
int i,status=0;
for(i=0;i<n;i++)
{
if(Value==Array[i])
{
status=1;
break;
}
}
return status;
}
//显示投影后的表信息
void ShowProjectedTable(int ID,int *ProjectedCol,int n,PC_Tuple *PCT,PA_Tuple *PAT)
{
int i,j,k,t,ColPos;
FILE *fp=NULL;
Buffer buffer;
char *PAGE=NULL;
PageHeadData *PHD=NULL;
Item *item=NULL;
bool *IsNull=NULL;
PAGE=(char*)malloc(sizeof(char)*PAGESIZE);
item=(Item*)malloc(sizeof(Item));
IsNull=(bool*)malloc(sizeof(bool)*PCT->ColNum);
//给取出的列排序//便于解释
qsort(PAT,PCT->ColNum,sizeof(PA_Tuple),Sort_Colnum);
if((fp=fopen(itoa(ID,buffer.TypeSetBuffer,10),"rb"))==NULL)
{
printf("%d 打开失败:ShowProjectedTable()\n",ID);
exit(1);
}
//获取每个块
for(i=0;feof(fp)==0;i++)
{
fseek(fp,PAGESIZE*i,SEEK_SET);
if(fread(PAGE,PAGESIZE,1,fp)==0)break;
PHD=(PageHeadData*)PAGE;
//每个元组获取
for(k=0;
(sizeof(PageHeadData)+sizeof(Item)*k)<PHD->lower;
k++)
{
memcpy(item,(Item*)(PAGE+sizeof(PageHeadData)+sizeof(Item)*k),sizeof(Item));
//检测是否已被删除
if(item->IsDeleted==true)continue;
memcpy(IsNull,(bool*)(PAGE+item->tuple_start),PCT->ColNum*sizeof(bool));
buffer.pChar=(char*)malloc(sizeof(char)*(item->length));
memcpy(buffer.pChar,(PAGE+item->tuple_start),PCT->ColNum*sizeof(bool));
memcpy(buffer.pChar,(PAGE+item->tuple_start+PCT->ColNum*sizeof(bool)),sizeof(char)*item->length);
//输出每个属性
for(j=0,ColPos=0;j<PCT->ColNum;j++)
{
//如果当前列不需要输出,跳过
if(IsValueInArray(j,ProjectedCol,n)==0)
{
switch(PAT[j].Type)
{
case BOOL: ColPos+=sizeof(bool);
break;
case DOUBLE:ColPos+=sizeof(double);
break;
case FLOAT: ColPos+=sizeof(float);
break;
case LONG: ColPos+=sizeof(long);
break;
case INT: ColPos+=sizeof(int);
break;
case CHAR: ColPos+=(strlen(buffer.pChar+ColPos)+1);
break;
default: printf("错误");i--;
}
continue;
}
else
{
if(IsNull[j]==true)
{
printf("%s[null] ",PAT[j].ColName);
continue;
}
else
{
switch(PAT[j].Type)
{
case BOOL: if(*((int*)(buffer.pChar+ColPos))==1)printf("%s[true] ",PAT[j].ColName);
else printf("%s[true] ",PAT[j].ColName);
ColPos+=sizeof(bool);
break;
case DOUBLE:buffer.pDouble=(double*)(buffer.pChar+ColPos);
printf("%s[%lf] ",PAT[j].ColName,*buffer.pDouble);
ColPos+=sizeof(double);
break;
case FLOAT: buffer.pFloat=(float*)(buffer.pChar+ColPos);
printf("%s[%f] ",PAT[j].ColName,*buffer.pFloat);
ColPos+=sizeof(float);
break;
case LONG: buffer.pLong=(long*)(buffer.pChar+ColPos);
printf("%s[%ld] ",PAT[j].ColName,*buffer.pLong);
ColPos+=sizeof(long);
break;
case INT: buffer.pInt=(int*)(buffer.pChar+ColPos);
printf("%s[%d] ",PAT[j].ColName,*buffer.pInt);
ColPos+=sizeof(int);
break;
case CHAR: printf("%s[%s] ",PAT[j].ColName,(buffer.pChar+ColPos));
ColPos+=(strlen(buffer.pChar+ColPos)+1);
break;
default: printf("错误");i--;
}
}
}
}
printf("\n");
free(buffer.pChar);
}
}
free(IsNull);
free(item);
free(PAGE);
if((fclose(fp))!=0)
{
printf("%d 关闭失败:ShowTable()\n",PCT->ID);
exit(1);
}
}
//select函数
void exec_simple_query(int ID,int *ProjectedCol,int n,Filter filter,PC_Tuple *PCT,PA_Tuple *PAT)
{
int i,k,j,ColPos;
Buffer buffer;
FILE *fp=NULL,*tempfp=NULL;
char *PAGE=NULL;
PageHeadData *PHD=NULL;
Item *item=NULL;
bool *IsNull=NULL;
IsNull=(bool*)malloc(sizeof(bool)*PCT->ColNum);
item=(Item*)malloc(sizeof(Item));
PAGE=(char*)malloc(sizeof(char)*PAGESIZE);
if((fp=fopen(itoa(PCT->ID,buffer.TypeSetBuffer,10),"rb"))==NULL)
{
printf("%d 打开失败:exec_simple_query()\n",PCT->ID);
exit(1);
}
if((tempfp=fopen("0","wb"))==NULL)
{
printf("临时文件创建失败:exec_simple_query()\n");
exit(1);
}
extend(tempfp);
if(fclose(tempfp)!=0)
{
printf("临时文件关闭失败");
exit(1);
}
//获取每个块
for(i=0;feof(fp)==0;i++)
{
fseek(fp,PAGESIZE*i,SEEK_SET);
if(fread(PAGE,PAGESIZE,1,fp)==0)break;
PHD=(PageHeadData*)PAGE;
//每个元组获取
for(k=0;
(sizeof(PageHeadData)+sizeof(Item)*k)<PHD->lower;
k++)
{
memcpy(item,(Item*)(PAGE+sizeof(PageHeadData)+sizeof(Item)*k),sizeof(Item));
//检测是否已被删除
if(item->IsDeleted==true)continue;
memcpy(IsNull,(bool*)(PAGE+item->tuple_start),PCT->ColNum*sizeof(bool));
buffer.pChar=(char*)malloc(sizeof(char)*(item->length));
memcpy(buffer.pChar,(PAGE+item->tuple_start),PCT->ColNum*sizeof(bool));
memcpy(buffer.pChar,(PAGE+item->tuple_start+PCT->ColNum*sizeof(bool)),sizeof(char)*item->length);
//输出每个属性
if(IsNull[filter.ColNo]==false)
{
//因为只有一个过滤表达式,只需要读取到filter.ColNo个属性就进行下一元组的筛选
for(j=0,ColPos=0;j<=filter.ColNo;j++)
{
// 如果不是过滤表达式的列名,只需要计算当前属性在元组中的位置即可
if(j!=filter.ColNo)
{
if(IsNull[j]==true)continue;
else
{
switch(PAT[j].Type)
{
case BOOL: ColPos+=sizeof(bool);
break;
case DOUBLE:ColPos+=sizeof(double);
break;
case FLOAT: ColPos+=sizeof(float);
break;
case LONG: ColPos+=sizeof(long);
break;
case INT: ColPos+=sizeof(int);
break;
case CHAR: ColPos+=(strlen(buffer.pChar+ColPos)+1);
break;
default: printf("错误");i--;
}
}
}
else
{
if(IsNull[j]==true)continue;
else
{
switch(PAT[j].Type)
{
case BOOL: buffer.pBool=(bool*)(buffer.pChar+ColPos);
switch(filter.CO)
{
case equal_to: if(*buffer.pBool==*((bool*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case not_equal_to:if(*buffer.pBool!=*((bool*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
}
break;
case DOUBLE:buffer.pDouble=(double*)(buffer.pChar+ColPos);
switch(filter.CO)
{
case less_than: if(*buffer.pDouble<*((double*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case greater_than: if(*buffer.pDouble>*((double*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case less_equal: if(*buffer.pDouble<=*((double*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case greater_equal:if(*buffer.pDouble>=*((double*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case equal_to: if(*buffer.pDouble==*((double*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case not_equal_to: if(*buffer.pDouble!=*((double*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
}
break;
case FLOAT: buffer.pFloat=(float*)(buffer.pChar+ColPos);
switch(filter.CO)
{
case less_than: if(*buffer.pFloat<*((float*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case greater_than: if(*buffer.pFloat>*((float*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case less_equal: if(*buffer.pFloat<=*((float*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case greater_equal:if(*buffer.pFloat>=*((float*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case equal_to: if(*buffer.pFloat==*((float*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case not_equal_to: if(*buffer.pFloat!=*((float*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
}
break;
case LONG: buffer.pLong=(long*)(buffer.pChar+ColPos);
switch(filter.CO)
{
case less_than: if(*buffer.pLong<*((long*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case greater_than: if(*buffer.pLong>*((long*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case less_equal: if(*buffer.pLong<=*((long*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case greater_equal:if(*buffer.pLong>=*((long*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case equal_to: if(*buffer.pLong==*((long*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case not_equal_to: if(*buffer.pLong!=*((long*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
}
break;
case INT: buffer.pInt=(int*)(buffer.pChar+ColPos);
switch(filter.CO)
{
case less_than: if(*buffer.pInt<*((int*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case greater_than: if(*buffer.pInt>*((int*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case less_equal: if(*buffer.pInt<=*((int*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case greater_equal:if(*buffer.pInt>=*((int*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case equal_to: if(*buffer.pInt==*((int*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case not_equal_to: if(*buffer.pInt!=*((int*)filter.Value))insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
}
break;
case CHAR: switch(filter.CO)
{
case less_than: if(strcmp(buffer.pChar+ColPos,filter.Value)<0)insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case greater_than: if(strcmp(buffer.pChar+ColPos,filter.Value)>0)insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case less_equal: if(strcmp(buffer.pChar+ColPos,filter.Value)<=0)insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case greater_equal:if(strcmp(buffer.pChar+ColPos,filter.Value)>=0)insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case equal_to: if(strcmp(buffer.pChar+ColPos,filter.Value)==0)insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
case not_equal_to: if(strcmp(buffer.pChar+ColPos,filter.Value)!=0)insert(buffer.pChar,IsNull,0,PCT->ColNum,item->length);break;
}
break;
default: printf("错误");i--;
}
}
}
}
}
free(buffer.pChar);
}
}
if(fclose(fp)!=0)
{
printf("文件关闭失败");
exit(1);
}
free(IsNull);
free(item);
free(PAGE);
ShowProjectedTable(0,ProjectedCol,n,PCT,PAT);
//删除临时数据
if(remove("0")!=0)
{
printf("临时文件删除失败\n");
exit(0);
}
}
//select输入处理函数
void Select_Input()
{
FILE* fp=NULL;
char TableName[20],ColName[20];
int *ProjectedCol=NULL; //需要投影的列号
int n,i,j,status;
bool *IsProjected=NULL; //是否需要投影标记
Buffer buffer;
PCT=(PC_Tuple*)malloc(sizeof(PC_Tuple));
Filter filter;
printf("请输入你要查看的表名称\nInput-->");
scanf("%s",TableName);
for(;strnicmp(TableName,"pg_class",8)==0||
strnicmp(TableName,"pg_attribute",12)==0||
GetTableInfoByName(TableName,PCT)!=1;)
{
printf("您要查看的表不存在,请重新输入,quit退出\nInput-->");
scanf("%s",TableName);
if(strnicmp(TableName,"quit",4)==0)return;
}
IsProjected=(bool*)malloc(sizeof(bool)*PCT->ColNum);
for(i=0;i<PCT->ColNum;i++)IsProjected[i]=false;
PAT=(PA_Tuple*)malloc(sizeof(PA_Tuple)*PCT->ColNum);
if(GetColInfo(PCT->ID,PAT,PCT->ColNum)!=PCT->ColNum)
{
printf("列信息不全:%d\n",PCT->ID);
exit(1);
}
qsort(PAT,PCT->ColNum,sizeof(PA_Tuple),Sort_Colnum);
for(n=PCT->ColNum+1,printf("请输入需要投影的列个数\nInput-->");
n>PCT->ColNum;)
{
scanf("%d",&n);
}
ProjectedCol=(int*)malloc(sizeof(int)*n);
for(i=0,printf("请输入需要投影的列%d\nInput-->",i);
i<n;i++)
{
scanf("%19s",ColName);
fflush(stdin);
for(status=0,j=0;j<PCT->ColNum;j++)
{
if(strcmp(ColName,PAT[j].ColName)==0)
{
status=1;
break;
}
}
if(status==0)
{
printf("未找到该列,请重新输入\nInput-->");
i--;
}
else
{
IsProjected[j]=true;
if(i<n-1)printf("请输入需要投影的列%d\nInput-->",i);
}
}
for(i=0,status=0;i<PCT->ColNum;i++)
{
if(IsProjected[i]==true)
{
ProjectedCol[status]=i;
status++;
if(status==n)break;
}
}
for(printf("请输入过滤表达式的列名");;)
{
scanf("%s",ColName);
fflush(stdin);
for(status=0,j=0;j<PCT->ColNum;j++)
{
if(strcmp(ColName,PAT[j].ColName)==0)
{
status=1;
break;
}
}
if(status==0)
{
printf("未找到该列,请重新输入");
}
else
{
filter.ColNo=j;
break;
}
}
for(status=1,printf("请输入过滤表达式的操作符");status==1;)
{
status=0;
fflush(stdin);
scanf("%s",ColName);
fflush(stdin);
if(PAT[filter.ColNo].Type==BOOL)
{
if(strcmp(ColName,"=")==0)filter.CO=equal_to;
else if(strcmp(ColName,"!=")==0)filter.CO=not_equal_to;
else
{
printf("重新输入\n");
status=1;
}
}
else
{
if(strcmp(ColName,"<")==0)filter.CO=less_than;
else if(strcmp(ColName,">")==0)filter.CO=greater_than;
else if(strcmp(ColName,"=")==0)filter.CO=equal_to;
else if(strcmp(ColName,"!=")==0)filter.CO=not_equal_to;
else if(strcmp(ColName,"<=")==0)filter.CO=less_equal;
else if(strcmp(ColName,">=")==0)filter.CO=greater_equal;
else
{
printf("重新输入\n");
status=1;
}
}
}
for(status=1;status==1;)
{
printf("请输入过滤表达式的值");
status=0;
switch(PAT[filter.ColNo].Type)
{
case BOOL: filter.Value=(char*)malloc(sizeof(bool));
scanf("%d",&buffer.Int);
if(buffer.Int==0)*((bool*)(filter.Value))=false;
else if(buffer.Int==1)*((bool*)(filter.Value))=true;
else
{
printf("%s 非法输入\n",PAT[i].ColName);
status=1;
}
break;
case DOUBLE:filter.Value=(char*)malloc(sizeof(double));
scanf("%lf",&buffer.Double);
memcpy((filter.Value),&buffer.Double,sizeof(double));
break;
case FLOAT: filter.Value=(char*)malloc(sizeof(float));
scanf("%f",&buffer.Float);
memcpy((filter.Value),&buffer.Float,sizeof(float));
break;
case LONG: filter.Value=(char*)malloc(sizeof(long));
scanf("%ld",&buffer.Long);
memcpy((filter.Value),&buffer.Long,sizeof(long));
break;
case INT: filter.Value=(char*)malloc(sizeof(int));
scanf("%d",&buffer.Int);
memcpy((filter.Value),&buffer.Int,sizeof(int));
break;
case CHAR: filter.Value=(char*)malloc(sizeof(char)*PAT[filter.ColNo].TypeSize);
scanf("%s",buffer.TypeSetBuffer);
if((buffer.Int=strlen(buffer.TypeSetBuffer))>=PAT[filter.ColNo].TypeSize)
{
printf("%s输入的字符串溢出\n",PAT[filter.ColNo].ColName);
status=1;
}
strcpy(filter.Value,buffer.TypeSetBuffer);
break;
default: printf("错误");i--;
}
if(status==1)free(filter.Value);
}
exec_simple_query(PCT->ID,ProjectedCol,n,filter,PCT,PAT);
free(PAT);
free(PCT);
free(ProjectedCol);
free(filter.Value);
}
//元组元素比较函数,在调用的函数中应先申请page,PCT,PAT全局变量的空间,同时调用相关函数获得信息
int ItemCompare(const void *elem1,const void *elem2)
{
Item *item1=(Item*)elem1;
Item *item2=(Item*)elem2;
char *pChar1=NULL,*pChar2=NULL;
bool *IsNull1=NULL,*IsNull2=NULL;
int i;
Buffer buffer1,buffer2;
pChar1=(char*)malloc(sizeof(char)*item1->length);
pChar2=(char*)malloc(sizeof(char)*item2->length);
IsNull1=(bool*)malloc(sizeof(bool)*PCT->ColNum);
IsNull2=(bool*)malloc(sizeof(bool)*PCT->ColNum);
IsNull1=(bool*)(page+item1->tuple_start);
IsNull2=(bool*)(page+item2->tuple_start);
pChar1=page+item1->tuple_start+sizeof(bool)*PCT->ColNum;
pChar1=page+item2->tuple_start+sizeof(bool)*PCT->ColNum;
for(i=0,buffer1.CurrentPos=0,buffer2.CurrentPos=0;i<=SortColFlag;i++)
{
if(i!=SortColFlag)
{
switch(PAT[i].Type)
{
case BOOL: if(IsNull1[i]==false)buffer1.CurrentPos+=sizeof(bool);
if(IsNull2[i]==false)buffer2.CurrentPos+=sizeof(bool);
break;
case DOUBLE:if(IsNull1[i]==false)buffer1.CurrentPos+=sizeof(bool);
if(IsNull2[i]==false)buffer2.CurrentPos+=sizeof(bool);
break;
case FLOAT: if(IsNull1[i]==false)buffer1.CurrentPos+=sizeof(bool);
if(IsNull2[i]==false)buffer2.CurrentPos+=sizeof(bool);
break;
case LONG: if(IsNull1[i]==false)buffer1.CurrentPos+=sizeof(bool);
if(IsNull2[i]==false)buffer2.CurrentPos+=sizeof(bool);
break;
case INT: if(IsNull1[i]==false)buffer1.CurrentPos+=sizeof(bool);
if(IsNull2[i]==false)buffer2.CurrentPos+=sizeof(bool);
break;
case CHAR: if(IsNull1[i]==false)buffer1.CurrentPos+=(strlen(buffer1.pChar+buffer1.CurrentPos)+1);
if(IsNull2[i]==false)buffer2.CurrentPos+=(strlen(buffer2.pChar+buffer2.CurrentPos)+1);
break;
}
}
else
{
switch(PAT[i].Type)
{
case BOOL: return *((bool*)(buffer1.pChar+buffer1.CurrentPos))-*((bool*)(buffer2.pChar+buffer2.CurrentPos));
case DOUBLE:buffer1.pDouble=(double*)(buffer1.pChar+buffer1.CurrentPos);
buffer2.pDouble=(double*)(buffer2.pChar+buffer2.CurrentPos);
return *buffer1.pDouble-*buffer2.pDouble;
case FLOAT: buffer1.pFloat=(float*)(buffer1.pChar+buffer1.CurrentPos);
buffer2.pFloat=(float*)(buffer2.pChar+buffer2.CurrentPos);
return *buffer1.pFloat-*buffer2.pFloat;
case LONG: buffer1.pLong=(long*)(buffer1.pChar+buffer1.CurrentPos);
buffer2.pLong=(long*)(buffer2.pChar+buffer2.CurrentPos);
return *buffer1.pLong-*buffer2.pLong;
case INT: buffer1.pInt=(int*)(buffer1.pChar+buffer1.CurrentPos);
buffer2.pInt=(int*)(buffer2.pChar+buffer2.CurrentPos);
return *buffer1.pInt-*buffer2.pInt;
case CHAR: return strcmp((buffer1.pChar+buffer1.CurrentPos),(buffer2.pChar+buffer2.CurrentPos));
}
}
}
}
//块内排序,归并函数未整合
void mergeruns(char *TableName,char *ColName,int ID)
{
FILE *fp=NULL,*tempfp=NULL;
int i,status;
PageHeadData *PHD=NULL;
Item *item=NULL;
Buffer buffer;
page=(char*)malloc(sizeof(char)*PAGESIZE);
if(GetTableInfo(ID,PCT)==1)
{
printf("您指定的临时表已存在!\n");
exit(0);
}
PCT=(PC_Tuple*)malloc(sizeof(PC_Tuple));
if(strnicmp(TableName,"pg_class",8)==0||
strnicmp(TableName,"pg_attribute",12)==0||
GetTableInfoByName(TableName,PCT)!=1)
{
printf("您要排序的表不存在!\n");
exit(0);
}
PAT=(PA_Tuple*)malloc(sizeof(PA_Tuple)*PCT->ColNum);
if(GetColInfo(PCT->ID,PAT,PCT->ColNum)!=PCT->ColNum)
{
printf("列信息不全:%d\n",PCT->ID);
exit(1);
}
for(i=0,status=0;i<PCT->ColNum;i++)
{
if(strcmp(PAT[i].ColName,ColName)==0)
{
status=1;
SortColFlag=i;
}
}
if(status==0)
{
printf("无此列");
exit(1);
}
if((fp=fopen(itoa(PCT->ID,buffer.TypeSetBuffer,10),"rb"))==NULL)
{
printf("%d 打开失败:mergeruns()\n",PCT->ID);
exit(1);
}
if((tempfp=fopen(itoa(ID,buffer.TypeSetBuffer,10),"wb"))==NULL)
{
printf("%d 临时文件创建失败:mergeruns()\n",ID);
exit(1);
}
//块内排序
for(i=0;feof(fp)==0;i++)
{
fseek(fp,PAGESIZE*i,SEEK_SET);
if(fread(page,PAGESIZE,1,fp)==0)break;
PHD=(PageHeadData*)page;
item=(Item*)(page+sizeof(PageHeadData));
qsort(item,(PHD->lower-sizeof(PageHeadData))/sizeof(Item),sizeof(Item),ItemCompare);
fseek(tempfp,0,SEEK_END);
if(fwrite(page,PAGESIZE,1,tempfp)!=1)
{
printf("%d 临时文件写入失败:insert()",ID);
exit(1);
}
}
if((fclose(fp))!=0)
{
printf("%d 关闭失败:insert()\n",ID);
exit(1);
}
}
七、函数以及用户界面函数
/******************************************主函数以及用户界面函数****************************/
//UI选项
void UserUI()
{
int input;
char choice;
for(printf("1.建表 2.展示pg_class 3.展示pg_attribute 4.插入元组 5.查看自定义表 6.Select 7.生成随机数据\nInput-->");
(choice=getchar())!='\n';
printf("\n\n1.建表 2.展示pg_class 3.展示pg_attribute 4.插入元组 5.查看自定义表 6.Select 7.生成随机数据\nInput-->"))
{
fflush(stdin);
if(choice=='1')
{
User_Create_Table();
}
else if(choice=='2')
{
ShowTableInfo();
}
else if(choice=='3')
{
ShowColInfo();
}
else if(choice=='4')
{
InsertInput();
}
else if(choice=='5')
{
ShowTable();
}
else if(choice=='6')
{
Select_Input();
}
else if(choice=='7')
{
InsertRandomInput();
}
fflush(stdin);
}
}
int main()
{
IsFirstExecutes();
UserUI();
return 0;
}
更多推荐
所有评论(0)