]> granicus.if.org Git - postgresql/commitdiff
Improve error reporting for problems in text search configuration files
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 18 Jun 2008 20:55:42 +0000 (20:55 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 18 Jun 2008 20:55:42 +0000 (20:55 +0000)
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.

contrib/dict_xsyn/dict_xsyn.c
src/backend/tsearch/dict_synonym.c
src/backend/tsearch/dict_thesaurus.c
src/backend/tsearch/spell.c
src/backend/tsearch/ts_locale.c
src/backend/tsearch/ts_utils.c
src/include/tsearch/ts_locale.h

index d98792aa01e2f5a7269510f1ef3f2ff7f5b5faae..f8430862be3a83e18f7d28ecdcd2ec638b20305b 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (c) 2007-2008, PostgreSQL Global Development Group
  *
  * 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 @@
 
 #include "commands/defrem.h"
 #include "fmgr.h"
-#include "storage/fd.h"
 #include "tsearch/ts_locale.h"
 #include "tsearch/ts_utils.h"
 
@@ -75,17 +74,17 @@ static void
 read_dictionary(DictSyn *d, char *filename)
 {
        char       *real_filename = get_tsearch_config_filename(filename, "rules");
-       FILE       *fin;
+       tsearch_readline_state trst;
        char       *line;
        int                     cur = 0;
 
-       if ((fin = AllocateFile(real_filename, "r")) == NULL)
+       if (!tsearch_readline_begin(&trst, real_filename))
                ereport(ERROR,
                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                                 errmsg("could not open synonym file \"%s\": %m",
                                                real_filename)));
 
-       while ((line = t_readline(fin)) != NULL)
+       while ((line = tsearch_readline(&trst)) != NULL)
        {
                char       *value;
                char       *key;
@@ -119,7 +118,7 @@ read_dictionary(DictSyn *d, char *filename)
                cur++;
        }
 
-       FreeFile(fin);
+       tsearch_readline_end(&trst);
 
        d->len = cur;
        if (cur > 1)
index 6f263603d7a3900fb02acf3474ba58496fbbeaef..8558602ace2f8a1af78d579890b8e2f430052e9a 100644 (file)
@@ -7,14 +7,13 @@
  *
  *
  * 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 "commands/defrem.h"
-#include "storage/fd.h"
 #include "tsearch/ts_locale.h"
 #include "tsearch/ts_public.h"
 #include "tsearch/ts_utils.h"
@@ -79,7 +78,7 @@ dsynonym_init(PG_FUNCTION_ARGS)
        ListCell   *l;
        char       *filename = NULL;
        bool            case_sensitive = false;
-       FILE       *fin;
+       tsearch_readline_state trst;
        char       *starti,
                           *starto,
                           *end = NULL;
@@ -108,7 +107,7 @@ dsynonym_init(PG_FUNCTION_ARGS)
 
        filename = get_tsearch_config_filename(filename, "syn");
 
-       if ((fin = AllocateFile(filename, "r")) == NULL)
+       if (!tsearch_readline_begin(&trst, filename))
                ereport(ERROR,
                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                                 errmsg("could not open synonym file \"%s\": %m",
@@ -116,7 +115,7 @@ dsynonym_init(PG_FUNCTION_ARGS)
 
        d = (DictSyn *) palloc0(sizeof(DictSyn));
 
-       while ((line = t_readline(fin)) != NULL)
+       while ((line = tsearch_readline(&trst)) != NULL)
        {
                starti = findwrd(line, &end);
                if (!starti)
@@ -175,7 +174,7 @@ skipline:
                pfree(line);
        }
 
-       FreeFile(fin);
+       tsearch_readline_end(&trst);
 
        d->len = cur;
        qsort(d->syn, d->len, sizeof(Syn), compareSyn);
index 6fcffa745737744f973e9d77fc2c46f603bc13dc..0f9c133f2e5c5487d314d639d95ab6bc766506b1 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * 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 @@
 
 #include "catalog/namespace.h"
 #include "commands/defrem.h"
-#include "storage/fd.h"
 #include "tsearch/ts_cache.h"
 #include "tsearch/ts_locale.h"
 #include "tsearch/ts_public.h"
@@ -169,21 +168,19 @@ addWrd(DictThesaurus *d, char *b, char *e, uint16 idsubst, uint16 nwrd, uint16 p
 static void
 thesaurusRead(char *filename, DictThesaurus *d)
 {
-       FILE       *fh;
-       int                     lineno = 0;
+       tsearch_readline_state trst;
        uint16          idsubst = 0;
        bool            useasis = false;
        char       *line;
 
        filename = get_tsearch_config_filename(filename, "ths");
-       fh = AllocateFile(filename, "r");
-       if (!fh)
+       if (!tsearch_readline_begin(&trst, filename))
                ereport(ERROR,
                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                                 errmsg("could not open thesaurus file \"%s\": %m",
                                                filename)));
 
-       while ((line = t_readline(fh)) != NULL)
+       while ((line = tsearch_readline(&trst)) != NULL)
        {
                char       *ptr;
                int                     state = TR_WAITLEX;
@@ -191,8 +188,6 @@ thesaurusRead(char *filename, DictThesaurus *d)
                uint16          posinsubst = 0;
                uint16          nwrd = 0;
 
-               lineno++;
-
                ptr = line;
 
                /* is it a comment? */
@@ -213,13 +208,9 @@ thesaurusRead(char *filename, DictThesaurus *d)
                                if (t_iseq(ptr, ':'))
                                {
                                        if (posinsubst == 0)
-                                       {
-                                               FreeFile(fh);
                                                ereport(ERROR,
                                                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                                                errmsg("unexpected delimiter at line %d of thesaurus file \"%s\"",
-                                                                               lineno, filename)));
-                                       }
+                                                                errmsg("unexpected delimiter")));
                                        state = TR_WAITSUBS;
                                }
                                else if (!t_isspace(ptr))
@@ -269,8 +260,7 @@ thesaurusRead(char *filename, DictThesaurus *d)
                                        if (ptr == beginwrd)
                                                ereport(ERROR,
                                                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                                                errmsg("unexpected end of line or lexeme at line %d of thesaurus file \"%s\"",
-                                                                               lineno, filename)));
+                                                                errmsg("unexpected end of line or lexeme")));
                                        addWrd(d, beginwrd, ptr, idsubst, nwrd++, posinsubst, useasis);
                                        state = TR_WAITSUBS;
                                }
@@ -286,28 +276,23 @@ thesaurusRead(char *filename, DictThesaurus *d)
                        if (ptr == beginwrd)
                                ereport(ERROR,
                                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                                errmsg("unexpected end of line or lexeme at line %d of thesaurus file \"%s\"",
-                                                               lineno, filename)));
+                                                errmsg("unexpected end of line or lexeme")));
                        addWrd(d, beginwrd, ptr, idsubst, nwrd++, posinsubst, useasis);
                }
 
                idsubst++;
 
                if (!(nwrd && posinsubst))
-               {
-                       FreeFile(fh);
                        ereport(ERROR,
                                        (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                        errmsg("unexpected end of line at line %d of thesaurus file \"%s\"",
-                                                       lineno, filename)));
-               }
+                                        errmsg("unexpected end of line")));
 
                pfree(line);
        }
 
        d->nsubst = idsubst;
 
-       FreeFile(fh);
+       tsearch_readline_end(&trst);
 }
 
 static TheLexeme *
index a2837d16831ec466dc4cf74803e7c4de93c940a1..d6e3a081b8917c2bea178f3717b71b1f4c19fef6 100644 (file)
@@ -7,14 +7,13 @@
  *
  *
  * 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 "storage/fd.h"
 #include "tsearch/dicts/spell.h"
 #include "tsearch/ts_locale.h"
 #include "utils/memutils.h"
@@ -194,18 +193,18 @@ NIAddSpell(IspellDict *Conf, const char *word, const char *flag)
 void
 NIImportDictionary(IspellDict *Conf, const char *filename)
 {
-       FILE       *dict;
+       tsearch_readline_state trst;
        char       *line;
 
        checkTmpCtx();
 
-       if (!(dict = AllocateFile(filename, "r")))
+       if (!tsearch_readline_begin(&trst, filename))
                ereport(ERROR,
                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                                 errmsg("could not open dictionary file \"%s\": %m",
                                                filename)));
 
-       while ((line = t_readline(dict)) != NULL)
+       while ((line = tsearch_readline(&trst)) != NULL)
        {
                char       *s,
                                   *pstr;
@@ -250,7 +249,7 @@ NIImportDictionary(IspellDict *Conf, const char *filename)
 
                pfree(line);
        }
-       FreeFile(dict);
+       tsearch_readline_end(&trst);
 }
 
 
@@ -392,8 +391,7 @@ NIAddAffix(IspellDict *Conf, int flag, char flagflags, const char *mask, const c
 #define PAE_INREPL     5
 
 static bool
-parse_affentry(char *str, char *mask, char *find, char *repl,
-                          const char *filename, int lineno)
+parse_affentry(char *str, char *mask, char *find, char *repl)
 {
        int                     state = PAE_WAIT_MASK;
        char       *pmask = mask,
@@ -443,8 +441,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl,
                        else if (!t_isspace(str))
                                ereport(ERROR,
                                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                          errmsg("syntax error at line %d of affix file \"%s\"",
-                                                         lineno, filename)));
+                                                errmsg("syntax error")));
                }
                else if (state == PAE_INFIND)
                {
@@ -461,8 +458,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl,
                        else if (!t_isspace(str))
                                ereport(ERROR,
                                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                          errmsg("syntax error at line %d of affix file \"%s\"",
-                                                         lineno, filename)));
+                                                errmsg("syntax error")));
                }
                else if (state == PAE_WAIT_REPL)
                {
@@ -479,8 +475,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl,
                        else if (!t_isspace(str))
                                ereport(ERROR,
                                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                          errmsg("syntax error at line %d of affix file \"%s\"",
-                                                         lineno, filename)));
+                                                errmsg("syntax error")));
                }
                else if (state == PAE_INREPL)
                {
@@ -497,8 +492,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl,
                        else if (!t_isspace(str))
                                ereport(ERROR,
                                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                          errmsg("syntax error at line %d of affix file \"%s\"",
-                                                         lineno, filename)));
+                                                errmsg("syntax error")));
                }
                else
                        elog(ERROR, "unrecognized state in parse_affentry: %d", state);
@@ -512,8 +506,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl,
 }
 
 static void
-addFlagValue(IspellDict *Conf, char *s, uint32 val,
-                        const char *filename, int lineno)
+addFlagValue(IspellDict *Conf, char *s, uint32 val)
 {
        while (*s && t_isspace(s))
                s++;
@@ -521,14 +514,12 @@ addFlagValue(IspellDict *Conf, char *s, uint32 val,
        if (!*s)
                ereport(ERROR,
                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                errmsg("syntax error at line %d of affix file \"%s\"",
-                                               lineno, filename)));
+                                errmsg("syntax error")));
 
        if (pg_mblen(s) != 1)
                ereport(ERROR,
                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                errmsg("multibyte flag character is not allowed at line %d of affix file \"%s\"",
-                                               lineno, filename)));
+                                errmsg("multibyte flag character is not allowed")));
 
        Conf->flagval[(unsigned int) *s] = (unsigned char) val;
        Conf->usecompound = true;
@@ -549,8 +540,7 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename)
        bool            isSuffix = false;
        int                     flag = 0;
        char            flagflags = 0;
-       FILE       *affix;
-       int                     lineno = 0;
+       tsearch_readline_state trst;
        int                     scanread = 0;
        char            scanbuf[BUFSIZ];
        char       *recoded;
@@ -561,16 +551,14 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename)
        memset(Conf->flagval, 0, sizeof(Conf->flagval));
        Conf->usecompound = false;
 
-       if (!(affix = AllocateFile(filename, "r")))
+       if (!tsearch_readline_begin(&trst, filename))
                ereport(ERROR,
                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                                 errmsg("could not open affix file \"%s\": %m",
                                                filename)));
 
-       while ((recoded = t_readline(affix)) != NULL)
+       while ((recoded = tsearch_readline(&trst)) != NULL)
        {
-               lineno++;
-
                if (*recoded == '\0' || t_isspace(recoded) || t_iseq(recoded, '#'))
                {
                        pfree(recoded);
@@ -579,29 +567,29 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename)
 
                if (STRNCMP(recoded, "COMPOUNDFLAG") == 0)
                        addFlagValue(Conf, recoded + strlen("COMPOUNDFLAG"),
-                                                FF_COMPOUNDFLAG, filename, lineno);
+                                                FF_COMPOUNDFLAG);
                else if (STRNCMP(recoded, "COMPOUNDBEGIN") == 0)
                        addFlagValue(Conf, recoded + strlen("COMPOUNDBEGIN"),
-                                                FF_COMPOUNDBEGIN, filename, lineno);
+                                                FF_COMPOUNDBEGIN);
                else if (STRNCMP(recoded, "COMPOUNDLAST") == 0)
                        addFlagValue(Conf, recoded + strlen("COMPOUNDLAST"),
-                                                FF_COMPOUNDLAST, filename, lineno);
+                                                FF_COMPOUNDLAST);
                /* COMPOUNDLAST and COMPOUNDEND are synonyms */
                else if (STRNCMP(recoded, "COMPOUNDEND") == 0)
                        addFlagValue(Conf, recoded + strlen("COMPOUNDEND"),
-                                                FF_COMPOUNDLAST, filename, lineno);
+                                                FF_COMPOUNDLAST);
                else if (STRNCMP(recoded, "COMPOUNDMIDDLE") == 0)
                        addFlagValue(Conf, recoded + strlen("COMPOUNDMIDDLE"),
-                                                FF_COMPOUNDMIDDLE, filename, lineno);
+                                                FF_COMPOUNDMIDDLE);
                else if (STRNCMP(recoded, "ONLYINCOMPOUND") == 0)
                        addFlagValue(Conf, recoded + strlen("ONLYINCOMPOUND"),
-                                                FF_COMPOUNDONLY, filename, lineno);
+                                                FF_COMPOUNDONLY);
                else if (STRNCMP(recoded, "COMPOUNDPERMITFLAG") == 0)
                        addFlagValue(Conf, recoded + strlen("COMPOUNDPERMITFLAG"),
-                                                FF_COMPOUNDPERMITFLAG, filename, lineno);
+                                                FF_COMPOUNDPERMITFLAG);
                else if (STRNCMP(recoded, "COMPOUNDFORBIDFLAG") == 0)
                        addFlagValue(Conf, recoded + strlen("COMPOUNDFORBIDFLAG"),
-                                                FF_COMPOUNDFORBIDFLAG, filename, lineno);
+                                                FF_COMPOUNDFORBIDFLAG);
                else if (STRNCMP(recoded, "FLAG") == 0)
                {
                        char       *s = recoded + strlen("FLAG");
@@ -612,26 +600,23 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename)
                        if (*s && STRNCMP(s, "default") != 0)
                                ereport(ERROR,
                                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                                errmsg("Ispell dictionary supports only default flag value at line %d of affix file \"%s\"",
-                                                               lineno, filename)));
+                                                errmsg("Ispell dictionary supports only default flag value")));
                }
 
                pfree(recoded);
        }
-       FreeFile(affix);
-       lineno = 0;
+       tsearch_readline_end(&trst);
 
        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,
                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                                 errmsg("could not open affix file \"%s\": %m",
                                                filename)));
 
-       while ((recoded = t_readline(affix)) != NULL)
+       while ((recoded = tsearch_readline(&trst)) != NULL)
        {
-               lineno++;
                if (*recoded == '\0' || t_isspace(recoded) || t_iseq(recoded, '#'))
                        goto nextline;
 
@@ -691,9 +676,9 @@ nextline:
                pfree(recoded);
        }
 
+       tsearch_readline_end(&trst);
        if (ptype)
                pfree(ptype);
-       FreeFile(affix);
 }
 
 /*
@@ -713,14 +698,13 @@ NIImportAffixes(IspellDict *Conf, const char *filename)
        bool            prefixes = false;
        int                     flag = 0;
        char            flagflags = 0;
-       FILE       *affix;
-       int                     lineno = 0;
+       tsearch_readline_state trst;
        bool            oldformat = false;
        char       *recoded = NULL;
 
        checkTmpCtx();
 
-       if (!(affix = AllocateFile(filename, "r")))
+       if (!tsearch_readline_begin(&trst, filename))
                ereport(ERROR,
                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                                 errmsg("could not open affix file \"%s\": %m",
@@ -729,12 +713,10 @@ NIImportAffixes(IspellDict *Conf, const char *filename)
        memset(Conf->flagval, 0, sizeof(Conf->flagval));
        Conf->usecompound = false;
 
-       while ((recoded = t_readline(affix)) != NULL)
+       while ((recoded = tsearch_readline(&trst)) != NULL)
        {
                pstr = lowerstr(recoded);
 
-               lineno++;
-
                /* Skip comments and empty lines */
                if (*pstr == '#' || *pstr == '\n')
                        goto nextline;
@@ -787,8 +769,7 @@ NIImportAffixes(IspellDict *Conf, const char *filename)
                        if (pg_mblen(s) != 1)
                                ereport(ERROR,
                                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                                errmsg("multibyte flag character is not allowed at line %d of affix file \"%s\"",
-                                                               lineno, filename)));
+                                                errmsg("multibyte flag character is not allowed")));
 
                        if (*s == '*')
                        {
@@ -808,8 +789,7 @@ NIImportAffixes(IspellDict *Conf, const char *filename)
                        if (pg_mblen(s) != 1)
                                ereport(ERROR,
                                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                                errmsg("multibyte flag character is not allowed at line %d of affix file \"%s\"",
-                                                               lineno, filename)));
+                                                errmsg("multibyte flag character is not allowed")));
 
                        flag = (unsigned char) *s;
                        goto nextline;
@@ -820,16 +800,15 @@ NIImportAffixes(IspellDict *Conf, const char *filename)
                        if (oldformat)
                                ereport(ERROR,
                                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                                errmsg("wrong affix file format for flag at line %d of affix file \"%s\"",
-                                                               lineno, filename)));
-                       FreeFile(affix);
+                                                errmsg("wrong affix file format for flag")));
+                       tsearch_readline_end(&trst);
                        NIImportOOAffixes(Conf, filename);
                        return;
                }
                if ((!suffixes) && (!prefixes))
                        goto nextline;
 
-               if (!parse_affentry(pstr, mask, find, repl, filename, lineno))
+               if (!parse_affentry(pstr, mask, find, repl))
                        goto nextline;
 
                NIAddAffix(Conf, flag, flagflags, mask, find, repl, suffixes ? FF_SUFFIX : FF_PREFIX);
@@ -838,7 +817,7 @@ nextline:
                pfree(recoded);
                pfree(pstr);
        }
-       FreeFile(affix);
+       tsearch_readline_end(&trst);
 }
 
 static int
index 5ce367a497e890c6aed2ad18573ac6911a815e83..53349d7fc080a0612d0e4a22874427419c1d3766 100644 (file)
@@ -7,15 +7,19 @@
  *
  *
  * 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 "storage/fd.h"
 #include "tsearch/ts_locale.h"
 #include "tsearch/ts_public.h"
 
+static void tsearch_readline_callback(void *arg);
+
+
 #ifdef USE_WIDE_UPPER_LOWER
 
 int
@@ -76,12 +80,111 @@ t_isprint(const char *ptr)
 #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
  * convert it to database encoding if needed. The returned string is palloc'd.
  * NULL return means EOF.
  */
 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)
 {
        int                     len;
index 3708d02689f7bf9300c491eef445018086f60e37..04586647890836b19d23ada248d86834bd51bf21 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * 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 @@
 #include <ctype.h>
 
 #include "miscadmin.h"
-#include "storage/fd.h"
 #include "tsearch/ts_locale.h"
 #include "tsearch/ts_public.h"
 #include "tsearch/ts_utils.h"
@@ -82,17 +81,17 @@ readstoplist(const char *fname, StopList *s, char *(*wordop) (const char *))
        if (fname && *fname)
        {
                char       *filename = get_tsearch_config_filename(fname, "stop");
-               FILE       *hin;
+               tsearch_readline_state trst;
                char       *line;
                int                     reallen = 0;
 
-               if ((hin = AllocateFile(filename, "r")) == NULL)
+               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 = t_readline(hin)) != NULL)
+               while ((line = tsearch_readline(&trst)) != NULL)
                {
                        char       *pbuf = line;
 
@@ -135,7 +134,7 @@ readstoplist(const char *fname, StopList *s, char *(*wordop) (const char *))
                        (s->len)++;
                }
 
-               FreeFile(hin);
+               tsearch_readline_end(&trst);
                pfree(filename);
        }
 
index 110efb191c1034b7577e51f9e22657b138610e07..b05ab7f1b0b23def3b51a716c7640532f76cd689 100644 (file)
@@ -5,7 +5,7 @@
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 #include <wctype.h>
 #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)))
 
 #ifdef USE_WIDE_UPPER_LOWER
@@ -55,6 +65,12 @@ extern int   t_isprint(const char *ptr);
 
 extern char *lowerstr(const char *str);
 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);
 
 #endif   /* __TSLOCALE_H__ */