1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-30 21:42:05 +03:00

Convert tsqueryin and tsvectorin to report errors softly.

This is slightly tedious because the adjustments cascade through
a couple of levels of subroutines, but it's not very hard.
I chose to avoid changing function signatures more than absolutely
necessary, by passing the escontext pointer in existing structs
where possible.

tsquery's nuisance NOTICEs about empty queries are suppressed in
soft-error mode, since they're not errors and we surely don't want
them to be shown to the user anyway.  Maybe that whole behavior
should be reconsidered.

Discussion: https://postgr.es/m/3824377.1672076822@sss.pgh.pa.us
This commit is contained in:
Tom Lane
2022-12-27 12:00:31 -05:00
parent eb8312a22a
commit 78212f2101
8 changed files with 196 additions and 52 deletions

View File

@ -20,9 +20,19 @@
/*
* Private state of tsvector parser. Note that tsquery also uses this code to
* parse its input, hence the boolean flags. The two flags are both true or
* both false in current usage, but we keep them separate for clarity.
* parse its input, hence the boolean flags. The oprisdelim and is_tsquery
* flags are both true or both false in current usage, but we keep them
* separate for clarity.
*
* If oprisdelim is set, the following characters are treated as delimiters
* (in addition to whitespace): ! | & ( )
*
* is_tsquery affects *only* the content of error messages.
*
* is_web can be true to further modify tsquery parsing.
*
* If escontext is an ErrorSaveContext node, then soft errors can be
* captured there rather than being thrown.
*/
struct TSVectorParseStateData
{
@ -34,16 +44,17 @@ struct TSVectorParseStateData
bool oprisdelim; /* treat ! | * ( ) as delimiters? */
bool is_tsquery; /* say "tsquery" not "tsvector" in errors? */
bool is_web; /* we're in websearch_to_tsquery() */
Node *escontext; /* for soft error reporting */
};
/*
* Initializes parser for the input string. If oprisdelim is set, the
* following characters are treated as delimiters in addition to whitespace:
* ! | & ( )
* Initializes a parser state object for the given input string.
* A bitmask of flags (see ts_utils.h) and an error context object
* can be provided as well.
*/
TSVectorParseState
init_tsvector_parser(char *input, int flags)
init_tsvector_parser(char *input, int flags, Node *escontext)
{
TSVectorParseState state;
@ -56,12 +67,15 @@ init_tsvector_parser(char *input, int flags)
state->oprisdelim = (flags & P_TSV_OPR_IS_DELIM) != 0;
state->is_tsquery = (flags & P_TSV_IS_TSQUERY) != 0;
state->is_web = (flags & P_TSV_IS_WEB) != 0;
state->escontext = escontext;
return state;
}
/*
* Reinitializes parser to parse 'input', instead of previous input.
*
* Note that bufstart (the string reported in errors) is not changed.
*/
void
reset_tsvector_parser(TSVectorParseState state, char *input)
@ -122,23 +136,26 @@ do { \
#define WAITPOSDELIM 7
#define WAITCHARCMPLX 8
#define PRSSYNTAXERROR prssyntaxerror(state)
#define PRSSYNTAXERROR return prssyntaxerror(state)
static void
static bool
prssyntaxerror(TSVectorParseState state)
{
ereport(ERROR,
errsave(state->escontext,
(errcode(ERRCODE_SYNTAX_ERROR),
state->is_tsquery ?
errmsg("syntax error in tsquery: \"%s\"", state->bufstart) :
errmsg("syntax error in tsvector: \"%s\"", state->bufstart)));
/* In soft error situation, return false as convenience for caller */
return false;
}
/*
* Get next token from string being parsed. Returns true if successful,
* false if end of input string is reached. On success, these output
* parameters are filled in:
* false if end of input string is reached or soft error.
*
* On success, these output parameters are filled in:
*
* *strval pointer to token
* *lenval length of *strval
@ -149,7 +166,11 @@ prssyntaxerror(TSVectorParseState state)
* *poslen number of elements in *pos_ptr
* *endptr scan resumption point
*
* Pass NULL for unwanted output parameters.
* Pass NULL for any unwanted output parameters.
*
* If state->escontext is an ErrorSaveContext, then caller must check
* SOFT_ERROR_OCCURRED() to determine whether a "false" result means
* error or normal end-of-string.
*/
bool
gettoken_tsvector(TSVectorParseState state,
@ -195,7 +216,7 @@ gettoken_tsvector(TSVectorParseState state,
else if (statecode == WAITNEXTCHAR)
{
if (*(state->prsbuf) == '\0')
ereport(ERROR,
ereturn(state->escontext, false,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("there is no escaped character: \"%s\"",
state->bufstart)));
@ -313,7 +334,7 @@ gettoken_tsvector(TSVectorParseState state,
WEP_SETPOS(pos[npos - 1], LIMITPOS(atoi(state->prsbuf)));
/* we cannot get here in tsquery, so no need for 2 errmsgs */
if (WEP_GETPOS(pos[npos - 1]) == 0)
ereport(ERROR,
ereturn(state->escontext, false,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("wrong position info in tsvector: \"%s\"",
state->bufstart)));