static char sccsid[]="%Z% %M% %I% %E% %U%";
/************************************************/
/* 検索処理										*/
/*	 WHERE 節作成関数							*/
/*----------------------------------------------*/
/************************************************/
#include "colmn.h"

#define ON	1
#define OFF	0

#define EOD	-1
#define ANT	 0
#define CMP	 1
#define LOG	 2
#define KEY	 3
#define CHR	 4
#define NUM	 5
#define LKAK	6
#define RKAK	7
#define NAM	 8
#define KIG	 9

#define TRUE	1
#define FALSE	0
#define KEYWORDS_NUM 16

#define ATR_LEN			32
#define TABLE_NUM		26
#define CAT_LINE		50

#define CNDDATA_MAX		64
#define COLSEL_MAX		64

#define BUFF_SIZE_CVCNDDATA  (CNDDATA_MAX*2)
#define BUFF_SIZE_CVCNDITION (COLSEL_MAX*2)
#define BUFF_SIZE_CVCAT	  ((ATR_LEN+1)*2+9)

#define BUFF_SIZE_ATR		BUFF_SIZE_CVCNDDATA
#define BUFF_SIZE_COLSEL	 BUFF_SIZE_CVCNDITION

#define ATTRIBUTE(n)  ItemTbl.Line[n].AttrName
#define ITEMALIAS(n)  ItemTbl.Line[n].ALIASNAME
#define CONDDATA(n)   ItemTbl.Line[n].ConditionData
#define CONDITION(n)  ViewTbl.Line[n].ColSelCondition
#define VIEWNAME(n)   ViewTbl.Line[n].ViewName
#define VIEWALIAS(n)  ViewTbl.Line[n].ALIASNAME
#define CATNUM(n)	 CatCondTbl.Line[n].CatRecNumber
#define CATATR(n)	 CatCondTbl.Line[n].AttrName
#define CATVIEW(n)	CatCondTbl.Line[n].ViewName

extern ItemTBL	ItemTbl;
extern ViewTBL	ViewTbl;
extern CatCondTBL CatCondTbl;

/****************************
*	キーワードのチェック	*
*****************************/
int iskeyword(word)
char *word;
{
	static char *keywords[] =
	{
		"like"   , "match"  , "range"  , "smatch",
		"between", "in"	 , "is"	 , "not"   ,
		"!match" , "!smatch", NULL
	};
	char **p;
 	p = keywords;
	while(*p) {
		if(!stricmp(word, *p++))
		return(TRUE);
	}
	return(FALSE);
}

/*****************************
*							 *
******************************/
int check_word(p)
char *p;
{
	int  j = 0;
	char c;

	switch(c = *p) {
	case '\0':
		return EOD;
	case '&' :
	case '|' :
		return(LOG);
	case '\'':
	case '"':
		return(CHR);
	case '(':
		return(LKAK);
	case ')':
		return(RKAK);
	case '=':
	case '>':
	case '<':
	case '!':
		return(CMP);
	case '+':
	case '-':
	case '.':
		return(NUM);
	default:
		if (c>='0' && c<='9') return(NUM);
		else if ((c>='A' && c<='Z') ||
				 (c>='a' && c<='z')) return(KEY);
	}
	return(ANT);
}

/**************************************************
*	 検索項目テーブルの条件データより条件を作成	  *
**************************************************/
char *atr_cnv_cnd(cnt, cndData)
int  cnt;
char cndData[];
{
	char *cvCndData, c, quot, *cp;
	int  indicator;
	int  type;
	char *tmp;
	char atr[ATR_LEN+4];
	MCAT mcat;

	if (!(cvCndData=(char *)Malloc(BUFF_SIZE_CVCNDDATA))) {
		ERROROUT("memory allocate error");
		return NULL;
	}
	mcat.mc_extlen = CNDDATA_MAX;
	mcat.mc_maxcnt = 0;
	mcat.mc_extcnt = 0;
	mcat.mc_alclen = BUFF_SIZE_CVCNDDATA;
	mcat.mc_bufp = cvCndData;
	mcat.mc_ipos = 0;

	*cvCndData = '\0';
	cp = cndData;
	while (*cp) {
		while ((c=*cp)==' ' || c=='\t' || c=='\n' || c==0x0d) cp++;
		if (!c) break;
		type = check_word(cp);
/* printf("atr_cnv_cnd:type = %d\n",type); */
		switch (type) {
		case CHR:
		case NUM:
		case CMP:
		case KEY:
			sprintf(atr, "%s.%s", ITEMALIAS(cnt), ATTRIBUTE(cnt));
			if (axtmcats(&mcat, atr)<0) goto Err;
			if (type==CHR || type==NUM) {
				if (axtmcat(&mcat,"=",1)<0) goto Err;
			}
			else if (type==KEY) {
				if (axtmcat(&mcat," ",1)<0) goto Err;
			}
			while (c=*cp) {
				if (c=='&') {
					if (axtmcats(&mcat," and ")<0) goto Err;
					cp++;
					break;
				}
				else if (c=='|') {
					if (axtmcats(&mcat," or ")<0) goto Err;
					cp++;
					break;
				}
				else if (c=='"' || c=='\'') {
					quot = c;
					if (axtmcat(&mcat,cp,1)<0) goto Err;
					cp++;
					for (;;) {
						c = *cp;
						if (axtmcat(&mcat,cp++,1)<0) goto Err;
						if (c == quot) {
							if (*cp == quot) {
								if (axtmcat(&mcat,cp++,1)<0) goto Err;
							}
							else break;
						}
					}
				}
				else {
					if (axtmcat(&mcat,cp++,1)<0) goto Err;
				}
			}
			break;
		case LKAK:
			if (axtmcat(&mcat,cp++,1)<0) goto Err;
			break;
		case LOG:
		default:
			goto Err;
			break;
		}
	}
	if (axtmcat(&mcat,"",1)<0) goto Err;
	return(mcat.mc_bufp);
Err:
	if (mcat.mc_bufp) Free(mcat.mc_bufp);
	return (NULL);
}

char *cl_sl_atr_cnd()
{
	char *buf;							/* 最終的に作成された条件 */
	char *tmp = NULL;
	int  flg;
	int  i;
	int  j;
	MCAT mcat;

	if( (buf = (char *)Malloc(BUFF_SIZE_ATR)) == NULL )
	{
		ERROROUT("memory allocate error");
		return NULL;
	}
	mcat.mc_extlen = CNDDATA_MAX;
	mcat.mc_maxcnt = 0;
	mcat.mc_extcnt = 0;
	mcat.mc_alclen = BUFF_SIZE_ATR;
	mcat.mc_bufp = buf;
	mcat.mc_ipos = 0;
	flg = OFF;
	*buf = '\0';

	/* 検索項目テーブルの使用行数だけループ */
	for(i=0; i<ItemTbl.iItemNum; i++)
	{
		/* 条件データが指定されている場合 */
		if( strlen(CONDDATA(i)) != 0 )
		{
			for(j=0; isspace(ItemTbl.Line[i].ConditionData[j]); j++)
				;
			if(ItemTbl.Line[i].ConditionData[j] == '\0')
				continue;
			if( ( tmp = atr_cnv_cnd(i, CONDDATA(i)) ) == NULL )
				goto Err;
			if (flg == ON) {
				if (axtmcats(&mcat,"and")<0) goto Err;
			}
			if (axtmcats(&mcat,"(")<0) goto Err;
			if (axtmcats(&mcat,tmp)<0) goto Err;
			if (axtmcats(&mcat,")")<0) goto Err;
			Free(tmp);tmp=NULL;
			flg = ON;
		}
	}
	return(mcat.mc_bufp);
Err:
	if (tmp) Free(tmp);
	if (mcat.mc_bufp) Free(mcat.mc_bufp);
	return (NULL);
}

/************************************************
*		文書検索式より条件を作成				*
*************************************************/
char *numtoatr(cnt, num, atr)
int cnt;
int num;
char *atr;
{
	int i;

	for (i=0; i<ItemTbl.iItemNum; i++) {
		if (!strcmp(VIEWALIAS(cnt), ITEMALIAS(i))) {
			if (ItemTbl.Line[i].ItemNumber == num) {
				sprintf(atr, "%s.%s", ITEMALIAS(i), ATTRIBUTE(i));
				return ATTRIBUTE(i);
			}
		}
	}
	ERROROUT(FORMAT(378));		/* 該当する項目番号が見つからない */
	return NULL;
}

char *colsel_cnv_cnd(cnt, Condition)
	int  cnt;
	char *Condition;
{

	char *cvCndition;
	char *topcv;
	char atr[ATR_LEN+4];
	char *p;
	int  j, num;
	MCAT mcat;

	if( (cvCndition = (char *)Malloc(BUFF_SIZE_CVCNDITION)) == NULL )
	{
		ERROROUT("memory allocate error");
		return NULL;
	}
	mcat.mc_extlen = COLSEL_MAX;
	mcat.mc_maxcnt = 0;
	mcat.mc_extcnt = 0;
	mcat.mc_alclen = BUFF_SIZE_CVCNDITION;
	mcat.mc_bufp = cvCndition;
	mcat.mc_ipos = 0;

	while(*Condition && *Condition==' ') Condition++;

	while(*Condition)
	{
/* printf("colsel_cnv_cnd:cond = [%s]\n",Condition); */
		if( *Condition == '#')
		{
			for(j=0,p=++Condition;isdigit(*Condition);j++,Condition++) ;
			if (axccvn(10,p,j,&num)) goto Err;
			if(!numtoatr(cnt, num, atr)) goto Err;
/* printf("colsel_cnv_cnd:atr = [%s]\n",atr); */
			if (axtmcat(&mcat,atr,strlen(atr))<0) goto Err;
		}
		else
			if (axtmcat(&mcat,Condition++,1)<0) goto Err;
/* printf("colsel_cnv_cnd:mcat.mc_ipos = %d\n",mcat.mc_ipos); */
	}
	if (axtmcat(&mcat,"",1)<0) goto Err;
	return(mcat.mc_bufp);
Err:
	if (mcat.mc_bufp) Free(mcat.mc_bufp);
	return (NULL);
}

char *cl_sl_col_sel()
{
	char *buf;							   /* 最終的に作成された条件 */
	char *tmp=NULL;
	int  flg;
	int  i, j;
	MCAT mcat;

	if( (buf = (char *)Malloc(BUFF_SIZE_CVCNDITION)) == NULL )
	{
		ERROROUT("memory allocate error");
		return NULL;
	}
	mcat.mc_extlen = BUFF_SIZE_CVCNDITION;
	mcat.mc_maxcnt = 0;
	mcat.mc_extcnt = 0;
	mcat.mc_alclen = BUFF_SIZE_CVCNDITION;
	mcat.mc_bufp = buf;
	mcat.mc_ipos = 0;

	*buf = '\0';

	/* 検索ビュー名称テーブルの使用行数だけループ */
	for(i=0, flg=OFF; i < ViewTbl.iItemNum; i++)
	{
		/* IF ObjFlag IS ON */
		if( ViewTbl.Line[i].ObjFlag )
		{
			for(j=0; isspace(ViewTbl.Line[i].ColSelCondition[j]); j++)
				;
			if(ViewTbl.Line[i].ColSelCondition[j] == '\0')
				continue;
			if( ( tmp = colsel_cnv_cnd(i,CONDITION(i)) ) == NULL )
				goto Err;
#if 0
			/* 2番目以降 -> "and" */
			sprintf(tcvCondition, (flg) ? "and(%s)" : "(%s)", tmp);
			/* 返却するエリアにコピー */
			strcat(buf, tcvCondition);
#else
			if (flg == ON) {
				if (axtmcats(&mcat,"and")<0) goto Err;
			}
			if (axtmcats(&mcat,"(")<0) goto Err;
			if (axtmcats(&mcat,tmp)<0) goto Err;
			if (axtmcats(&mcat,")")<0) goto Err;
#endif
			Free(tmp);tmp=NULL;
			flg = ON;
		}
	}
	return(mcat.mc_bufp);
Err:
	if (tmp) Free(tmp);
	if (mcat.mc_bufp) Free(mcat.mc_bufp);
	return (NULL);
}

/************************************************
*				結合条件の作成					*
*************************************************/
char *getalias(view)
	char *view;
{
	int i;
	for(i=0; i<ViewTbl.iItemNum; i++)
		if( !(strcmp(ViewTbl.Line[i].ViewName, view)) )
			return(ViewTbl.Line[i].ALIASNAME);
	ERROROUT("ViewName is not found");
	return(NULL);
}

char *cl_sl_cat_cnd()
{
	char buff[BUFF_SIZE_CVCAT];
	char *catcnd;
	char *alias1;
	char *alias2;
	int i;
	int flg;
	MCAT mcat;

	if( (catcnd = (char *)Malloc(BUFF_SIZE_CVCAT)) == NULL )
	{
		ERROROUT("memory allocate error");
		return(NULL);
	}
	mcat.mc_extlen = BUFF_SIZE_CVCAT;
	mcat.mc_maxcnt = 0;
	mcat.mc_extcnt = 0;
	mcat.mc_alclen = BUFF_SIZE_CVCAT;
	mcat.mc_bufp = catcnd;
	mcat.mc_ipos = 0;

	*catcnd = '\0';

	for(i=0, flg=OFF; i<CatCondTbl.iItemNum-1; i++)	/* 10.29 Koba */
	{
		if( CATNUM(i) == CATNUM(i+1) )
		{
			if( (alias1 = getalias(CATVIEW(i))) == NULL )
				goto Err;
			if( (alias2 = getalias(CATVIEW(i+1))) == NULL )
				goto Err;
			sprintf(buff, (flg) ? "and(%s.%s=%s.%s)" : "(%s.%s=%s.%s)",
								   alias1, CATATR(i), alias2, CATATR(i+1));
		 /* strcat(catcnd, buff); */
			if (axtmcats(&mcat,buff)<0) goto Err;
			flg = ON;
		}
	}
	return(mcat.mc_bufp);
Err:
	if (mcat.mc_bufp) Free(mcat.mc_bufp);
	return (NULL);
}

/********************************************
* cl_sl_const_where()						*
*   where文節の作成							*
*   ent: cl_sl_col_sel()					*
*		cl_sl_atr_cnd()						*
*		cl_sl_cat_cnd()						*
*********************************************/
char *cl_sl_const_where()
{
	char  *buf, *p, c, *pp;
	char  *cnd1, *cnd2, *cnd3;
	int   size1, size2, size3;
	int   i,n;

/*
*** where文節の生成
 */
	/* 検索項目テーブルの条件データより条件を作成 */
	if (!(cnd1=cl_sl_atr_cnd())) {
		ERROROUT("condition not created");
		return NULL;
	}

	/* 文書検索式より条件を作成 */
	if (!(cnd2=cl_sl_col_sel())) {
		ERROROUT("condition not created");
		Free(cnd1);cnd1=NULL;
		return NULL;
	}

	/* 結合条件の作成 */
	if (!(cnd3=cl_sl_cat_cnd())) {
		ERROROUT("condition not created");
		Free(cnd1);cnd1=NULL;
		Free(cnd2);cnd2=NULL;
		return NULL;
	}
#if 0
	if (ViewTbl.iItemNum>1 && *cnd3=='\0') {
#else
	for (n=0,i=0;i<ViewTbl.iItemNum;i++)
		if (ViewTbl.Line[i].ObjFlag) n++;
	if (n>1 && *cnd3=='\0') {
#endif
		ERROROUT(FORMAT(379));		/* 結合条件がない。 */
		Free(cnd1);
		Free(cnd2);
		Free(cnd3);
		return(NULL);
	}
#if 1
	size1 = strlen(cnd1) + strlen(cnd2) + strlen(cnd3) + 26;
	if (!(buf = (char *)Malloc(size1))) {
		ERROROUT("memory allocate error");
		Free(cnd1);
		Free(cnd2);
		Free(cnd3);
		return NULL;
	}
#endif

	/* 各条件をandで連結しwhere節を作成 */
	if (!*cnd1) {
		if (!*cnd2) {
			if (!*cnd3) *buf = '\0';
			else sprintf(buf," where %s",cnd3);
		}
		else {
			if (!*cnd3 ) sprintf(buf," where %s", cnd2);
			else sprintf(buf," where (%s) and (%s)",cnd2,cnd3);
		}
	}
	else {
		if (!*cnd2) {
			if (!*cnd3) sprintf(buf," where %s",cnd1);
			else sprintf(buf," where (%s) and (%s)",cnd1,cnd3);
		}
		else {
			if (!*cnd3) sprintf(buf," where (%s) and (%s)",cnd1,cnd2);
			else sprintf(buf," where (%s) and (%s) and (%s)",cnd1,cnd2,cnd3);
		}
	}
#if 1
	size2 = strlen(buf);
	size3 = 0;
	p = buf;
	while (c = *p++) {
		if (c=='$' || c=='#' || c=='%' || c==ESCAPE_CODE ||
			c=='"' || c=='\\' || c=='@') size3++;
	}
	if (size3) {
		if (!(pp=cnd1=Realloc(cnd1,size2+size3+1))) {
			ERROROUT("memory allocate error");
			Free(buf);
			Free(cnd2);
			Free(cnd3);
			return(NULL);
		}
		p = buf;
		while (c = *p++) {
			if (c=='$' || c=='#' || c=='%' || c==ESCAPE_CODE)
				*pp++ = ESCAPE_CODE;
			else if (c=='"' || c=='\\' || c=='@')
				*pp++ = '\\';
			*pp++ = c;
		}
		*pp = c;
		p = buf;
		buf = cnd1;
		cnd1 = p;
	}
#endif

	Free(cnd1);cnd1=NULL;
	Free(cnd2);cnd2=NULL;
	Free(cnd3);cnd3=NULL;

	/* where文節の文字列のポインターをリターン */
	return buf;
}
