# include	<symbol.h>
# include	<ingres.h>
# include	<tree.h>
# include	<aux.h>
# include	<sccs.h>

SCCSID(@(#)pr_tree.c	8.3	5/1/86)

/*
**  PR_TREE.C -- Query tree printing routines
**
**	Trace Flags:
**		52
*/




char	*pr_trim();
char	*resultres();

struct tab
{
	char	t_opcode;
	char	*t_string;
};


struct tab	Uop_tab[] =
{
	opPLUS,		"+ ",
	opMINUS,	"- ",
	opNOT,		"not[ERROR]",
	opATAN,		"atan",
	opCOS,		"cos",
	opGAMMA,	"gamma",
	opLOG,		"log",
	opASCII,	"ascii",
	opSIN,		"sin",
	opSQRT,		"sqrt",
	opABS,		"abs",
	opEXP,		"exp",
	opINT1,		"int1",
	opINT2,		"int2",
	opINT4,		"int4",
	opFLOAT4,	"float4",
	opFLOAT8,	"float8",
};
struct tab	Bop_tab[] =
{
	opADD,		"+",
	opSUB,		"-",
	opMUL,		"*",
	opDIV,		"/",
	opPOW,		"**",
	opEQ,		"=",
	opNE,		"!=",
	opLT,		"<",
	opLE,		"<=",
	opGT,		">",
	opGE,		">=",
	opMOD,		"%",
};

struct tab	Cop_tab[] =
{
	opDBA,		"dba",
	opUSERCODE,	"usercode",
	opDATE,		"date",
	opTIME,		"time",
};

struct tab	Aop_tab[] =
{
	opCOUNT,	"count",
	opCOUNTU,	"countu",
	opSUM,		"sum",
	opSUMU,		"sumu",
	opAVG,		"avg",
	opAVGU,		"avgu",
	opMIN,		"min",
	opMAX,		"max",
	opANY,		"any",
};


DESC		Attdes;
int		Tl_elm;
int		Dom_num;
char		*Resrel;
/* 
**  PR_TREE
**
**	tree:	tl_clause ROOT tl_clause
**
**	prints out a tree assuming a mdVIEW-like mode
**
*/

pr_tree(root)
QTREE	*root;
{

#	ifdef xZTR1
	if (tTf(52, -1))
		printf("pr_tree: root %u Resultvar %d Resrel %s\n",
			root, Qt.qt_resvar, Resrel);
#	endif

	printf("%s ", pr_trim(resultres(), MAXNAME));

	pr_dom_init();
	Tl_elm = 0;

	/* print target list */
	printf("(\n");
	pr_tl_clause(root->left, TRUE);
	putchar(')');

	/* print qualification */
	if (root->right->sym.type != QLEND)
	{
                printf("\nwhere ");
		pr_qual(root->right);
	}
	putchar('\n');
}
/*
**  PR_TL_CLAUSE
**
**	tl_clause:	TREE
**		|	tl_clause RESDOM expr
**	
** target_flag = "in a target list (as opposed to in a by list)"
*/

pr_tl_clause(t_l, target_flag)
QTREE		*t_l;
register bool	target_flag;
{

#	ifdef xZTR1
	if (tTf(52, 1))
		printf("tl_clause target %d Tl_elm %d\n", target_flag, Tl_elm);
#	endif

	if (t_l->sym.type != TREE)
	{
		pr_tl_clause(t_l->left, target_flag);
		if (Tl_elm)
		{
			printf(", ");
			if (target_flag)
				putchar('\n');
		}
		/* print out info on result variable */
		pr_resdom(t_l, target_flag);
		pr_expr(t_l->right);
		Tl_elm++;
	}
}
/*
**  PR_RESDOM
**
**	print out info on a result attribute.
**	this will be done only if the RESDOM node
**	is inside a target_list and if the Qt.qt_resvar >= 0.
**	Qt.qt_resvar == -1 inside a target list indicates that this is
**	a retrieve to terminal.
*/

pr_resdom(resdom, target_flag)
QTREE	*resdom;
int	target_flag;
{

#	ifdef xZTR1
	if (tTf(52, 2))
		printf("pr_resdom: target_flag %d\n", target_flag);
#	endif

	if (target_flag)
	{
		printf("\t");
		pr_attname(resultres(), resdom->sym.value.sym_resdom.resno);
		printf(" = ");
	}
}
/* 
**  PR_ATTNAME
**
**	give a relation name, and the attribute number of that
**	relation, looks in the attribute relation for the name of the
**	attribute.
*/

pr_attname(rel, attno)
char	*rel;
int	attno;
{
	TID			tid;
	struct attribute	key, tuple;
	short			attnum;
	register		i;

#	ifdef xZTR1
	if (tTf(52, 3))
		printf("pr_attname: rel %s attno %d\n",
		rel, attno);
#	endif

	if (attno == 0)
	{
		printf("tid");
		return;
	}
	opencatalog("attribute", OR_READ);
	clearkeys(&Attdes);
	attnum = (short) attno;
	setkey(&Attdes, &key, rel, ATTRELID);
	setkey(&Attdes, &key, &attnum, ATTID);
	i = getequal(&Attdes, &key, &tuple, &tid);
	if (i)
		syserr("pr_attname: bad getequal %d rel %s attno %d",
		i, rel, attno);
	printf("%s", pr_trim(tuple.attname, MAXNAME));
}
/*
**  PR_EXPR
**
**	expr:		VAR
**		|	expr BOP expr
**		|	expr UOP
**		|	AOP AGHEAD qual
**			  \
**			   expr
**		|	BYHEAD	  AGHEAD qual
**		        /    \
**		tl_clause     AOP
**				\
**				 expr
**		|	INT
**		|	FLOAT
**		| 	CHAR
*/

pr_expr(e)
register QTREE	*e;
{
	register int	op;
	register int	tl_elm;

	switch (e->sym.type)
	{
	  case VAR:
		pr_var(e);
		break;

	  case BOP:
		if (e->sym.value.sym_op.opno == opCONCAT)
		{
			printf("concat(");
			pr_expr(e->left);
			printf(", ");
			pr_expr(e->right);
			putchar(')');
		}
		else
		{
			putchar('(');
			pr_expr(e->left);
			pr_op(BOP, e->sym.value.sym_op.opno);
			pr_expr(e->right);
			putchar(')');
		}
		break;

	  case UOP:
		if ((op = e->sym.value.sym_op.opno) == opMINUS || op == opPLUS || op == opNOT)
		{
			pr_op(UOP, e->sym.value.sym_op.opno);
			pr_expr(e->left);
			putchar(')');
		}
		else
		{
			/* functional operators */
			pr_op(UOP, e->sym.value.sym_op.opno);
			pr_expr(e->left);
			putchar(')');
		}
		break;

	  case AGHEAD:
		if (e->left->sym.type == AOP)
		{
			/* simple aggregate */
			pr_op(AOP, e->left->sym.value.sym_op.opno);
			pr_expr(e->left->right);
			if (e->right->sym.type != QLEND)
			{
				printf("\where ");
				pr_qual(e->right);
			}
			putchar(')');
		}
		else
		{
			/* aggregate function */
			pr_op(AOP, e->left->right->sym.value.sym_op.opno);
			pr_expr(e->left->right->right);
			printf(" by ");
			/* avoid counting target list elements
			 * in determining wether to put out
			 * commas after list's elements
			 */
			tl_elm = Tl_elm;
			Tl_elm = 0;
			pr_tl_clause(e->left->left, FALSE);
			Tl_elm = tl_elm;
			if (e->right->sym.type != QLEND)
			{
				printf("\n\t\twhere ");
				pr_qual(e->right);
			}
			putchar(')');
		}
		break;
	  
	  case INT:
	  case FLOAT:
	  case CHAR:
		pr_const(e);
		break;

	  default:
		syserr("expr %d", e->sym.type);
	}
}
/*
**  PR_CONST -- print constant
*/

pr_const(c)
register QTREE	*c;
{
	register char	*cp;
	register int	i;
	char		ch;
	double		d;

	switch (c->sym.type)
	{
	  case INT:
		if (c->sym.len == 1)
			printf("%d", c->sym.value.sym_data.i1type);
		else if (c->sym.len == 2)
			printf("%d", c->sym.value.sym_data.i2type);
		else	/* i4 */
			printf("%D", c->sym.value.sym_data.i4type);
		break;

	  case FLOAT:
		if (c->sym.len == 4)
			d = c->sym.value.sym_data.f4type;
		else
			d = c->sym.value.sym_data.f8type;
		printf("%-10.3f", d);
		break;

	  case CHAR:
		printf("\"");
		cp = c->sym.value.sym_data.c0type;
		for (i = c->sym.len; i--; cp++)
		{
			if (any(*cp, "\"\\[]*?") == TRUE)
				putchar('\\');

			if (*cp >= ' ')
			{
				putchar(*cp);
				continue;
			}
			/* perform pattern matching character replacement */
			switch (*cp)
			{
			  case PAT_ANY:
				ch = '*';
				break;
			
			  case PAT_ONE:
				ch = '?';
				break;
			
			  case PAT_LBRAC:
				ch = '[';
				break;

			  case PAT_RBRAC:
				ch = ']';
				break;

			  default:
				ch = *cp;
			}
			putchar(ch);
		}
		putchar('"');
		break;

	  default:
		syserr("bad constant %d", c->sym.type);
	}
}
/*
**  PR_OP -- print out operator of a certain type
*/

pr_op(op_type, op_code)
int		op_type;
register int	op_code;
{
	register struct tab	*s;

	switch (op_type)
	{
	  case UOP:
		s = &Uop_tab[op_code];
		printf("%s(", s->t_string);
		break;

	  case BOP:
		s = &Bop_tab[op_code];
		printf(" %s ", s->t_string);
		break;

	  case AOP:
		s = &Aop_tab[op_code];
		printf("%s(", s->t_string);
		break;

	  case COP:
		s = &Cop_tab[op_code];
		printf("%s", s->t_string);
		break;
	}
	if (op_code != s->t_opcode)
		syserr("pr_op: op in wrong place type %d, code %d", op_type,
		s->t_opcode);
}
/*
**  PR_VAR
**
**	print a VAR node: that is, a var.attno pair
**	at present the var part is the relation name over which var
**	ranges.
*/

pr_var(var)
QTREE	*var;
{

#	ifdef xZTR1
	if (tTf(52, 4))
		printf("pr_var(var=%d)\n", var);
#	endif
	pr_rv(var->sym.value.sym_var.varno);
	putchar('.');
	pr_attname(Qt.qt_rangev[var->sym.value.sym_var.varno].rngvdesc->reldum.relid, var->sym.value.sym_var.attno);
}
/*
**  PR_QUAL
**
**	qual:		QLEND
**		|	q_clause AND qual
**
*/

pr_qual(q)
register QTREE	*q;
{

	pr_q_clause(q->left);
	if (q->right->sym.type != QLEND)
	{
		printf(" and ");
		pr_qual(q->right);
	}
}
/*
**  PR_Q_CLAUSE
**
**	q_clause:	q_clause OR q_clause
**		|	expr
*/

pr_q_clause(q)
QTREE	*q;
{

	if (q->sym.type == OR)
	{
		pr_q_clause(q->left);
		printf(" or ");
		pr_q_clause(q->right);
	}
	else
		pr_expr(q);
}
/*
**  PR_TRIM
*/

char *
pr_trim(s, l)
register char	*s;
register int	l;
{
	static char	buf[30];

	bmove(s, buf, l);
	for (s = buf; l && *s != ' ' && *s; --l)
		s++;
	*s = '\0';
	return (buf);
}
/*
**  PR_DOM_INIT
*/

pr_dom_init()
{
	Dom_num = 0;
}

pr_ddom()
{
	printf("d%d = ", Dom_num++);
}
/*
**  PR_RANGE -- print the range table
*/

pr_range()
{
	register int	i;

	for (i = 0; i <= MAXVAR; i++)
	{
		if (Qt.qt_rangev[i].rngvdesc != NULL)
		{
			printf("range of ");
			pr_rv(i);
			printf(" is %s\n", 
			  pr_trim(Qt.qt_rangev[i].rngvdesc->reldum.relid, MAXNAME));
		}
	}
}
/*
**  PR_RV -- print range variable
*/

pr_rv(re)
register int	re;
{
	register int	j;
	register char	ch;

	ch = Qt.qt_rangev[re].rngvdesc->reldum.relid[0];

#	ifdef xZTR1
	if (tTf(52, 6))
		printf("pr_rv(%d) ch '%c'\n", re, ch);
#	endif
	
	for (j = 0; j <= MAXVAR; j++)
	{
		if (Qt.qt_rangev[j].rngvdesc == NULL)
			continue;
		if (ch == Qt.qt_rangev[j].rngvdesc->reldum.relid[0])
			break;
	}
	if (j < re)
		printf("rv%d", re);
	else
		printf("%c", ch);
}
/*
**  RESULTRES
*/

char *
resultres()
{
	extern char	*Resrel;

#	ifdef xZTR1
	if (tTf(52, 5))
		printf("resultres: Resultvar %d, Resrel %s\n", Qt.qt_resvar, Resrel);
#	endif
	if (Qt.qt_resvar > 0)
		return (Qt.qt_rangev[Qt.qt_resvar].rngvdesc->reldum.relid);
	if (Resrel == 0)
		syserr("resultres: Resrel == 0");

	return (Resrel);
}

any(c, s)
register char	c;
register char	*s;
{

	while (*s != '\0')
		if (*s++ == c)
			return (TRUE);
	return (FALSE);
}
