tsquery.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 980 行 · 第 1/2 页

C
980
字号
	*(state.curop) = '\0';	/* parse query & make polish notation (postfix, but in reverse order) */	makepol(&state, pushval, opaque);	close_tsvector_parser(state.valstate);	if (list_length(state.polstr) == 0)	{		ereport(NOTICE,				(errmsg("text-search query doesn't contain lexemes: \"%s\"",						state.buffer)));		query = (TSQuery) palloc(HDRSIZETQ);		SET_VARSIZE(query, HDRSIZETQ);		query->size = 0;		return query;	}	/* Pack the QueryItems in the final TSQuery struct to return to caller */	commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen);	query = (TSQuery) palloc0(commonlen);	SET_VARSIZE(query, commonlen);	query->size = list_length(state.polstr);	ptr = GETQUERY(query);	/* Copy QueryItems to TSQuery */	i = 0;	foreach(cell, state.polstr)	{		QueryItem  *item = (QueryItem *) lfirst(cell);		switch (item->type)		{			case QI_VAL:				memcpy(&ptr[i], item, sizeof(QueryOperand));				break;			case QI_VALSTOP:				ptr[i].type = QI_VALSTOP;				break;			case QI_OPR:				memcpy(&ptr[i], item, sizeof(QueryOperator));				break;			default:				elog(ERROR, "unrecognized QueryItem type: %d", item->type);		}		i++;	}	/* Copy all the operand strings to TSQuery */	memcpy((void *) GETOPERAND(query), (void *) state.op, state.sumlen);	pfree(state.op);	/* Set left operand pointers for every operator. */	findoprnd(ptr, query->size);	return query;}static voidpushval_asis(Datum opaque, TSQueryParserState state, char *strval, int lenval,			 int16 weight){	pushValue(state, strval, lenval, weight);}/* * in without morphology */Datumtsqueryin(PG_FUNCTION_ARGS){	char	   *in = PG_GETARG_CSTRING(0);	pg_verifymbstr(in, strlen(in), false);	PG_RETURN_TSQUERY(parse_tsquery(in, pushval_asis, PointerGetDatum(NULL), false));}/* * out function */typedef struct{	QueryItem  *curpol;	char	   *buf;	char	   *cur;	char	   *op;	int			buflen;} INFIX;/* Makes sure inf->buf is large enough for adding 'addsize' bytes */#define RESIZEBUF(inf, addsize) \while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) \{ \	int len = (inf)->cur - (inf)->buf; \	(inf)->buflen *= 2; \	(inf)->buf = (char*) repalloc( (void*)(inf)->buf, (inf)->buflen ); \	(inf)->cur = (inf)->buf + len; \}/* * recursive walk on tree and print it in * infix (human-readable) view */static voidinfix(INFIX *in, bool first){	/* since this function recurses, it could be driven to stack overflow. */	check_stack_depth();	if (in->curpol->type == QI_VAL)	{		QueryOperand *curpol = &in->curpol->operand;		char	   *op = in->op + curpol->distance;		int			clen;		RESIZEBUF(in, curpol->length * (pg_database_encoding_max_length() + 1) + 2 + 5);		*(in->cur) = '\'';		in->cur++;		while (*op)		{			if (t_iseq(op, '\''))			{				*(in->cur) = '\'';				in->cur++;			}			else if (t_iseq(op, '\\'))			{				*(in->cur) = '\\';				in->cur++;			}			COPYCHAR(in->cur, op);			clen = pg_mblen(op);			op += clen;			in->cur += clen;		}		*(in->cur) = '\'';		in->cur++;		if (curpol->weight)		{			*(in->cur) = ':';			in->cur++;			if (curpol->weight & (1 << 3))			{				*(in->cur) = 'A';				in->cur++;			}			if (curpol->weight & (1 << 2))			{				*(in->cur) = 'B';				in->cur++;			}			if (curpol->weight & (1 << 1))			{				*(in->cur) = 'C';				in->cur++;			}			if (curpol->weight & 1)			{				*(in->cur) = 'D';				in->cur++;			}		}		*(in->cur) = '\0';		in->curpol++;	}	else if (in->curpol->operator.oper == OP_NOT)	{		bool		isopr = false;		RESIZEBUF(in, 1);		*(in->cur) = '!';		in->cur++;		*(in->cur) = '\0';		in->curpol++;		if (in->curpol->type == QI_OPR)		{			isopr = true;			RESIZEBUF(in, 2);			sprintf(in->cur, "( ");			in->cur = strchr(in->cur, '\0');		}		infix(in, isopr);		if (isopr)		{			RESIZEBUF(in, 2);			sprintf(in->cur, " )");			in->cur = strchr(in->cur, '\0');		}	}	else	{		int8		op = in->curpol->operator.oper;		INFIX		nrm;		in->curpol++;		if (op == OP_OR && !first)		{			RESIZEBUF(in, 2);			sprintf(in->cur, "( ");			in->cur = strchr(in->cur, '\0');		}		nrm.curpol = in->curpol;		nrm.op = in->op;		nrm.buflen = 16;		nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);		/* get right operand */		infix(&nrm, false);		/* get & print left operand */		in->curpol = nrm.curpol;		infix(in, false);		/* print operator & right operand */		RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));		switch (op)		{			case OP_OR:				sprintf(in->cur, " | %s", nrm.buf);				break;			case OP_AND:				sprintf(in->cur, " & %s", nrm.buf);				break;			default:				/* OP_NOT is handled in above if-branch */				elog(ERROR, "unrecognized operator type: %d", op);		}		in->cur = strchr(in->cur, '\0');		pfree(nrm.buf);		if (op == OP_OR && !first)		{			RESIZEBUF(in, 2);			sprintf(in->cur, " )");			in->cur = strchr(in->cur, '\0');		}	}}Datumtsqueryout(PG_FUNCTION_ARGS){	TSQuery		query = PG_GETARG_TSQUERY(0);	INFIX		nrm;	if (query->size == 0)	{		char	   *b = palloc(1);		*b = '\0';		PG_RETURN_POINTER(b);	}	nrm.curpol = GETQUERY(query);	nrm.buflen = 32;	nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);	*(nrm.cur) = '\0';	nrm.op = GETOPERAND(query);	infix(&nrm, true);	PG_FREE_IF_COPY(query, 0);	PG_RETURN_CSTRING(nrm.buf);}/* * Binary Input / Output functions. The binary format is as follows: * * uint32	 number of operators/operands in the query * * Followed by the operators and operands, in prefix notation. For each * operand: * * uint8	type, QI_VAL * uint8	weight *			operand text in client encoding, null-terminated * * For each operator: * uint8	type, QI_OPR * uint8	operator, one of OP_AND, OP_OR, OP_NOT. */Datumtsquerysend(PG_FUNCTION_ARGS){	TSQuery		query = PG_GETARG_TSQUERY(0);	StringInfoData buf;	int			i;	QueryItem  *item = GETQUERY(query);	pq_begintypsend(&buf);	pq_sendint(&buf, query->size, sizeof(uint32));	for (i = 0; i < query->size; i++)	{		pq_sendint(&buf, item->type, sizeof(item->type));		switch (item->type)		{			case QI_VAL:				pq_sendint(&buf, item->operand.weight, sizeof(uint8));				pq_sendstring(&buf, GETOPERAND(query) + item->operand.distance);				break;			case QI_OPR:				pq_sendint(&buf, item->operator.oper, sizeof(item->operator.oper));				break;			default:				elog(ERROR, "unrecognized tsquery node type: %d", item->type);		}		item++;	}	PG_FREE_IF_COPY(query, 0);	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}Datumtsqueryrecv(PG_FUNCTION_ARGS){	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);	TSQuery		query;	int			i,				len;	QueryItem  *item;	int			datalen;	char	   *ptr;	uint32		size;	const char **operands;	size = pq_getmsgint(buf, sizeof(uint32));	if (size > (MaxAllocSize / sizeof(QueryItem)))		elog(ERROR, "invalid size of tsquery");	/* Allocate space to temporarily hold operand strings */	operands = palloc(size * sizeof(char *));	/* Allocate space for all the QueryItems. */	len = HDRSIZETQ + sizeof(QueryItem) * size;	query = (TSQuery) palloc0(len);	query->size = size;	item = GETQUERY(query);	datalen = 0;	for (i = 0; i < size; i++)	{		item->type = (int8) pq_getmsgint(buf, sizeof(int8));		if (item->type == QI_VAL)		{			size_t		val_len;	/* length after recoding to server encoding */			uint8		weight;			const char *val;			pg_crc32	valcrc;			weight = (uint8) pq_getmsgint(buf, sizeof(uint8));			val = pq_getmsgstring(buf);			val_len = strlen(val);			/* Sanity checks */			if (weight > 0xF)				elog(ERROR, "invalid tsquery: invalid weight bitmap");			if (val_len > MAXSTRLEN)				elog(ERROR, "invalid tsquery: operand too long");			if (datalen > MAXSTRPOS)				elog(ERROR, "invalid tsquery: total operand length exceeded");			/* Looks valid. */			INIT_CRC32(valcrc);			COMP_CRC32(valcrc, val, val_len);			FIN_CRC32(valcrc);			item->operand.weight = weight;			item->operand.valcrc = (int32) valcrc;			item->operand.length = val_len;			item->operand.distance = datalen;			/*			 * Operand strings are copied to the final struct after this loop;			 * here we just collect them to an array			 */			operands[i] = val;			datalen += val_len + 1;		/* + 1 for the '\0' terminator */		}		else if (item->type == QI_OPR)		{			int8		oper;			oper = (int8) pq_getmsgint(buf, sizeof(int8));			if (oper != OP_NOT && oper != OP_OR && oper != OP_AND)				elog(ERROR, "invalid tsquery: unrecognized operator type %d",					 (int) oper);			if (i == size - 1)				elog(ERROR, "invalid pointer to right operand");			item->operator.oper = oper;		}		else			elog(ERROR, "unrecognized tsquery node type: %d", item->type);		item++;	}	/* Enlarge buffer to make room for the operand values. */	query = (TSQuery) repalloc(query, len + datalen);	item = GETQUERY(query);	ptr = GETOPERAND(query);	/*	 * Fill in the left-pointers. Checks that the tree is well-formed as a	 * side-effect.	 */	findoprnd(item, size);	/* Copy operands to output struct */	for (i = 0; i < size; i++)	{		if (item->type == QI_VAL)		{			memcpy(ptr, operands[i], item->operand.length + 1);			ptr += item->operand.length + 1;		}		item++;	}	pfree(operands);	Assert(ptr - GETOPERAND(query) == datalen);	SET_VARSIZE(query, len + datalen);	PG_RETURN_TSVECTOR(query);}/* * debug function, used only for view query * which will be executed in non-leaf pages in index */Datumtsquerytree(PG_FUNCTION_ARGS){	TSQuery		query = PG_GETARG_TSQUERY(0);	INFIX		nrm;	text	   *res;	QueryItem  *q;	int			len;	if (query->size == 0)	{		res = (text *) palloc(VARHDRSZ);		SET_VARSIZE(res, VARHDRSZ);		PG_RETURN_POINTER(res);	}	q = clean_NOT(GETQUERY(query), &len);	if (!q)	{		res = (text *) palloc(1 + VARHDRSZ);		SET_VARSIZE(res, 1 + VARHDRSZ);		*((char *) VARDATA(res)) = 'T';	}	else	{		nrm.curpol = q;		nrm.buflen = 32;		nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);		*(nrm.cur) = '\0';		nrm.op = GETOPERAND(query);		infix(&nrm, true);		res = (text *) palloc(nrm.cur - nrm.buf + VARHDRSZ);		SET_VARSIZE(res, nrm.cur - nrm.buf + VARHDRSZ);		strncpy(VARDATA(res), nrm.buf, nrm.cur - nrm.buf);		pfree(q);	}	PG_FREE_IF_COPY(query, 0);	PG_RETURN_POINTER(res);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?