Commit fbeb9da2 authored by Tom Lane's avatar Tom Lane

Improve error reporting for problems in text search configuration files

by installing an error context subroutine that will provide the file name
and line number for all errors detected while reading a config file.
Some of the reader routines were already doing that in an ad-hoc way for
errors detected directly in the reader, but it didn't help for problems
detected in subroutines, such as encoding violations.

Back-patch to 8.3 because 8.3 is where people will be trying to debug
configuration files.
parent 9de09c08
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Copyright (c) 2007-2008, PostgreSQL Global Development Group * Copyright (c) 2007-2008, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/contrib/dict_xsyn/dict_xsyn.c,v 1.4 2008/01/01 20:31:21 tgl Exp $ * $PostgreSQL: pgsql/contrib/dict_xsyn/dict_xsyn.c,v 1.5 2008/06/18 20:55:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include "commands/defrem.h" #include "commands/defrem.h"
#include "fmgr.h" #include "fmgr.h"
#include "storage/fd.h"
#include "tsearch/ts_locale.h" #include "tsearch/ts_locale.h"
#include "tsearch/ts_utils.h" #include "tsearch/ts_utils.h"
...@@ -75,17 +74,17 @@ static void ...@@ -75,17 +74,17 @@ static void
read_dictionary(DictSyn *d, char *filename) read_dictionary(DictSyn *d, char *filename)
{ {
char *real_filename = get_tsearch_config_filename(filename, "rules"); char *real_filename = get_tsearch_config_filename(filename, "rules");
FILE *fin; tsearch_readline_state trst;
char *line; char *line;
int cur = 0; int cur = 0;
if ((fin = AllocateFile(real_filename, "r")) == NULL) if (!tsearch_readline_begin(&trst, real_filename))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not open synonym file \"%s\": %m", errmsg("could not open synonym file \"%s\": %m",
real_filename))); real_filename)));
while ((line = t_readline(fin)) != NULL) while ((line = tsearch_readline(&trst)) != NULL)
{ {
char *value; char *value;
char *key; char *key;
...@@ -119,7 +118,7 @@ read_dictionary(DictSyn *d, char *filename) ...@@ -119,7 +118,7 @@ read_dictionary(DictSyn *d, char *filename)
cur++; cur++;
} }
FreeFile(fin); tsearch_readline_end(&trst);
d->len = cur; d->len = cur;
if (cur > 1) if (cur > 1)
......
...@@ -7,14 +7,13 @@ ...@@ -7,14 +7,13 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tsearch/dict_synonym.c,v 1.8 2008/03/10 03:01:28 tgl Exp $ * $PostgreSQL: pgsql/src/backend/tsearch/dict_synonym.c,v 1.9 2008/06/18 20:55:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "storage/fd.h"
#include "tsearch/ts_locale.h" #include "tsearch/ts_locale.h"
#include "tsearch/ts_public.h" #include "tsearch/ts_public.h"
#include "tsearch/ts_utils.h" #include "tsearch/ts_utils.h"
...@@ -79,7 +78,7 @@ dsynonym_init(PG_FUNCTION_ARGS) ...@@ -79,7 +78,7 @@ dsynonym_init(PG_FUNCTION_ARGS)
ListCell *l; ListCell *l;
char *filename = NULL; char *filename = NULL;
bool case_sensitive = false; bool case_sensitive = false;
FILE *fin; tsearch_readline_state trst;
char *starti, char *starti,
*starto, *starto,
*end = NULL; *end = NULL;
...@@ -108,7 +107,7 @@ dsynonym_init(PG_FUNCTION_ARGS) ...@@ -108,7 +107,7 @@ dsynonym_init(PG_FUNCTION_ARGS)
filename = get_tsearch_config_filename(filename, "syn"); filename = get_tsearch_config_filename(filename, "syn");
if ((fin = AllocateFile(filename, "r")) == NULL) if (!tsearch_readline_begin(&trst, filename))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not open synonym file \"%s\": %m", errmsg("could not open synonym file \"%s\": %m",
...@@ -116,7 +115,7 @@ dsynonym_init(PG_FUNCTION_ARGS) ...@@ -116,7 +115,7 @@ dsynonym_init(PG_FUNCTION_ARGS)
d = (DictSyn *) palloc0(sizeof(DictSyn)); d = (DictSyn *) palloc0(sizeof(DictSyn));
while ((line = t_readline(fin)) != NULL) while ((line = tsearch_readline(&trst)) != NULL)
{ {
starti = findwrd(line, &end); starti = findwrd(line, &end);
if (!starti) if (!starti)
...@@ -175,7 +174,7 @@ skipline: ...@@ -175,7 +174,7 @@ skipline:
pfree(line); pfree(line);
} }
FreeFile(fin); tsearch_readline_end(&trst);
d->len = cur; d->len = cur;
qsort(d->syn, d->len, sizeof(Syn), compareSyn); qsort(d->syn, d->len, sizeof(Syn), compareSyn);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tsearch/dict_thesaurus.c,v 1.11 2008/01/01 19:45:52 momjian Exp $ * $PostgreSQL: pgsql/src/backend/tsearch/dict_thesaurus.c,v 1.12 2008/06/18 20:55:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "storage/fd.h"
#include "tsearch/ts_cache.h" #include "tsearch/ts_cache.h"
#include "tsearch/ts_locale.h" #include "tsearch/ts_locale.h"
#include "tsearch/ts_public.h" #include "tsearch/ts_public.h"
...@@ -169,21 +168,19 @@ addWrd(DictThesaurus *d, char *b, char *e, uint16 idsubst, uint16 nwrd, uint16 p ...@@ -169,21 +168,19 @@ addWrd(DictThesaurus *d, char *b, char *e, uint16 idsubst, uint16 nwrd, uint16 p
static void static void
thesaurusRead(char *filename, DictThesaurus *d) thesaurusRead(char *filename, DictThesaurus *d)
{ {
FILE *fh; tsearch_readline_state trst;
int lineno = 0;
uint16 idsubst = 0; uint16 idsubst = 0;
bool useasis = false; bool useasis = false;
char *line; char *line;
filename = get_tsearch_config_filename(filename, "ths"); filename = get_tsearch_config_filename(filename, "ths");
fh = AllocateFile(filename, "r"); if (!tsearch_readline_begin(&trst, filename))
if (!fh)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not open thesaurus file \"%s\": %m", errmsg("could not open thesaurus file \"%s\": %m",
filename))); filename)));
while ((line = t_readline(fh)) != NULL) while ((line = tsearch_readline(&trst)) != NULL)
{ {
char *ptr; char *ptr;
int state = TR_WAITLEX; int state = TR_WAITLEX;
...@@ -191,8 +188,6 @@ thesaurusRead(char *filename, DictThesaurus *d) ...@@ -191,8 +188,6 @@ thesaurusRead(char *filename, DictThesaurus *d)
uint16 posinsubst = 0; uint16 posinsubst = 0;
uint16 nwrd = 0; uint16 nwrd = 0;
lineno++;
ptr = line; ptr = line;
/* is it a comment? */ /* is it a comment? */
...@@ -213,13 +208,9 @@ thesaurusRead(char *filename, DictThesaurus *d) ...@@ -213,13 +208,9 @@ thesaurusRead(char *filename, DictThesaurus *d)
if (t_iseq(ptr, ':')) if (t_iseq(ptr, ':'))
{ {
if (posinsubst == 0) if (posinsubst == 0)
{
FreeFile(fh);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("unexpected delimiter at line %d of thesaurus file \"%s\"", errmsg("unexpected delimiter")));
lineno, filename)));
}
state = TR_WAITSUBS; state = TR_WAITSUBS;
} }
else if (!t_isspace(ptr)) else if (!t_isspace(ptr))
...@@ -269,8 +260,7 @@ thesaurusRead(char *filename, DictThesaurus *d) ...@@ -269,8 +260,7 @@ thesaurusRead(char *filename, DictThesaurus *d)
if (ptr == beginwrd) if (ptr == beginwrd)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("unexpected end of line or lexeme at line %d of thesaurus file \"%s\"", errmsg("unexpected end of line or lexeme")));
lineno, filename)));
addWrd(d, beginwrd, ptr, idsubst, nwrd++, posinsubst, useasis); addWrd(d, beginwrd, ptr, idsubst, nwrd++, posinsubst, useasis);
state = TR_WAITSUBS; state = TR_WAITSUBS;
} }
...@@ -286,28 +276,23 @@ thesaurusRead(char *filename, DictThesaurus *d) ...@@ -286,28 +276,23 @@ thesaurusRead(char *filename, DictThesaurus *d)
if (ptr == beginwrd) if (ptr == beginwrd)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("unexpected end of line or lexeme at line %d of thesaurus file \"%s\"", errmsg("unexpected end of line or lexeme")));
lineno, filename)));
addWrd(d, beginwrd, ptr, idsubst, nwrd++, posinsubst, useasis); addWrd(d, beginwrd, ptr, idsubst, nwrd++, posinsubst, useasis);
} }
idsubst++; idsubst++;
if (!(nwrd && posinsubst)) if (!(nwrd && posinsubst))
{
FreeFile(fh);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("unexpected end of line at line %d of thesaurus file \"%s\"", errmsg("unexpected end of line")));
lineno, filename)));
}
pfree(line); pfree(line);
} }
d->nsubst = idsubst; d->nsubst = idsubst;
FreeFile(fh); tsearch_readline_end(&trst);
} }
static TheLexeme * static TheLexeme *
......
...@@ -7,14 +7,13 @@ ...@@ -7,14 +7,13 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tsearch/spell.c,v 1.11 2008/01/21 02:46:10 tgl Exp $ * $PostgreSQL: pgsql/src/backend/tsearch/spell.c,v 1.12 2008/06/18 20:55:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "storage/fd.h"
#include "tsearch/dicts/spell.h" #include "tsearch/dicts/spell.h"
#include "tsearch/ts_locale.h" #include "tsearch/ts_locale.h"
#include "utils/memutils.h" #include "utils/memutils.h"
...@@ -194,18 +193,18 @@ NIAddSpell(IspellDict *Conf, const char *word, const char *flag) ...@@ -194,18 +193,18 @@ NIAddSpell(IspellDict *Conf, const char *word, const char *flag)
void void
NIImportDictionary(IspellDict *Conf, const char *filename) NIImportDictionary(IspellDict *Conf, const char *filename)
{ {
FILE *dict; tsearch_readline_state trst;
char *line; char *line;
checkTmpCtx(); checkTmpCtx();
if (!(dict = AllocateFile(filename, "r"))) if (!tsearch_readline_begin(&trst, filename))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not open dictionary file \"%s\": %m", errmsg("could not open dictionary file \"%s\": %m",
filename))); filename)));
while ((line = t_readline(dict)) != NULL) while ((line = tsearch_readline(&trst)) != NULL)
{ {
char *s, char *s,
*pstr; *pstr;
...@@ -250,7 +249,7 @@ NIImportDictionary(IspellDict *Conf, const char *filename) ...@@ -250,7 +249,7 @@ NIImportDictionary(IspellDict *Conf, const char *filename)
pfree(line); pfree(line);
} }
FreeFile(dict); tsearch_readline_end(&trst);
} }
...@@ -392,8 +391,7 @@ NIAddAffix(IspellDict *Conf, int flag, char flagflags, const char *mask, const c ...@@ -392,8 +391,7 @@ NIAddAffix(IspellDict *Conf, int flag, char flagflags, const char *mask, const c
#define PAE_INREPL 5 #define PAE_INREPL 5
static bool static bool
parse_affentry(char *str, char *mask, char *find, char *repl, parse_affentry(char *str, char *mask, char *find, char *repl)
const char *filename, int lineno)
{ {
int state = PAE_WAIT_MASK; int state = PAE_WAIT_MASK;
char *pmask = mask, char *pmask = mask,
...@@ -443,8 +441,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl, ...@@ -443,8 +441,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl,
else if (!t_isspace(str)) else if (!t_isspace(str))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("syntax error at line %d of affix file \"%s\"", errmsg("syntax error")));
lineno, filename)));
} }
else if (state == PAE_INFIND) else if (state == PAE_INFIND)
{ {
...@@ -461,8 +458,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl, ...@@ -461,8 +458,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl,
else if (!t_isspace(str)) else if (!t_isspace(str))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("syntax error at line %d of affix file \"%s\"", errmsg("syntax error")));
lineno, filename)));
} }
else if (state == PAE_WAIT_REPL) else if (state == PAE_WAIT_REPL)
{ {
...@@ -479,8 +475,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl, ...@@ -479,8 +475,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl,
else if (!t_isspace(str)) else if (!t_isspace(str))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("syntax error at line %d of affix file \"%s\"", errmsg("syntax error")));
lineno, filename)));
} }
else if (state == PAE_INREPL) else if (state == PAE_INREPL)
{ {
...@@ -497,8 +492,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl, ...@@ -497,8 +492,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl,
else if (!t_isspace(str)) else if (!t_isspace(str))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("syntax error at line %d of affix file \"%s\"", errmsg("syntax error")));
lineno, filename)));
} }
else else
elog(ERROR, "unrecognized state in parse_affentry: %d", state); elog(ERROR, "unrecognized state in parse_affentry: %d", state);
...@@ -512,8 +506,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl, ...@@ -512,8 +506,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl,
} }
static void static void
addFlagValue(IspellDict *Conf, char *s, uint32 val, addFlagValue(IspellDict *Conf, char *s, uint32 val)
const char *filename, int lineno)
{ {
while (*s && t_isspace(s)) while (*s && t_isspace(s))
s++; s++;
...@@ -521,14 +514,12 @@ addFlagValue(IspellDict *Conf, char *s, uint32 val, ...@@ -521,14 +514,12 @@ addFlagValue(IspellDict *Conf, char *s, uint32 val,
if (!*s) if (!*s)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("syntax error at line %d of affix file \"%s\"", errmsg("syntax error")));
lineno, filename)));
if (pg_mblen(s) != 1) if (pg_mblen(s) != 1)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multibyte flag character is not allowed at line %d of affix file \"%s\"", errmsg("multibyte flag character is not allowed")));
lineno, filename)));
Conf->flagval[(unsigned int) *s] = (unsigned char) val; Conf->flagval[(unsigned int) *s] = (unsigned char) val;
Conf->usecompound = true; Conf->usecompound = true;
...@@ -549,8 +540,7 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename) ...@@ -549,8 +540,7 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename)
bool isSuffix = false; bool isSuffix = false;
int flag = 0; int flag = 0;
char flagflags = 0; char flagflags = 0;
FILE *affix; tsearch_readline_state trst;
int lineno = 0;
int scanread = 0; int scanread = 0;
char scanbuf[BUFSIZ]; char scanbuf[BUFSIZ];
char *recoded; char *recoded;
...@@ -561,16 +551,14 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename) ...@@ -561,16 +551,14 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename)
memset(Conf->flagval, 0, sizeof(Conf->flagval)); memset(Conf->flagval, 0, sizeof(Conf->flagval));
Conf->usecompound = false; Conf->usecompound = false;
if (!(affix = AllocateFile(filename, "r"))) if (!tsearch_readline_begin(&trst, filename))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not open affix file \"%s\": %m", errmsg("could not open affix file \"%s\": %m",
filename))); filename)));
while ((recoded = t_readline(affix)) != NULL) while ((recoded = tsearch_readline(&trst)) != NULL)
{ {
lineno++;
if (*recoded == '\0' || t_isspace(recoded) || t_iseq(recoded, '#')) if (*recoded == '\0' || t_isspace(recoded) || t_iseq(recoded, '#'))
{ {
pfree(recoded); pfree(recoded);
...@@ -579,29 +567,29 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename) ...@@ -579,29 +567,29 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename)
if (STRNCMP(recoded, "COMPOUNDFLAG") == 0) if (STRNCMP(recoded, "COMPOUNDFLAG") == 0)
addFlagValue(Conf, recoded + strlen("COMPOUNDFLAG"), addFlagValue(Conf, recoded + strlen("COMPOUNDFLAG"),
FF_COMPOUNDFLAG, filename, lineno); FF_COMPOUNDFLAG);
else if (STRNCMP(recoded, "COMPOUNDBEGIN") == 0) else if (STRNCMP(recoded, "COMPOUNDBEGIN") == 0)
addFlagValue(Conf, recoded + strlen("COMPOUNDBEGIN"), addFlagValue(Conf, recoded + strlen("COMPOUNDBEGIN"),
FF_COMPOUNDBEGIN, filename, lineno); FF_COMPOUNDBEGIN);
else if (STRNCMP(recoded, "COMPOUNDLAST") == 0) else if (STRNCMP(recoded, "COMPOUNDLAST") == 0)
addFlagValue(Conf, recoded + strlen("COMPOUNDLAST"), addFlagValue(Conf, recoded + strlen("COMPOUNDLAST"),
FF_COMPOUNDLAST, filename, lineno); FF_COMPOUNDLAST);
/* COMPOUNDLAST and COMPOUNDEND are synonyms */ /* COMPOUNDLAST and COMPOUNDEND are synonyms */
else if (STRNCMP(recoded, "COMPOUNDEND") == 0) else if (STRNCMP(recoded, "COMPOUNDEND") == 0)
addFlagValue(Conf, recoded + strlen("COMPOUNDEND"), addFlagValue(Conf, recoded + strlen("COMPOUNDEND"),
FF_COMPOUNDLAST, filename, lineno); FF_COMPOUNDLAST);
else if (STRNCMP(recoded, "COMPOUNDMIDDLE") == 0) else if (STRNCMP(recoded, "COMPOUNDMIDDLE") == 0)
addFlagValue(Conf, recoded + strlen("COMPOUNDMIDDLE"), addFlagValue(Conf, recoded + strlen("COMPOUNDMIDDLE"),
FF_COMPOUNDMIDDLE, filename, lineno); FF_COMPOUNDMIDDLE);
else if (STRNCMP(recoded, "ONLYINCOMPOUND") == 0) else if (STRNCMP(recoded, "ONLYINCOMPOUND") == 0)
addFlagValue(Conf, recoded + strlen("ONLYINCOMPOUND"), addFlagValue(Conf, recoded + strlen("ONLYINCOMPOUND"),
FF_COMPOUNDONLY, filename, lineno); FF_COMPOUNDONLY);
else if (STRNCMP(recoded, "COMPOUNDPERMITFLAG") == 0) else if (STRNCMP(recoded, "COMPOUNDPERMITFLAG") == 0)
addFlagValue(Conf, recoded + strlen("COMPOUNDPERMITFLAG"), addFlagValue(Conf, recoded + strlen("COMPOUNDPERMITFLAG"),
FF_COMPOUNDPERMITFLAG, filename, lineno); FF_COMPOUNDPERMITFLAG);
else if (STRNCMP(recoded, "COMPOUNDFORBIDFLAG") == 0) else if (STRNCMP(recoded, "COMPOUNDFORBIDFLAG") == 0)
addFlagValue(Conf, recoded + strlen("COMPOUNDFORBIDFLAG"), addFlagValue(Conf, recoded + strlen("COMPOUNDFORBIDFLAG"),
FF_COMPOUNDFORBIDFLAG, filename, lineno); FF_COMPOUNDFORBIDFLAG);
else if (STRNCMP(recoded, "FLAG") == 0) else if (STRNCMP(recoded, "FLAG") == 0)
{ {
char *s = recoded + strlen("FLAG"); char *s = recoded + strlen("FLAG");
...@@ -612,26 +600,23 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename) ...@@ -612,26 +600,23 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename)
if (*s && STRNCMP(s, "default") != 0) if (*s && STRNCMP(s, "default") != 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("Ispell dictionary supports only default flag value at line %d of affix file \"%s\"", errmsg("Ispell dictionary supports only default flag value")));
lineno, filename)));
} }
pfree(recoded); pfree(recoded);
} }
FreeFile(affix); tsearch_readline_end(&trst);
lineno = 0;
sprintf(scanbuf, "%%6s %%%ds %%%ds %%%ds %%%ds", BUFSIZ / 5, BUFSIZ / 5, BUFSIZ / 5, BUFSIZ / 5); sprintf(scanbuf, "%%6s %%%ds %%%ds %%%ds %%%ds", BUFSIZ / 5, BUFSIZ / 5, BUFSIZ / 5, BUFSIZ / 5);
if (!(affix = AllocateFile(filename, "r"))) if (!tsearch_readline_begin(&trst, filename))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not open affix file \"%s\": %m", errmsg("could not open affix file \"%s\": %m",
filename))); filename)));
while ((recoded = t_readline(affix)) != NULL) while ((recoded = tsearch_readline(&trst)) != NULL)
{ {
lineno++;
if (*recoded == '\0' || t_isspace(recoded) || t_iseq(recoded, '#')) if (*recoded == '\0' || t_isspace(recoded) || t_iseq(recoded, '#'))
goto nextline; goto nextline;
...@@ -691,9 +676,9 @@ nextline: ...@@ -691,9 +676,9 @@ nextline:
pfree(recoded); pfree(recoded);
} }
tsearch_readline_end(&trst);
if (ptype) if (ptype)
pfree(ptype); pfree(ptype);
FreeFile(affix);
} }
/* /*
...@@ -713,14 +698,13 @@ NIImportAffixes(IspellDict *Conf, const char *filename) ...@@ -713,14 +698,13 @@ NIImportAffixes(IspellDict *Conf, const char *filename)
bool prefixes = false; bool prefixes = false;
int flag = 0; int flag = 0;
char flagflags = 0; char flagflags = 0;
FILE *affix; tsearch_readline_state trst;
int lineno = 0;
bool oldformat = false; bool oldformat = false;
char *recoded = NULL; char *recoded = NULL;
checkTmpCtx(); checkTmpCtx();
if (!(affix = AllocateFile(filename, "r"))) if (!tsearch_readline_begin(&trst, filename))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not open affix file \"%s\": %m", errmsg("could not open affix file \"%s\": %m",
...@@ -729,12 +713,10 @@ NIImportAffixes(IspellDict *Conf, const char *filename) ...@@ -729,12 +713,10 @@ NIImportAffixes(IspellDict *Conf, const char *filename)
memset(Conf->flagval, 0, sizeof(Conf->flagval)); memset(Conf->flagval, 0, sizeof(Conf->flagval));
Conf->usecompound = false; Conf->usecompound = false;
while ((recoded = t_readline(affix)) != NULL) while ((recoded = tsearch_readline(&trst)) != NULL)
{ {
pstr = lowerstr(recoded); pstr = lowerstr(recoded);
lineno++;
/* Skip comments and empty lines */ /* Skip comments and empty lines */
if (*pstr == '#' || *pstr == '\n') if (*pstr == '#' || *pstr == '\n')
goto nextline; goto nextline;
...@@ -787,8 +769,7 @@ NIImportAffixes(IspellDict *Conf, const char *filename) ...@@ -787,8 +769,7 @@ NIImportAffixes(IspellDict *Conf, const char *filename)
if (pg_mblen(s) != 1) if (pg_mblen(s) != 1)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multibyte flag character is not allowed at line %d of affix file \"%s\"", errmsg("multibyte flag character is not allowed")));
lineno, filename)));
if (*s == '*') if (*s == '*')
{ {
...@@ -808,8 +789,7 @@ NIImportAffixes(IspellDict *Conf, const char *filename) ...@@ -808,8 +789,7 @@ NIImportAffixes(IspellDict *Conf, const char *filename)
if (pg_mblen(s) != 1) if (pg_mblen(s) != 1)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multibyte flag character is not allowed at line %d of affix file \"%s\"", errmsg("multibyte flag character is not allowed")));
lineno, filename)));
flag = (unsigned char) *s; flag = (unsigned char) *s;
goto nextline; goto nextline;
...@@ -820,16 +800,15 @@ NIImportAffixes(IspellDict *Conf, const char *filename) ...@@ -820,16 +800,15 @@ NIImportAffixes(IspellDict *Conf, const char *filename)
if (oldformat) if (oldformat)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("wrong affix file format for flag at line %d of affix file \"%s\"", errmsg("wrong affix file format for flag")));
lineno, filename))); tsearch_readline_end(&trst);
FreeFile(affix);
NIImportOOAffixes(Conf, filename); NIImportOOAffixes(Conf, filename);
return; return;
} }
if ((!suffixes) && (!prefixes)) if ((!suffixes) && (!prefixes))
goto nextline; goto nextline;
if (!parse_affentry(pstr, mask, find, repl, filename, lineno)) if (!parse_affentry(pstr, mask, find, repl))
goto nextline; goto nextline;
NIAddAffix(Conf, flag, flagflags, mask, find, repl, suffixes ? FF_SUFFIX : FF_PREFIX); NIAddAffix(Conf, flag, flagflags, mask, find, repl, suffixes ? FF_SUFFIX : FF_PREFIX);
...@@ -838,7 +817,7 @@ nextline: ...@@ -838,7 +817,7 @@ nextline:
pfree(recoded); pfree(recoded);
pfree(pstr); pfree(pstr);
} }
FreeFile(affix); tsearch_readline_end(&trst);
} }
static int static int
......
...@@ -7,15 +7,19 @@ ...@@ -7,15 +7,19 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tsearch/ts_locale.c,v 1.9 2008/06/18 18:42:54 momjian Exp $ * $PostgreSQL: pgsql/src/backend/tsearch/ts_locale.c,v 1.10 2008/06/18 20:55:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "storage/fd.h"
#include "tsearch/ts_locale.h" #include "tsearch/ts_locale.h"
#include "tsearch/ts_public.h" #include "tsearch/ts_public.h"
static void tsearch_readline_callback(void *arg);
#ifdef USE_WIDE_UPPER_LOWER #ifdef USE_WIDE_UPPER_LOWER
int int
...@@ -76,12 +80,111 @@ t_isprint(const char *ptr) ...@@ -76,12 +80,111 @@ t_isprint(const char *ptr)
#endif /* USE_WIDE_UPPER_LOWER */ #endif /* USE_WIDE_UPPER_LOWER */
/*
* Set up to read a file using tsearch_readline(). This facility is
* better than just reading the file directly because it provides error
* context pointing to the specific line where a problem is detected.
*
* Expected usage is:
*
* tsearch_readline_state trst;
*
* if (!tsearch_readline_begin(&trst, filename))
* ereport(ERROR,
* (errcode(ERRCODE_CONFIG_FILE_ERROR),
* errmsg("could not open stop-word file \"%s\": %m",
* filename)));
* while ((line = tsearch_readline(&trst)) != NULL)
* process line;
* tsearch_readline_end(&trst);
*
* Note that the caller supplies the ereport() for file open failure;
* this is so that a custom message can be provided. The filename string
* passed to tsearch_readline_begin() must remain valid through
* tsearch_readline_end().
*/
bool
tsearch_readline_begin(tsearch_readline_state *stp,
const char *filename)
{
if ((stp->fp = AllocateFile(filename, "r")) == NULL)
return false;
stp->filename = filename;
stp->lineno = 0;
stp->curline = NULL;
/* Setup error traceback support for ereport() */
stp->cb.callback = tsearch_readline_callback;
stp->cb.arg = (void *) stp;
stp->cb.previous = error_context_stack;
error_context_stack = &stp->cb;
return true;
}
/* /*
* Read the next line from a tsearch data file (expected to be in UTF-8), and * Read the next line from a tsearch data file (expected to be in UTF-8), and
* convert it to database encoding if needed. The returned string is palloc'd. * convert it to database encoding if needed. The returned string is palloc'd.
* NULL return means EOF. * NULL return means EOF.
*/ */
char * char *
tsearch_readline(tsearch_readline_state *stp)
{
char *result;
stp->lineno++;
stp->curline = NULL;
result = t_readline(stp->fp);
stp->curline = result;
return result;
}
/*
* Close down after reading a file with tsearch_readline()
*/
void
tsearch_readline_end(tsearch_readline_state *stp)
{
FreeFile(stp->fp);
/* Pop the error context stack */
error_context_stack = stp->cb.previous;
}
/*
* Error context callback for errors occurring while reading a tsearch
* configuration file.
*/
static void
tsearch_readline_callback(void *arg)
{
tsearch_readline_state *stp = (tsearch_readline_state *) arg;
/*
* We can't include the text of the config line for errors that occur
* during t_readline() itself. This is only partly a consequence of
* our arms-length use of that routine: the major cause of such
* errors is encoding violations, and we daren't try to print error
* messages containing badly-encoded data.
*/
if (stp->curline)
errcontext("line %d of configuration file \"%s\": \"%s\"",
stp->lineno,
stp->filename,
stp->curline);
else
errcontext("line %d of configuration file \"%s\"",
stp->lineno,
stp->filename);
}
/*
* Read the next line from a tsearch data file (expected to be in UTF-8), and
* convert it to database encoding if needed. The returned string is palloc'd.
* NULL return means EOF.
*
* Note: direct use of this function is now deprecated. Go through
* tsearch_readline() to provide better error reporting.
*/
char *
t_readline(FILE *fp) t_readline(FILE *fp)
{ {
int len; int len;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tsearch/ts_utils.c,v 1.10 2008/06/18 18:42:54 momjian Exp $ * $PostgreSQL: pgsql/src/backend/tsearch/ts_utils.c,v 1.11 2008/06/18 20:55:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <ctype.h> #include <ctype.h>
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/fd.h"
#include "tsearch/ts_locale.h" #include "tsearch/ts_locale.h"
#include "tsearch/ts_public.h" #include "tsearch/ts_public.h"
#include "tsearch/ts_utils.h" #include "tsearch/ts_utils.h"
...@@ -82,17 +81,17 @@ readstoplist(const char *fname, StopList *s, char *(*wordop) (const char *)) ...@@ -82,17 +81,17 @@ readstoplist(const char *fname, StopList *s, char *(*wordop) (const char *))
if (fname && *fname) if (fname && *fname)
{ {
char *filename = get_tsearch_config_filename(fname, "stop"); char *filename = get_tsearch_config_filename(fname, "stop");
FILE *hin; tsearch_readline_state trst;
char *line; char *line;
int reallen = 0; int reallen = 0;
if ((hin = AllocateFile(filename, "r")) == NULL) if (!tsearch_readline_begin(&trst, filename))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not open stop-word file \"%s\": %m", errmsg("could not open stop-word file \"%s\": %m",
filename))); filename)));
while ((line = t_readline(hin)) != NULL) while ((line = tsearch_readline(&trst)) != NULL)
{ {
char *pbuf = line; char *pbuf = line;
...@@ -135,7 +134,7 @@ readstoplist(const char *fname, StopList *s, char *(*wordop) (const char *)) ...@@ -135,7 +134,7 @@ readstoplist(const char *fname, StopList *s, char *(*wordop) (const char *))
(s->len)++; (s->len)++;
} }
FreeFile(hin); tsearch_readline_end(&trst);
pfree(filename); pfree(filename);
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1998-2008, PostgreSQL Global Development Group * Copyright (c) 1998-2008, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/include/tsearch/ts_locale.h,v 1.7 2008/06/18 18:42:54 momjian Exp $ * $PostgreSQL: pgsql/src/include/tsearch/ts_locale.h,v 1.8 2008/06/18 20:55:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -29,6 +29,16 @@ ...@@ -29,6 +29,16 @@
#include <wctype.h> #include <wctype.h>
#endif #endif
/* working state for tsearch_readline (should be a local var in caller) */
typedef struct
{
FILE *fp;
const char *filename;
int lineno;
char *curline;
ErrorContextCallback cb;
} tsearch_readline_state;
#define TOUCHAR(x) (*((const unsigned char *) (x))) #define TOUCHAR(x) (*((const unsigned char *) (x)))
#ifdef USE_WIDE_UPPER_LOWER #ifdef USE_WIDE_UPPER_LOWER
...@@ -55,6 +65,12 @@ extern int t_isprint(const char *ptr); ...@@ -55,6 +65,12 @@ extern int t_isprint(const char *ptr);
extern char *lowerstr(const char *str); extern char *lowerstr(const char *str);
extern char *lowerstr_with_len(const char *str, int len); extern char *lowerstr_with_len(const char *str, int len);
extern bool tsearch_readline_begin(tsearch_readline_state *stp,
const char *filename);
extern char *tsearch_readline(tsearch_readline_state *stp);
extern void tsearch_readline_end(tsearch_readline_state *stp);
extern char *t_readline(FILE *fp); extern char *t_readline(FILE *fp);
#endif /* __TSLOCALE_H__ */ #endif /* __TSLOCALE_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment