(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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值