mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-04 00:02:52 -05:00 
			
		
		
		
	comment line where output as too long, and update typedefs for /lib directory. Also fix case where identifiers were used as variable names in the backend, but as typedefs in ecpg (favor the backend for indenting). Backpatch to 8.1.X.
		
			
				
	
	
		
			302 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			302 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include "postgres.h"
 | 
						|
#include "executor/spi.h"
 | 
						|
#include "query_util.h"
 | 
						|
 | 
						|
QTNode *
 | 
						|
QT2QTN(ITEM * in, char *operand)
 | 
						|
{
 | 
						|
	QTNode	   *node = (QTNode *) palloc0(sizeof(QTNode));
 | 
						|
 | 
						|
	node->valnode = in;
 | 
						|
 | 
						|
	if (in->type == OPR)
 | 
						|
	{
 | 
						|
		node->child = (QTNode **) palloc0(sizeof(QTNode *) * 2);
 | 
						|
		node->child[0] = QT2QTN(in + 1, operand);
 | 
						|
		node->sign = node->child[0]->sign;
 | 
						|
		if (in->val == (int4) '!')
 | 
						|
			node->nchild = 1;
 | 
						|
		else
 | 
						|
		{
 | 
						|
			node->nchild = 2;
 | 
						|
			node->child[1] = QT2QTN(in + in->left, operand);
 | 
						|
			node->sign |= node->child[1]->sign;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else if (operand)
 | 
						|
	{
 | 
						|
		node->word = operand + in->distance;
 | 
						|
		node->sign = 1 << (in->val % 32);
 | 
						|
	}
 | 
						|
 | 
						|
	return node;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
QTNFree(QTNode * in)
 | 
						|
{
 | 
						|
	if (!in)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (in->valnode->type == VAL && in->word && (in->flags & QTN_WORDFREE) != 0)
 | 
						|
		pfree(in->word);
 | 
						|
 | 
						|
	if (in->child)
 | 
						|
	{
 | 
						|
		if (in->valnode)
 | 
						|
		{
 | 
						|
			if (in->valnode->type == OPR && in->nchild > 0)
 | 
						|
			{
 | 
						|
				int			i;
 | 
						|
 | 
						|
				for (i = 0; i < in->nchild; i++)
 | 
						|
					QTNFree(in->child[i]);
 | 
						|
			}
 | 
						|
			if (in->flags & QTN_NEEDFREE)
 | 
						|
				pfree(in->valnode);
 | 
						|
		}
 | 
						|
		pfree(in->child);
 | 
						|
	}
 | 
						|
 | 
						|
	pfree(in);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
QTNodeCompare(QTNode * an, QTNode * bn)
 | 
						|
{
 | 
						|
	if (an->valnode->type != bn->valnode->type)
 | 
						|
		return (an->valnode->type > bn->valnode->type) ? -1 : 1;
 | 
						|
	else if (an->valnode->val != bn->valnode->val)
 | 
						|
		return (an->valnode->val > bn->valnode->val) ? -1 : 1;
 | 
						|
	else if (an->valnode->type == VAL)
 | 
						|
	{
 | 
						|
		if (an->valnode->length == bn->valnode->length)
 | 
						|
			return strncmp(an->word, bn->word, an->valnode->length);
 | 
						|
		else
 | 
						|
			return (an->valnode->length > bn->valnode->length) ? -1 : 1;
 | 
						|
	}
 | 
						|
	else if (an->nchild != bn->nchild)
 | 
						|
	{
 | 
						|
		return (an->nchild > bn->nchild) ? -1 : 1;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		int			i,
 | 
						|
					res;
 | 
						|
 | 
						|
		for (i = 0; i < an->nchild; i++)
 | 
						|
			if ((res = QTNodeCompare(an->child[i], bn->child[i])) != 0)
 | 
						|
				return res;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmpQTN(const void *a, const void *b)
 | 
						|
{
 | 
						|
	return QTNodeCompare(*(QTNode **) a, *(QTNode **) b);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
QTNSort(QTNode * in)
 | 
						|
{
 | 
						|
	int			i;
 | 
						|
 | 
						|
	if (in->valnode->type != OPR)
 | 
						|
		return;
 | 
						|
 | 
						|
	for (i = 0; i < in->nchild; i++)
 | 
						|
		QTNSort(in->child[i]);
 | 
						|
	if (in->nchild > 1)
 | 
						|
		qsort((void *) in->child, in->nchild, sizeof(QTNode *), cmpQTN);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
QTNEq(QTNode * a, QTNode * b)
 | 
						|
{
 | 
						|
	uint32		sign = a->sign & b->sign;
 | 
						|
 | 
						|
	if (!(sign == a->sign && sign == b->sign))
 | 
						|
		return 0;
 | 
						|
 | 
						|
	return (QTNodeCompare(a, b) == 0) ? true : false;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
QTNTernary(QTNode * in)
 | 
						|
{
 | 
						|
	int			i;
 | 
						|
 | 
						|
	if (in->valnode->type != OPR)
 | 
						|
		return;
 | 
						|
 | 
						|
	for (i = 0; i < in->nchild; i++)
 | 
						|
		QTNTernary(in->child[i]);
 | 
						|
 | 
						|
	for (i = 0; i < in->nchild; i++)
 | 
						|
	{
 | 
						|
		if (in->valnode->type == in->child[i]->valnode->type && in->valnode->val == in->child[i]->valnode->val)
 | 
						|
		{
 | 
						|
			QTNode	   *cc = in->child[i];
 | 
						|
			int			oldnchild = in->nchild;
 | 
						|
 | 
						|
			in->nchild += cc->nchild - 1;
 | 
						|
			in->child = (QTNode **) repalloc(in->child, in->nchild * sizeof(QTNode *));
 | 
						|
 | 
						|
			if (i + 1 != oldnchild)
 | 
						|
				memmove(in->child + i + cc->nchild, in->child + i + 1,
 | 
						|
						(oldnchild - i - 1) * sizeof(QTNode *));
 | 
						|
 | 
						|
			memcpy(in->child + i, cc->child, cc->nchild * sizeof(QTNode *));
 | 
						|
			i += cc->nchild - 1;
 | 
						|
 | 
						|
			pfree(cc);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
QTNBinary(QTNode * in)
 | 
						|
{
 | 
						|
	int			i;
 | 
						|
 | 
						|
	if (in->valnode->type != OPR)
 | 
						|
		return;
 | 
						|
 | 
						|
	for (i = 0; i < in->nchild; i++)
 | 
						|
		QTNBinary(in->child[i]);
 | 
						|
 | 
						|
	if (in->nchild <= 2)
 | 
						|
		return;
 | 
						|
 | 
						|
	while (in->nchild > 2)
 | 
						|
	{
 | 
						|
		QTNode	   *nn = (QTNode *) palloc0(sizeof(QTNode));
 | 
						|
 | 
						|
		nn->valnode = (ITEM *) palloc0(sizeof(ITEM));
 | 
						|
		nn->child = (QTNode **) palloc0(sizeof(QTNode *) * 2);
 | 
						|
 | 
						|
		nn->nchild = 2;
 | 
						|
		nn->flags = QTN_NEEDFREE;
 | 
						|
 | 
						|
		nn->child[0] = in->child[0];
 | 
						|
		nn->child[1] = in->child[1];
 | 
						|
		nn->sign = nn->child[0]->sign | nn->child[1]->sign;
 | 
						|
 | 
						|
		nn->valnode->type = in->valnode->type;
 | 
						|
		nn->valnode->val = in->valnode->val;
 | 
						|
 | 
						|
		in->child[0] = nn;
 | 
						|
		in->child[1] = in->child[in->nchild - 1];
 | 
						|
		in->nchild--;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
cntsize(QTNode * in, int4 *sumlen, int4 *nnode)
 | 
						|
{
 | 
						|
	*nnode += 1;
 | 
						|
	if (in->valnode->type == OPR)
 | 
						|
	{
 | 
						|
		int			i;
 | 
						|
 | 
						|
		for (i = 0; i < in->nchild; i++)
 | 
						|
			cntsize(in->child[i], sumlen, nnode);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		*sumlen += in->valnode->length + 1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
	ITEM	   *curitem;
 | 
						|
	char	   *operand;
 | 
						|
	char	   *curoperand;
 | 
						|
}	QTN2QTState;
 | 
						|
 | 
						|
static void
 | 
						|
fillQT(QTN2QTState * state, QTNode * in)
 | 
						|
{
 | 
						|
	*(state->curitem) = *(in->valnode);
 | 
						|
 | 
						|
	if (in->valnode->type == VAL)
 | 
						|
	{
 | 
						|
		memcpy(state->curoperand, in->word, in->valnode->length);
 | 
						|
		state->curitem->distance = state->curoperand - state->operand;
 | 
						|
		state->curoperand[in->valnode->length] = '\0';
 | 
						|
		state->curoperand += in->valnode->length + 1;
 | 
						|
		state->curitem++;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		ITEM	   *curitem = state->curitem;
 | 
						|
 | 
						|
		Assert(in->nchild <= 2);
 | 
						|
		state->curitem++;
 | 
						|
 | 
						|
		fillQT(state, in->child[0]);
 | 
						|
 | 
						|
		if (in->nchild == 2)
 | 
						|
		{
 | 
						|
			curitem->left = state->curitem - curitem;
 | 
						|
			fillQT(state, in->child[1]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
QUERYTYPE *
 | 
						|
QTN2QT(QTNode * in, MemoryType memtype)
 | 
						|
{
 | 
						|
	QUERYTYPE  *out;
 | 
						|
	int			len;
 | 
						|
	int			sumlen = 0,
 | 
						|
				nnode = 0;
 | 
						|
	QTN2QTState state;
 | 
						|
 | 
						|
	cntsize(in, &sumlen, &nnode);
 | 
						|
	len = COMPUTESIZE(nnode, sumlen);
 | 
						|
 | 
						|
	out = (QUERYTYPE *) MEMALLOC(memtype, len);
 | 
						|
	out->len = len;
 | 
						|
	out->size = nnode;
 | 
						|
 | 
						|
	state.curitem = GETQUERY(out);
 | 
						|
	state.operand = state.curoperand = GETOPERAND(out);
 | 
						|
 | 
						|
	fillQT(&state, in);
 | 
						|
	return out;
 | 
						|
}
 | 
						|
 | 
						|
QTNode *
 | 
						|
QTNCopy(QTNode * in, MemoryType memtype)
 | 
						|
{
 | 
						|
	QTNode	   *out = (QTNode *) MEMALLOC(memtype, sizeof(QTNode));
 | 
						|
 | 
						|
	*out = *in;
 | 
						|
	out->valnode = (ITEM *) MEMALLOC(memtype, sizeof(ITEM));
 | 
						|
	*(out->valnode) = *(in->valnode);
 | 
						|
	out->flags |= QTN_NEEDFREE;
 | 
						|
 | 
						|
	if (in->valnode->type == VAL)
 | 
						|
	{
 | 
						|
		out->word = MEMALLOC(memtype, in->valnode->length + 1);
 | 
						|
		memcpy(out->word, in->word, in->valnode->length);
 | 
						|
		out->word[in->valnode->length] = '\0';
 | 
						|
		out->flags |= QTN_WORDFREE;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		int			i;
 | 
						|
 | 
						|
		out->child = (QTNode **) MEMALLOC(memtype, sizeof(QTNode *) * in->nchild);
 | 
						|
 | 
						|
		for (i = 0; i < in->nchild; i++)
 | 
						|
			out->child[i] = QTNCopy(in->child[i], memtype);
 | 
						|
	}
 | 
						|
 | 
						|
	return out;
 | 
						|
}
 |