Simplify the syntax of CREATE/ALTER TEXT SEARCH DICTIONARY by treating the
authorTom Lane
Wed, 22 Aug 2007 01:39:46 +0000 (01:39 +0000)
committerTom Lane
Wed, 22 Aug 2007 01:39:46 +0000 (01:39 +0000)
init options of the template as top-level options in the syntax.  This also
makes ALTER a bit easier to use, since options can be replaced individually.
I also made these statements verify that the tmplinit method will accept
the new settings before they get stored; in the original coding you didn't
find out about mistakes until the dictionary got invoked.

Under the hood, init methods now get options as a List of DefElem instead
of a raw text string --- that lets tsearch use existing options-pushing code
instead of duplicating functionality.

17 files changed:
doc/src/sgml/ref/alter_tsdictionary.sgml
doc/src/sgml/ref/create_tsdictionary.sgml
src/backend/commands/tsearchcmds.c
src/backend/snowball/dict_snowball.c
src/backend/snowball/snowball.sql.in
src/backend/tsearch/dict_ispell.c
src/backend/tsearch/dict_simple.c
src/backend/tsearch/dict_thesaurus.c
src/backend/tsearch/ts_utils.c
src/backend/tsearch/wparser.c
src/backend/tsearch/wparser_def.c
src/backend/utils/cache/ts_cache.c
src/bin/pg_dump/pg_dump.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/commands/defrem.h
src/include/tsearch/ts_public.h

index 59c33666557584e0ed735a1f84ce059a50d1b095..a2929c70d12e55e514773810de54a4702dc6aa35 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -20,7 +20,9 @@ PostgreSQL documentation
 
  
 
-ALTER TEXT SEARCH DICTIONARY name ( OPTION = init_options )
+ALTER TEXT SEARCH DICTIONARY name (
+    option [ = value ] [, ... ]
+)
 ALTER TEXT SEARCH DICTIONARY name RENAME TO newname
 ALTER TEXT SEARCH DICTIONARY name OWNER TO newowner
 
@@ -31,8 +33,8 @@ ALTER TEXT SEARCH DICTIONARY name OWNER TO 
 
   
    ALTER TEXT SEARCH DICTIONARY changes the definition of
-   a text search dictionary.  You can change the dictionary's initialization
-   options, or change the dictionary's name or owner.
+   a text search dictionary.  You can change the dictionary's
+   template-specific options, or change the dictionary's name or owner.
   
 
   
@@ -56,11 +58,22 @@ ALTER TEXT SEARCH DICTIONARY name OWNER TO 
    
 
    
-    init_options
+    option
     
      
-      A new list of initialization options, or NULL to
-      remove all options.
+      The name of a template-specific option to be set for this dictionary.
+     
+    
+   
+
+   
+    value
+    
+     
+      The new value to use for a template-specific option.
+      If the equal sign and value are omitted, then any previous
+      setting for the option is removed from the dictionary,
+      allowing the default to be used.
      
     
    
@@ -83,18 +96,31 @@ ALTER TEXT SEARCH DICTIONARY name OWNER TO 
     
    
  
+
+  
+   Template-specific options can appear in any order.
+  
  
   
  
   Examples
 
   
-   The following example command sets the language and stopword list
-   for a Snowball-based dictionary.
+   The following example command changes the stopword list
+   for a Snowball-based dictionary.  Other parameters remain unchanged.
+  
+
+
+ALTER TEXT SEARCH DICTIONARY my_dict ( StopWords = newrussian );
+  
+
+  
+   The following example command changes the language option to dutch,
+   and removes the stopword option entirely.
   
 
 
-ALTER TEXT SEARCH DICTIONARY my_russian ( option = 'Language=russian, StopWords=my_russian' );
+ALTER TEXT SEARCH DICTIONARY my_dict ( language = dutch, StopWords );
   
  
 
index 81c6a0c6edb2fb8885f1daec47128b61266334d0..9aa53a6a7c484d331a0662cd1a9bbe84095eaf1a 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -22,7 +22,7 @@ PostgreSQL documentation
 
 CREATE TEXT SEARCH DICTIONARY name (
     TEMPLATE = template
-    [, OPTION = init_options ]
+    [, option = value [, ... ]]
 )
 
  
@@ -78,17 +78,46 @@ CREATE TEXT SEARCH DICTIONARY name
    
 
    
-    init_options
+    option
     
      
-      A list of initialization options for the template functions.
-      This is a string containing keyword =
-      value pairs.  The specific keywords allowed
-      vary depending on the text search template.
+      The name of a template-specific option to be set for this dictionary.
+     
+    
+   
+
+   
+    value
+    
+     
+      The value to use for a template-specific option.  If the value
+      is not a simple identifier or number, it must be quoted (but you can
+      always quote it, if you wish).
      
     
    
   
+
+  
+   The options can appear in any order.
+  
+  
+  Examples
+
+  
+   The following example command creates a Snowball-based dictionary
+   with a nonstandard list of stop words.
+  
+
+
+CREATE TEXT SEARCH DICTIONARY my_russian (
+    template = snowball,
+    language = russian,
+    stopwords = myrussian
+);
+  
  
  
  
index af34c58c7c230c4d003bd871f791516793bb9b21..7c5a1c49a33040bf388599e412be9d9c711f3d75 100644 (file)
@@ -9,12 +9,13 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/tsearchcmds.c,v 1.2 2007/08/21 21:24:00 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/tsearchcmds.c,v 1.3 2007/08/22 01:39:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
-#include "miscadmin.h"
+
+#include 
 
 #include "access/heapam.h"
 #include "access/genam.h"
@@ -31,6 +32,8 @@
 #include "catalog/pg_ts_template.h"
 #include "catalog/pg_type.h"
 #include "commands/defrem.h"
+#include "miscadmin.h"
+#include "nodes/makefuncs.h"
 #include "parser/parse_func.h"
 #include "tsearch/ts_cache.h"
 #include "tsearch/ts_public.h"
@@ -86,7 +89,7 @@ get_ts_parser_func(DefElem *defel, int attnum)
            break;
        case Anum_pg_ts_parser_prsheadline:
            nargs = 3;
-           typeId[1] = TEXTOID;
+           typeId[1] = INTERNALOID;
            typeId[2] = TSQUERYOID;
            break;
        case Anum_pg_ts_parser_prslextype:
@@ -407,6 +410,53 @@ makeDictionaryDependencies(HeapTuple tuple)
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 }
 
+/*
+ * verify that a template's init method accepts a proposed option list
+ */
+static void
+verify_dictoptions(Oid tmplId, List *dictoptions)
+{
+   HeapTuple   tup;
+   Form_pg_ts_template tform;
+   Oid         initmethod;
+
+   tup = SearchSysCache(TSTEMPLATEOID,
+                        ObjectIdGetDatum(tmplId),
+                        0, 0, 0);
+   if (!HeapTupleIsValid(tup)) /* should not happen */
+       elog(ERROR, "cache lookup failed for text search template %u",
+            tmplId);
+   tform = (Form_pg_ts_template) GETSTRUCT(tup);
+
+   initmethod = tform->tmplinit;
+
+   if (!OidIsValid(initmethod))
+   {
+       /* If there is no init method, disallow any options */
+       if (dictoptions)
+           ereport(ERROR,
+                   (errcode(ERRCODE_SYNTAX_ERROR),
+                    errmsg("text search template \"%s\" does not accept options",
+                           NameStr(tform->tmplname))));
+   }
+   else
+   {
+       /*
+        * Copy the options just in case init method thinks it can scribble
+        * on them ...
+        */
+       dictoptions = copyObject(dictoptions);
+
+       /*
+        * Call the init method and see if it complains.  We don't worry about
+        * it leaking memory, since our command will soon be over anyway.
+        */
+       (void) OidFunctionCall1(initmethod, PointerGetDatum(dictoptions));
+   }
+
+   ReleaseSysCache(tup);
+}
+
 /*
  * CREATE TEXT SEARCH DICTIONARY
  */
@@ -419,7 +469,8 @@ DefineTSDictionary(List *names, List *parameters)
    Datum       values[Natts_pg_ts_dict];
    char        nulls[Natts_pg_ts_dict];
    NameData    dname;
-   int         i;
+   Oid         templId = InvalidOid;
+   List       *dictoptions = NIL;
    Oid         dictOid;
    Oid         namespaceoid;
    AclResult   aclresult;
@@ -434,18 +485,6 @@ DefineTSDictionary(List *names, List *parameters)
        aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                       get_namespace_name(namespaceoid));
 
-   for (i = 0; i < Natts_pg_ts_dict; i++)
-   {
-       nulls[i] = ' ';
-       values[i] = ObjectIdGetDatum(InvalidOid);
-   }
-
-   namestrcpy(&dname, dictname);
-   values[Anum_pg_ts_dict_dictname - 1] = NameGetDatum(&dname);
-   values[Anum_pg_ts_dict_dictnamespace - 1] = ObjectIdGetDatum(namespaceoid);
-   values[Anum_pg_ts_dict_dictowner - 1] = ObjectIdGetDatum(GetUserId());
-   nulls[Anum_pg_ts_dict_dictinitoption - 1] = 'n';
-
    /*
     * loop over the definition list and extract the information we need.
     */
@@ -455,42 +494,41 @@ DefineTSDictionary(List *names, List *parameters)
 
        if (pg_strcasecmp(defel->defname, "template") == 0)
        {
-           Oid         templId;
-
            templId = TSTemplateGetTmplid(defGetQualifiedName(defel), false);
-
-           values[Anum_pg_ts_dict_dicttemplate - 1] = ObjectIdGetDatum(templId);
-           nulls[Anum_pg_ts_dict_dicttemplate - 1] = ' ';
        }
-       else if (pg_strcasecmp(defel->defname, "option") == 0)
+       else
        {
-           char       *opt = defGetString(defel);
-
-           if (pg_strcasecmp(opt, "null") != 0)
-           {
-               values[Anum_pg_ts_dict_dictinitoption - 1] =
-                   DirectFunctionCall1(textin, CStringGetDatum(opt));
-               nulls[Anum_pg_ts_dict_dictinitoption - 1] = ' ';
-           }
+           /* Assume it's an option for the dictionary itself */
+           dictoptions = lappend(dictoptions, defel);
        }
-       else
-           ereport(ERROR,
-                   (errcode(ERRCODE_SYNTAX_ERROR),
-                    errmsg("text search dictionary parameter \"%s\" not recognized",
-                           defel->defname)));
    }
 
    /*
     * Validation
     */
-   if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_dict_dicttemplate - 1])))
+   if (!OidIsValid(templId))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("text search template is required")));
 
+   verify_dictoptions(templId, dictoptions);
+
    /*
     * Looks good, insert
     */
+   memset(values, 0, sizeof(values));
+   memset(nulls, ' ', sizeof(nulls));
+
+   namestrcpy(&dname, dictname);
+   values[Anum_pg_ts_dict_dictname - 1] = NameGetDatum(&dname);
+   values[Anum_pg_ts_dict_dictnamespace - 1] = ObjectIdGetDatum(namespaceoid);
+   values[Anum_pg_ts_dict_dictowner - 1] = ObjectIdGetDatum(GetUserId());
+   values[Anum_pg_ts_dict_dicttemplate - 1] = ObjectIdGetDatum(templId);
+   if (dictoptions)
+       values[Anum_pg_ts_dict_dictinitoption - 1] =
+           PointerGetDatum(serialize_deflist(dictoptions));
+   else
+       nulls[Anum_pg_ts_dict_dictinitoption - 1] = 'n';
 
    dictRel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
 
@@ -652,6 +690,9 @@ AlterTSDictionary(AlterTSDictionaryStmt * stmt)
    Relation    rel;
    Oid         dictId;
    ListCell   *pl;
+   List       *dictoptions;
+   Datum       opt;
+   bool        isnull;
    Datum       repl_val[Natts_pg_ts_dict];
    char        repl_null[Natts_pg_ts_dict];
    char        repl_repl[Natts_pg_ts_dict];
@@ -673,41 +714,67 @@ AlterTSDictionary(AlterTSDictionaryStmt * stmt)
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
                       NameListToString(stmt->dictname));
 
-   memset(repl_val, 0, sizeof(repl_val));
-   memset(repl_null, ' ', sizeof(repl_null));
-   memset(repl_repl, ' ', sizeof(repl_repl));
+   /* deserialize the existing set of options */
+   opt = SysCacheGetAttr(TSDICTOID, tup,
+                         Anum_pg_ts_dict_dictinitoption,
+                         &isnull);
+   if (isnull)
+       dictoptions = NIL;
+   else
+       dictoptions = deserialize_deflist(opt);
 
    /*
-    * NOTE: because we only support altering the option, not the template,
-    * there is no need to update dependencies.
+    * Modify the options list as per specified changes
     */
    foreach(pl, stmt->options)
    {
        DefElem    *defel = (DefElem *) lfirst(pl);
+       ListCell   *cell;
+       ListCell   *prev;
+       ListCell   *next;
 
-       if (pg_strcasecmp(defel->defname, "option") == 0)
+       /*
+        * Remove any matches ...
+        */
+       prev = NULL;
+       for (cell = list_head(dictoptions); cell; cell = next)
        {
-           char       *opt = defGetString(defel);
+           DefElem    *oldel = (DefElem *) lfirst(cell);
 
-           if (pg_strcasecmp(opt, "null") == 0)
-           {
-               repl_null[Anum_pg_ts_dict_dictinitoption - 1] = 'n';
-           }
+           next = lnext(cell);
+           if (pg_strcasecmp(oldel->defname, defel->defname) == 0)
+               dictoptions = list_delete_cell(dictoptions, cell, prev);
            else
-           {
-               repl_val[Anum_pg_ts_dict_dictinitoption - 1] =
-                   DirectFunctionCall1(textin, CStringGetDatum(opt));
-               repl_null[Anum_pg_ts_dict_dictinitoption - 1] = ' ';
-           }
-           repl_repl[Anum_pg_ts_dict_dictinitoption - 1] = 'r';
+               prev = cell;
        }
-       else
-           ereport(ERROR,
-                   (errcode(ERRCODE_SYNTAX_ERROR),
-                    errmsg("text search dictionary parameter \"%s\" not recognized",
-                           defel->defname)));
+
+       /*
+        * and add new value if it's got one
+        */
+       if (defel->arg)
+           dictoptions = lappend(dictoptions, defel);
    }
 
+   /*
+    * Validate
+    */
+   verify_dictoptions(((Form_pg_ts_dict) GETSTRUCT(tup))->dicttemplate,
+                      dictoptions);
+
+   /*
+    * Looks good, update
+    */
+   memset(repl_val, 0, sizeof(repl_val));
+   memset(repl_null, ' ', sizeof(repl_null));
+   memset(repl_repl, ' ', sizeof(repl_repl));
+
+   if (dictoptions)
+       repl_val[Anum_pg_ts_dict_dictinitoption - 1] =
+           PointerGetDatum(serialize_deflist(dictoptions));
+   else
+       repl_null[Anum_pg_ts_dict_dictinitoption - 1] = 'n';
+   repl_repl[Anum_pg_ts_dict_dictinitoption - 1] = 'r';
+
    newtup = heap_modifytuple(tup, RelationGetDescr(rel),
                              repl_val, repl_null, repl_repl);
 
@@ -715,6 +782,12 @@ AlterTSDictionary(AlterTSDictionaryStmt * stmt)
 
    CatalogUpdateIndexes(rel, newtup);
 
+   /*
+    * NOTE: because we only support altering the options, not the template,
+    * there is no need to update dependencies.  This might have to change
+    * if the options ever reference inside-the-database objects.
+    */
+
    heap_freetuple(newtup);
    ReleaseSysCache(tup);
 
@@ -1941,3 +2014,265 @@ DropConfigurationMapping(AlterTSConfigurationStmt *stmt, HeapTuple tup)
 
    heap_close(relMap, RowExclusiveLock);
 }
+
+
+/*
+ * Serialize dictionary options, producing a TEXT datum from a List of DefElem
+ *
+ * This is used to form the value stored in pg_ts_dict.dictinitoption.
+ * For the convenience of pg_dump, the output is formatted exactly as it
+ * would need to appear in CREATE TEXT SEARCH DICTIONARY to reproduce the
+ * same options.
+ *
+ * Note that we assume that only the textual representation of an option's
+ * value is interesting --- hence, non-string DefElems get forced to strings.
+ */
+text *
+serialize_deflist(List *deflist)
+{
+   text       *result;
+   StringInfoData buf;
+   ListCell   *l;
+
+   initStringInfo(&buf);
+
+   foreach(l, deflist)
+   {
+       DefElem    *defel = (DefElem *) lfirst(l);
+       char       *val = defGetString(defel);
+
+       appendStringInfo(&buf, "%s = ",
+                    quote_identifier(defel->defname));
+       /* If backslashes appear, force E syntax to determine their handling */
+       if (strchr(val, '\\'))
+           appendStringInfoChar(&buf, ESCAPE_STRING_SYNTAX);
+       appendStringInfoChar(&buf, '\'');
+       while (*val)
+       {
+           char        ch = *val++;
+
+           if (SQL_STR_DOUBLE(ch, true))
+               appendStringInfoChar(&buf, ch);
+           appendStringInfoChar(&buf, ch);
+       }
+       appendStringInfoChar(&buf, '\'');
+       if (lnext(l) != NULL)
+           appendStringInfo(&buf, ", ");
+   }
+
+   result = CStringGetTextP(buf.data);
+   pfree(buf.data);
+   return result;
+}
+
+/*
+ * Deserialize dictionary options, reconstructing a List of DefElem from TEXT
+ *
+ * This is also used for prsheadline options, so for backward compatibility
+ * we need to accept a few things serialize_deflist() will never emit:
+ * in particular, unquoted and double-quoted values.
+ */
+List *
+deserialize_deflist(Datum txt)
+{
+   text       *in = DatumGetTextP(txt); /* in case it's toasted */
+   List       *result = NIL;
+   int         len = VARSIZE(in) - VARHDRSZ;
+   char       *ptr,
+              *endptr,
+              *workspace,
+              *wsptr = NULL,
+              *startvalue = NULL;
+   typedef enum {
+       CS_WAITKEY,
+       CS_INKEY,
+       CS_INQKEY,
+       CS_WAITEQ,
+       CS_WAITVALUE,
+       CS_INSQVALUE,
+       CS_INDQVALUE,
+       CS_INWVALUE
+   } ds_state;
+   ds_state    state = CS_WAITKEY;
+
+   workspace = (char *) palloc(len + 1);       /* certainly enough room */
+   ptr = VARDATA(in);
+   endptr = ptr + len;
+   for (; ptr < endptr; ptr++)
+   {
+       switch (state)
+       {
+           case CS_WAITKEY:
+               if (isspace((unsigned char) *ptr) || *ptr == ',')
+                   continue;
+               if (*ptr == '"')
+               {
+                   wsptr = workspace;
+                   state = CS_INQKEY;
+               }
+               else
+               {
+                   wsptr = workspace;
+                   *wsptr++ = *ptr;
+                   state = CS_INKEY;
+               }
+               break;
+           case CS_INKEY:
+               if (isspace((unsigned char) *ptr))
+               {
+                   *wsptr++ = '\0';
+                   state = CS_WAITEQ;
+               }
+               else if (*ptr == '=')
+               {
+                   *wsptr++ = '\0';
+                   state = CS_WAITVALUE;
+               }
+               else
+               {
+                   *wsptr++ = *ptr;
+               }
+               break;
+           case CS_INQKEY:
+               if (*ptr == '"')
+               {
+                   if (ptr+1 < endptr && ptr[1] == '"')
+                   {
+                       /* copy only one of the two quotes */
+                       *wsptr++ = *ptr++;
+                   }
+                   else
+                   {
+                       *wsptr++ = '\0';
+                       state = CS_WAITEQ;
+                   }
+               }
+               else
+               {
+                   *wsptr++ = *ptr;
+               }
+               break;
+           case CS_WAITEQ:
+               if (*ptr == '=')
+                   state = CS_WAITVALUE;
+               else if (!isspace((unsigned char) *ptr))
+                   ereport(ERROR,
+                           (errcode(ERRCODE_SYNTAX_ERROR),
+                            errmsg("invalid parameter list format: \"%s\"",
+                                   TextPGetCString(in))));
+               break;
+           case CS_WAITVALUE:
+               if (*ptr == '\'')
+               {
+                   startvalue = wsptr;
+                   state = CS_INSQVALUE;
+               }
+               else if (*ptr == 'E' && ptr+1 < endptr && ptr[1] == '\'')
+               {
+                   ptr++;
+                   startvalue = wsptr;
+                   state = CS_INSQVALUE;
+               }
+               else if (*ptr == '"')
+               {
+                   startvalue = wsptr;
+                   state = CS_INDQVALUE;
+               }
+               else if (!isspace((unsigned char) *ptr))
+               {
+                   startvalue = wsptr;
+                   *wsptr++ = *ptr;
+                   state = CS_INWVALUE;
+               }
+               break;
+           case CS_INSQVALUE:
+               if (*ptr == '\'')
+               {
+                   if (ptr+1 < endptr && ptr[1] == '\'')
+                   {
+                       /* copy only one of the two quotes */
+                       *wsptr++ = *ptr++;
+                   }
+                   else
+                   {
+                       *wsptr++ = '\0';
+                       result = lappend(result,
+                                        makeDefElem(pstrdup(workspace),
+                                                    (Node *) makeString(pstrdup(startvalue))));
+                       state = CS_WAITKEY;
+                   }
+               }
+               else if (*ptr == '\\')
+               {
+                   if (ptr+1 < endptr && ptr[1] == '\\')
+                   {
+                       /* copy only one of the two backslashes */
+                       *wsptr++ = *ptr++;
+                   }
+                   else
+                       *wsptr++ = *ptr;
+               }
+               else
+               {
+                   *wsptr++ = *ptr;
+               }
+               break;
+           case CS_INDQVALUE:
+               if (*ptr == '"')
+               {
+                   if (ptr+1 < endptr && ptr[1] == '"')
+                   {
+                       /* copy only one of the two quotes */
+                       *wsptr++ = *ptr++;
+                   }
+                   else
+                   {
+                       *wsptr++ = '\0';
+                       result = lappend(result,
+                                        makeDefElem(pstrdup(workspace),
+                                                    (Node *) makeString(pstrdup(startvalue))));
+                       state = CS_WAITKEY;
+                   }
+               }
+               else
+               {
+                   *wsptr++ = *ptr;
+               }
+               break;
+           case CS_INWVALUE:
+               if (*ptr == ',' || isspace((unsigned char) *ptr))
+               {
+                   *wsptr++ = '\0';
+                   result = lappend(result,
+                                    makeDefElem(pstrdup(workspace),
+                                                (Node *) makeString(pstrdup(startvalue))));
+                   state = CS_WAITKEY;
+               }
+               else
+               {
+                   *wsptr++ = *ptr;
+               }
+               break;
+           default:
+               elog(ERROR, "unrecognized deserialize_deflist state: %d",
+                    state);
+       }
+   }
+
+   if (state == CS_INWVALUE)
+   {
+       *wsptr++ = '\0';
+       result = lappend(result,
+                        makeDefElem(pstrdup(workspace),
+                                    (Node *) makeString(pstrdup(startvalue))));
+   }
+   else if (state != CS_WAITKEY)
+       ereport(ERROR,
+               (errcode(ERRCODE_SYNTAX_ERROR),
+                errmsg("invalid parameter list format: \"%s\"",
+                       TextPGetCString(in))));
+
+   pfree(workspace);
+
+   return result;
+}
index f0bc2feedecbb02ed6a7401de6b0ea7015fdfe61..03f2dd928c2a3e77a41af2e81314ed8e57d21c0d 100644 (file)
@@ -6,12 +6,13 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/snowball/dict_snowball.c,v 1.1 2007/08/21 01:11:16 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/snowball/dict_snowball.c,v 1.2 2007/08/22 01:39:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "commands/defrem.h"
 #include "fmgr.h"
 #include "tsearch/ts_locale.h"
 #include "tsearch/ts_public.h"
@@ -185,59 +186,44 @@ locate_stem_module(DictSnowball * d, char *lang)
 Datum
 dsnowball_init(PG_FUNCTION_ARGS)
 {
-   text       *in;
+   List       *dictoptions = (List *) PG_GETARG_POINTER(0);
    DictSnowball *d;
-   Map        *cfg,
-              *pcfg;
    bool        stoploaded = false;
-
-   /* init functions must defend against NULLs for themselves */
-   if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
-       ereport(ERROR,
-               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                errmsg("NULL config not allowed for Snowball")));
-   in = PG_GETARG_TEXT_P(0);
+   ListCell   *l;
 
    d = (DictSnowball *) palloc0(sizeof(DictSnowball));
    d->stoplist.wordop = recode_and_lowerstr;
 
-   parse_keyvalpairs(in, &cfg);
-   pcfg = cfg;
-   PG_FREE_IF_COPY(in, 0);
-
-   while (pcfg && pcfg->key)
+   foreach(l, dictoptions)
    {
-       if (pg_strcasecmp("StopWords", pcfg->key) == 0)
+       DefElem    *defel = (DefElem *) lfirst(l);
+
+       if (pg_strcasecmp("StopWords", defel->defname) == 0)
        {
            if (stoploaded)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("multiple StopWords parameters")));
-           readstoplist(pcfg->value, &d->stoplist);
+           readstoplist(defGetString(defel), &d->stoplist);
            sortstoplist(&d->stoplist);
            stoploaded = true;
        }
-       else if (pg_strcasecmp("Language", pcfg->key) == 0)
+       else if (pg_strcasecmp("Language", defel->defname) == 0)
        {
            if (d->stem)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("multiple Language parameters")));
-           locate_stem_module(d, pcfg->value);
+           locate_stem_module(d, defGetString(defel));
        }
        else
        {
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("unrecognized Snowball parameter: \"%s\"",
-                           pcfg->key)));
+                           defel->defname)));
        }
-
-       pfree(pcfg->key);
-       pfree(pcfg->value);
-       pcfg++;
    }
-   pfree(cfg);
 
    if (!d->stem)
        ereport(ERROR,
index 5f1f3e772e80a1d78701e67124f0ce8e4f9a8526..873a5bf5592d11497d772a90c8a3442ddac70adb 100644 (file)
@@ -1,9 +1,9 @@
--- $PostgreSQL: pgsql/src/backend/snowball/snowball.sql.in,v 1.1 2007/08/21 01:11:16 tgl Exp $$
+-- $PostgreSQL: pgsql/src/backend/snowball/snowball.sql.in,v 1.2 2007/08/22 01:39:44 tgl Exp $$
 
 -- text search configuration for _CFGNAME_ language
 CREATE TEXT SEARCH DICTIONARY _DICTNAME_
    (TEMPLATE = snowball,
-   OPTION = 'Language=_DICTNAME__STOPWORDS_');
+   Language = _DICTNAME_ _STOPWORDS_);
 
 COMMENT ON TEXT SEARCH DICTIONARY _DICTNAME_ IS 'Snowball stemmer for _DICTNAME_ language';
 
index f7cee1073005f1303c481a889437a10cf61a1acc..802a64508787460f496a724521a2f37c91222e10 100644 (file)
@@ -7,12 +7,13 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/tsearch/dict_ispell.c,v 1.1 2007/08/21 01:11:18 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/tsearch/dict_ispell.c,v 1.2 2007/08/22 01:39:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "commands/defrem.h"
 #include "tsearch/dicts/spell.h"
 #include "tsearch/ts_locale.h"
 #include "tsearch/ts_public.h"
@@ -30,59 +31,49 @@ typedef struct
 Datum
 dispell_init(PG_FUNCTION_ARGS)
 {
+   List       *dictoptions = (List *) PG_GETARG_POINTER(0);
    DictISpell *d;
-   Map        *cfg,
-              *pcfg;
    bool        affloaded = false,
                dictloaded = false,
                stoploaded = false;
-   text       *in;
-
-   /* init functions must defend against NULLs for themselves */
-   if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
-       ereport(ERROR,
-               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                errmsg("NULL config not allowed for ISpell")));
-   in = PG_GETARG_TEXT_P(0);
-
-   parse_keyvalpairs(in, &cfg);
-   PG_FREE_IF_COPY(in, 0);
+   ListCell   *l;
 
    d = (DictISpell *) palloc0(sizeof(DictISpell));
    d->stoplist.wordop = recode_and_lowerstr;
 
-   pcfg = cfg;
-   while (pcfg->key)
+   foreach(l, dictoptions)
    {
-       if (pg_strcasecmp("DictFile", pcfg->key) == 0)
+       DefElem    *defel = (DefElem *) lfirst(l);
+
+       if (pg_strcasecmp(defel->defname, "DictFile") == 0)
        {
            if (dictloaded)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("multiple DictFile parameters")));
            NIImportDictionary(&(d->obj),
-                              get_tsearch_config_filename(pcfg->value,
+                              get_tsearch_config_filename(defGetString(defel),
                                                           "dict"));
            dictloaded = true;
        }
-       else if (pg_strcasecmp("AffFile", pcfg->key) == 0)
+       else if (pg_strcasecmp(defel->defname, "AffFile") == 0)
        {
            if (affloaded)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("multiple AffFile parameters")));
            NIImportAffixes(&(d->obj),
-                           get_tsearch_config_filename(pcfg->value,
+                           get_tsearch_config_filename(defGetString(defel),
                                                        "affix"));
            affloaded = true;
        }
-       else if (pg_strcasecmp("StopWords", pcfg->key) == 0)
+       else if (pg_strcasecmp(defel->defname, "StopWords") == 0)
        {
            if (stoploaded)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("multiple StopWords parameters")));
-           readstoplist(pcfg->value, &(d->stoplist));
+           readstoplist(defGetString(defel), &(d->stoplist));
            sortstoplist(&(d->stoplist));
            stoploaded = true;
        }
@@ -91,13 +82,9 @@ dispell_init(PG_FUNCTION_ARGS)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("unrecognized ISpell parameter: \"%s\"",
-                           pcfg->key)));
+                           defel->defname)));
        }
-       pfree(pcfg->key);
-       pfree(pcfg->value);
-       pcfg++;
    }
-   pfree(cfg);
 
    if (affloaded && dictloaded)
    {
index 2c1bc3d017ee33fdc0f11abe1a1df49fd4b0d288..fcc08ea180da5d561626e6b80a69004f8001de85 100644 (file)
@@ -7,12 +7,13 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/tsearch/dict_simple.c,v 1.1 2007/08/21 01:11:18 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/tsearch/dict_simple.c,v 1.2 2007/08/22 01:39:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "commands/defrem.h"
 #include "tsearch/ts_locale.h"
 #include "tsearch/ts_public.h"
 #include "tsearch/ts_utils.h"
@@ -28,18 +29,34 @@ typedef struct
 Datum
 dsimple_init(PG_FUNCTION_ARGS)
 {
+   List       *dictoptions = (List *) PG_GETARG_POINTER(0);
    DictExample *d = (DictExample *) palloc0(sizeof(DictExample));
+   bool        stoploaded = false;
+   ListCell   *l;
 
    d->stoplist.wordop = recode_and_lowerstr;
 
-   if (!PG_ARGISNULL(0) && PG_GETARG_POINTER(0) != NULL)
+   foreach(l, dictoptions)
    {
-       text   *in = PG_GETARG_TEXT_P(0);
-       char   *filename = TextPGetCString(in);
+       DefElem    *defel = (DefElem *) lfirst(l);
 
-       readstoplist(filename, &d->stoplist);
-       sortstoplist(&d->stoplist);
-       pfree(filename);
+       if (pg_strcasecmp("StopWords", defel->defname) == 0)
+       {
+           if (stoploaded)
+               ereport(ERROR,
+                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                        errmsg("multiple StopWords parameters")));
+           readstoplist(defGetString(defel), &d->stoplist);
+           sortstoplist(&d->stoplist);
+           stoploaded = true;
+       }
+       else
+       {
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("unrecognized simple dictionary parameter: \"%s\"",
+                           defel->defname)));
+       }
    }
 
    PG_RETURN_POINTER(d);
index 8c544ad4f8aba495bfed226815181fb987edc1f5..70700db41fb8653d38188abbcd07a2579f8a12d8 100644 (file)
@@ -7,13 +7,14 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/tsearch/dict_thesaurus.c,v 1.1 2007/08/21 01:11:18 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/tsearch/dict_thesaurus.c,v 1.2 2007/08/22 01:39:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/namespace.h"
+#include "commands/defrem.h"
 #include "storage/fd.h"
 #include "tsearch/ts_cache.h"
 #include "tsearch/ts_locale.h"
@@ -593,57 +594,43 @@ compileTheSubstitute(DictThesaurus * d)
 Datum
 thesaurus_init(PG_FUNCTION_ARGS)
 {
+   List       *dictoptions = (List *) PG_GETARG_POINTER(0);
    DictThesaurus *d;
-   Map        *cfg,
-              *pcfg;
-   text       *in;
    char       *subdictname = NULL;
    bool        fileloaded = false;
-
-   /* init functions must defend against NULLs for themselves */
-   if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
-       ereport(ERROR,
-               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                errmsg("NULL config not allowed for Thesaurus")));
-   in = PG_GETARG_TEXT_P(0);
-
-   parse_keyvalpairs(in, &cfg);
-   PG_FREE_IF_COPY(in, 0);
+   ListCell   *l;
 
    d = (DictThesaurus *) palloc0(sizeof(DictThesaurus));
 
-   pcfg = cfg;
-   while (pcfg->key)
+   foreach(l, dictoptions)
    {
-       if (pg_strcasecmp("DictFile", pcfg->key) == 0)
+       DefElem    *defel = (DefElem *) lfirst(l);
+
+       if (pg_strcasecmp("DictFile", defel->defname) == 0)
        {
            if (fileloaded)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("multiple DictFile parameters")));
-           thesaurusRead(pcfg->value, d);
+           thesaurusRead(defGetString(defel), d);
            fileloaded = true;
        }
-       else if (pg_strcasecmp("Dictionary", pcfg->key) == 0)
+       else if (pg_strcasecmp("Dictionary", defel->defname) == 0)
        {
            if (subdictname)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("multiple Dictionary parameters")));
-           subdictname = pstrdup(pcfg->value);
+           subdictname = pstrdup(defGetString(defel));
        }
        else
        {
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("unrecognized Thesaurus parameter: \"%s\"",
-                           pcfg->key)));
+                           defel->defname)));
        }
-       pfree(pcfg->key);
-       pfree(pcfg->value);
-       pcfg++;
    }
-   pfree(cfg);
 
    if (!fileloaded)
        ereport(ERROR,
index bb0a75ca85aa348f11302d5c60a1efee46ecce2f..9270c403696156cf1deaf19af793ebb9cab577f8 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/tsearch/ts_utils.c,v 1.1 2007/08/21 01:11:18 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/tsearch/ts_utils.c,v 1.2 2007/08/22 01:39:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "utils/builtins.h"
 
 
-#define CS_WAITKEY 0
-#define CS_INKEY   1
-#define CS_WAITEQ  2
-#define CS_WAITVALUE   3
-#define CS_INVALUE 4
-#define CS_IN2VALUE 5
-#define CS_WAITDELIM   6
-#define CS_INESC   7
-#define CS_IN2ESC  8
-
-static char *
-nstrdup(char *ptr, int len)
-{
-   char       *res = palloc(len + 1),
-              *cptr;
-
-   memcpy(res, ptr, len);
-   res[len] = '\0';
-   cptr = ptr = res;
-   while (*ptr)
-   {
-       if (t_iseq(ptr, '\\'))
-           ptr++;
-       COPYCHAR(cptr, ptr);
-       cptr += pg_mblen(ptr);
-       ptr += pg_mblen(ptr);
-   }
-   *cptr = '\0';
-
-   return res;
-}
-
-/*
- * Parse a parameter string consisting of key = value clauses
- */
-void
-parse_keyvalpairs(text *in, Map ** m)
-{
-   Map        *mptr;
-   char       *ptr = VARDATA(in),
-              *begin = NULL;
-   char        num = 0;
-   int         state = CS_WAITKEY;
-
-   while (ptr - VARDATA(in) < VARSIZE(in) - VARHDRSZ)
-   {
-       if (t_iseq(ptr, ','))
-           num++;
-       ptr += pg_mblen(ptr);
-   }
-
-   *m = mptr = (Map *) palloc(sizeof(Map) * (num + 2));
-   memset(mptr, 0, sizeof(Map) * (num + 2));
-   ptr = VARDATA(in);
-   while (ptr - VARDATA(in) < VARSIZE(in) - VARHDRSZ)
-   {
-       if (state == CS_WAITKEY)
-       {
-           if (t_isalpha(ptr))
-           {
-               begin = ptr;
-               state = CS_INKEY;
-           }
-           else if (!t_isspace(ptr))
-               ereport(ERROR,
-                       (errcode(ERRCODE_SYNTAX_ERROR),
-                        errmsg("invalid parameter list format: \"%s\"",
-                               TextPGetCString(in))));
-       }
-       else if (state == CS_INKEY)
-       {
-           if (t_isspace(ptr))
-           {
-               mptr->key = nstrdup(begin, ptr - begin);
-               state = CS_WAITEQ;
-           }
-           else if (t_iseq(ptr, '='))
-           {
-               mptr->key = nstrdup(begin, ptr - begin);
-               state = CS_WAITVALUE;
-           }
-           else if (!t_isalpha(ptr))
-               ereport(ERROR,
-                       (errcode(ERRCODE_SYNTAX_ERROR),
-                        errmsg("invalid parameter list format: \"%s\"",
-                               TextPGetCString(in))));
-       }
-       else if (state == CS_WAITEQ)
-       {
-           if (t_iseq(ptr, '='))
-               state = CS_WAITVALUE;
-           else if (!t_isspace(ptr))
-               ereport(ERROR,
-                       (errcode(ERRCODE_SYNTAX_ERROR),
-                        errmsg("invalid parameter list format: \"%s\"",
-                               TextPGetCString(in))));
-       }
-       else if (state == CS_WAITVALUE)
-       {
-           if (t_iseq(ptr, '"'))
-           {
-               begin = ptr + 1;
-               state = CS_INVALUE;
-           }
-           else if (!t_isspace(ptr))
-           {
-               begin = ptr;
-               state = CS_IN2VALUE;
-           }
-       }
-       else if (state == CS_INVALUE)
-       {
-           if (t_iseq(ptr, '"'))
-           {
-               mptr->value = nstrdup(begin, ptr - begin);
-               mptr++;
-               state = CS_WAITDELIM;
-           }
-           else if (t_iseq(ptr, '\\'))
-               state = CS_INESC;
-       }
-       else if (state == CS_IN2VALUE)
-       {
-           if (t_isspace(ptr) || t_iseq(ptr, ','))
-           {
-               mptr->value = nstrdup(begin, ptr - begin);
-               mptr++;
-               state = (t_iseq(ptr, ',')) ? CS_WAITKEY : CS_WAITDELIM;
-           }
-           else if (t_iseq(ptr, '\\'))
-               state = CS_INESC;
-       }
-       else if (state == CS_WAITDELIM)
-       {
-           if (t_iseq(ptr, ','))
-               state = CS_WAITKEY;
-           else if (!t_isspace(ptr))
-               ereport(ERROR,
-                       (errcode(ERRCODE_SYNTAX_ERROR),
-                        errmsg("invalid parameter list format: \"%s\"",
-                               TextPGetCString(in))));
-       }
-       else if (state == CS_INESC)
-           state = CS_INVALUE;
-       else if (state == CS_IN2ESC)
-           state = CS_IN2VALUE;
-       else
-           elog(ERROR, "unrecognized parse_keyvalpairs state: %d", state);
-       ptr += pg_mblen(ptr);
-   }
-
-   if (state == CS_IN2VALUE)
-   {
-       mptr->value = nstrdup(begin, ptr - begin);
-       mptr++;
-   }
-   else if (!(state == CS_WAITDELIM || state == CS_WAITKEY))
-       ereport(ERROR,
-               (errcode(ERRCODE_SYNTAX_ERROR),
-                errmsg("invalid parameter list format: \"%s\"",
-                       TextPGetCString(in))));
-}
-
 /*
  * Given the base name and extension of a tsearch config file, return
  * its full path name.  The base name is assumed to be user-supplied,
index 0b374e8159eb130e0cc87e076ced2c10ebff0805..e927e98aab2f147ba9188d7e0f6e0dde5605d67f 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/tsearch/wparser.c,v 1.1 2007/08/21 01:11:18 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/tsearch/wparser.c,v 1.2 2007/08/22 01:39:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,7 @@
 #include "catalog/namespace.h"
 #include "catalog/pg_ts_parser.h"
 #include "catalog/pg_type.h"
+#include "commands/defrem.h"
 #include "tsearch/ts_cache.h"
 #include "tsearch/ts_public.h"
 #include "tsearch/ts_utils.h"
@@ -300,6 +301,7 @@ ts_headline_byid_opt(PG_FUNCTION_ARGS)
    TSQuery     query = PG_GETARG_TSQUERY(2);
    text       *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_P(3) : NULL;
    HeadlineText prs;
+   List       *prsoptions;
    text       *out;
    TSConfigCacheEntry *cfg;
    TSParserCacheEntry *prsobj;
@@ -313,9 +315,14 @@ ts_headline_byid_opt(PG_FUNCTION_ARGS)
 
    hlparsetext(cfg->cfgId, &prs, query, VARDATA(in), VARSIZE(in) - VARHDRSZ);
 
+   if (opt)
+       prsoptions = deserialize_deflist(PointerGetDatum(opt));
+   else
+       prsoptions = NIL;
+
    FunctionCall3(&(prsobj->prsheadline),
                  PointerGetDatum(&prs),
-                 PointerGetDatum(opt),
+                 PointerGetDatum(prsoptions),
                  PointerGetDatum(query));
 
    out = generatHeadline(&prs);
index 8d71e3e914e3f4e7359b3ade870874c8bf40d714..5b47f66d07fdf77c93e21cf4bdbed3eeb0f8d3d6 100644 (file)
@@ -7,13 +7,14 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/tsearch/wparser_def.c,v 1.1 2007/08/21 01:11:18 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/tsearch/wparser_def.c,v 1.2 2007/08/22 01:39:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
+#include "commands/defrem.h"
 #include "tsearch/ts_locale.h"
 #include "tsearch/ts_public.h"
 #include "tsearch/ts_type.h"
@@ -1662,7 +1663,7 @@ Datum
 prsd_headline(PG_FUNCTION_ARGS)
 {
    HeadlineParsedText *prs = (HeadlineParsedText *) PG_GETARG_POINTER(0);
-   text       *opt = (text *) PG_GETARG_POINTER(1);    /* can't be toasted */
+   List       *prsoptions = (List *) PG_GETARG_POINTER(1);
    TSQuery     query = PG_GETARG_TSQUERY(2);
 
    /* from opt + start and and tag */
@@ -1682,66 +1683,55 @@ prsd_headline(PG_FUNCTION_ARGS)
 
    int         i;
    int         highlight = 0;
+   ListCell   *l;
 
    /* config */
    prs->startsel = NULL;
    prs->stopsel = NULL;
-   if (opt)
+   foreach(l, prsoptions)
    {
-       Map        *map,
-                  *mptr;
-
-       parse_keyvalpairs(opt, &map);
-       mptr = map;
-
-       while (mptr && mptr->key)
-       {
-           if (pg_strcasecmp(mptr->key, "MaxWords") == 0)
-               max_words = pg_atoi(mptr->value, 4, 1);
-           else if (pg_strcasecmp(mptr->key, "MinWords") == 0)
-               min_words = pg_atoi(mptr->value, 4, 1);
-           else if (pg_strcasecmp(mptr->key, "ShortWord") == 0)
-               shortword = pg_atoi(mptr->value, 4, 1);
-           else if (pg_strcasecmp(mptr->key, "StartSel") == 0)
-               prs->startsel = pstrdup(mptr->value);
-           else if (pg_strcasecmp(mptr->key, "StopSel") == 0)
-               prs->stopsel = pstrdup(mptr->value);
-           else if (pg_strcasecmp(mptr->key, "HighlightAll") == 0)
-               highlight = (
-                            pg_strcasecmp(mptr->value, "1") == 0 ||
-                            pg_strcasecmp(mptr->value, "on") == 0 ||
-                            pg_strcasecmp(mptr->value, "true") == 0 ||
-                            pg_strcasecmp(mptr->value, "t") == 0 ||
-                            pg_strcasecmp(mptr->value, "y") == 0 ||
-                            pg_strcasecmp(mptr->value, "yes") == 0) ?
-                   1 : 0;
-
-           pfree(mptr->key);
-           pfree(mptr->value);
-
-           mptr++;
-       }
-       pfree(map);
-
-       if (highlight == 0)
-       {
-           if (min_words >= max_words)
-               ereport(ERROR,
-                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                        errmsg("MinWords should be less than MaxWords")));
-           if (min_words <= 0)
-               ereport(ERROR,
-                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                        errmsg("MinWords should be positive")));
-           if (shortword < 0)
-               ereport(ERROR,
-                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                        errmsg("ShortWord should be >= 0")));
-       }
+       DefElem    *defel = (DefElem *) lfirst(l);
+       char       *val = defGetString(defel);
+
+       if (pg_strcasecmp(defel->defname, "MaxWords") == 0)
+           max_words = pg_atoi(val, sizeof(int32), 0);
+       else if (pg_strcasecmp(defel->defname, "MinWords") == 0)
+           min_words = pg_atoi(val, sizeof(int32), 0);
+       else if (pg_strcasecmp(defel->defname, "ShortWord") == 0)
+           shortword = pg_atoi(val, sizeof(int32), 0);
+       else if (pg_strcasecmp(defel->defname, "StartSel") == 0)
+           prs->startsel = pstrdup(val);
+       else if (pg_strcasecmp(defel->defname, "StopSel") == 0)
+           prs->stopsel = pstrdup(val);
+       else if (pg_strcasecmp(defel->defname, "HighlightAll") == 0)
+           highlight = (pg_strcasecmp(val, "1") == 0 ||
+                        pg_strcasecmp(val, "on") == 0 ||
+                        pg_strcasecmp(val, "true") == 0 ||
+                        pg_strcasecmp(val, "t") == 0 ||
+                        pg_strcasecmp(val, "y") == 0 ||
+                        pg_strcasecmp(val, "yes") == 0);
+       else
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("unrecognized headline parameter: \"%s\"",
+                           defel->defname)));
    }
 
    if (highlight == 0)
    {
+       if (min_words >= max_words)
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("MinWords should be less than MaxWords")));
+       if (min_words <= 0)
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("MinWords should be positive")));
+       if (shortword < 0)
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("ShortWord should be >= 0")));
+
        while (hlCover(prs, query, &p, &q))
        {
            /* find cover len in words */
index cd3a9dad57116e7cb1f12f674433cbaf572e6b8e..94051b8c32f1233c3c9e259bb349bb617b31c951 100644 (file)
@@ -20,7 +20,7 @@
  * Copyright (c) 2006-2007, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/cache/ts_cache.c,v 1.1 2007/08/21 01:11:19 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/cache/ts_cache.c,v 1.2 2007/08/22 01:39:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -37,9 +37,9 @@
 #include "catalog/pg_ts_parser.h"
 #include "catalog/pg_ts_template.h"
 #include "catalog/pg_type.h"
+#include "commands/defrem.h"
 #include "miscadmin.h"
 #include "tsearch/ts_cache.h"
-#include "tsearch/ts_utils.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/catcache.h"
@@ -252,7 +252,7 @@ lookup_ts_dictionary_cache(Oid dictId)
                    tptmpl;
        Form_pg_ts_dict dict;
        Form_pg_ts_template template;
-       MemoryContext saveCtx = NULL;
+       MemoryContext saveCtx;
 
        tpdict = SearchSysCache(TSDICTOID,
                                ObjectIdGetDatum(dictId),
@@ -319,21 +319,30 @@ lookup_ts_dictionary_cache(Oid dictId)
 
        if (OidIsValid(template->tmplinit))
        {
-           bool        isnull;
+           List       *dictoptions;
            Datum       opt;
+           bool        isnull;
+           MemoryContext oldcontext;
+
+           /*
+            * Init method runs in dictionary's private memory context,
+            * and we make sure the options are stored there too
+            */
+           oldcontext = MemoryContextSwitchTo(entry->dictCtx);
 
            opt = SysCacheGetAttr(TSDICTOID, tpdict,
                                  Anum_pg_ts_dict_dictinitoption,
                                  &isnull);
            if (isnull)
-               opt = PointerGetDatum(NULL);
+               dictoptions = NIL;
+           else
+               dictoptions = deserialize_deflist(opt);
 
-           /*
-            * Init method runs in dictionary's private memory context
-            */
-           saveCtx = MemoryContextSwitchTo(entry->dictCtx);
-           entry->dictData = DatumGetPointer(OidFunctionCall1(template->tmplinit, opt));
-           MemoryContextSwitchTo(saveCtx);
+           entry->dictData =
+               DatumGetPointer(OidFunctionCall1(template->tmplinit,
+                                           PointerGetDatum(dictoptions)));
+
+           MemoryContextSwitchTo(oldcontext);
        }
 
        ReleaseSysCache(tptmpl);
index 4d4d7f7986e9ffb241f004d4d247b5fa90e689c7..7da419db6aa966733f2e6410a9fafcac223a7f3c 100644 (file)
@@ -12,7 +12,7 @@
  * by PostgreSQL
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.470 2007/08/21 01:11:21 tgl Exp $
+ *   $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.471 2007/08/22 01:39:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -8288,11 +8288,9 @@ dumpTSDictionary(Archive *fout, TSDictInfo * dictinfo)
 
    PQclear(res);
 
+   /* the dictinitoption can be dumped straight into the command */
    if (dictinfo->dictinitoption)
-   {
-       appendPQExpBuffer(q, ",\n    OPTION = ");
-       appendStringLiteralConn(q, dictinfo->dictinitoption, g_conn);
-   }
+       appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
 
    appendPQExpBuffer(q, " );\n");
 
index a050ff1d3ccef34354552d21b5a8bb738e03f4a6..be40e7cf0f3d7efc0269d8a7978a35e6d2bf7d85 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.416 2007/08/21 01:11:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.417 2007/08/22 01:39:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 200708201
+#define CATALOG_VERSION_NO 200708211
 
 #endif
index 1a624c6dbe0cad293f6facf7ff40808c993caba3..a19bda2ab7e30485223f7c17320d8022397fa712 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.463 2007/08/21 01:11:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.464 2007/08/22 01:39:45 tgl Exp $
  *
  * NOTES
  *   The script catalog/genbki.sh reads this file and generates .bki
@@ -4311,7 +4311,7 @@ DATA(insert OID = 3718 (  prsd_nexttoken  PGNSP PGUID 12 1 0 f f t f i 3 2281 "22
 DESCR("");
 DATA(insert OID = 3719 (  prsd_end         PGNSP PGUID 12 1 0 f f t f i 1 2278 "2281" _null_ _null_ _null_ prsd_end - _null_ ));
 DESCR("");
-DATA(insert OID = 3720 (  prsd_headline        PGNSP PGUID 12 1 0 f f t f i 3 2281 "2281 25 3615" _null_ _null_ _null_ prsd_headline - _null_ ));
+DATA(insert OID = 3720 (  prsd_headline        PGNSP PGUID 12 1 0 f f t f i 3 2281 "2281 2281 3615" _null_ _null_ _null_ prsd_headline - _null_ ));
 DESCR("");
 DATA(insert OID = 3721 (  prsd_lextype     PGNSP PGUID 12 1 0 f f t f i 1 2281 "2281" _null_ _null_ _null_ prsd_lextype - _null_ ));
 DESCR("");
@@ -4321,22 +4321,22 @@ DESCR("normalize one word by dictionary");
 DATA(insert OID = 3724 (  ts_lexize            PGNSP PGUID 12 1 0 f f t f s 2 1009 "25 25" _null_ _null_ _null_ ts_lexize_byname - _null_ ));
 DESCR("normalize one word by dictionary");
 
-DATA(insert OID = 3725 (  dsimple_init     PGNSP PGUID 12 1 0 f f f f i 1 2281 "2281" _null_ _null_ _null_ dsimple_init - _null_ ));
+DATA(insert OID = 3725 (  dsimple_init     PGNSP PGUID 12 1 0 f f t f i 1 2281 "2281" _null_ _null_ _null_ dsimple_init - _null_ ));
 DESCR("");
 DATA(insert OID = 3726 (  dsimple_lexize   PGNSP PGUID 12 1 0 f f t f i 4 2281 "2281 2281 2281 2281" _null_ _null_ _null_ dsimple_lexize - _null_ ));
 DESCR("");
 
-DATA(insert OID = 3728 (  dsynonym_init        PGNSP PGUID 12 1 0 f f f f i 1 2281 "2281" _null_ _null_ _null_ dsynonym_init - _null_ ));
+DATA(insert OID = 3728 (  dsynonym_init        PGNSP PGUID 12 1 0 f f t f i 1 2281 "2281" _null_ _null_ _null_ dsynonym_init - _null_ ));
 DESCR("");
 DATA(insert OID = 3729 (  dsynonym_lexize  PGNSP PGUID 12 1 0 f f t f i 4 2281 "2281 2281 2281 2281" _null_ _null_ _null_ dsynonym_lexize - _null_ ));
 DESCR("");
 
-DATA(insert OID = 3731 (  dispell_init     PGNSP PGUID 12 1 0 f f f f i 1 2281 "2281" _null_ _null_ _null_ dispell_init - _null_ ));
+DATA(insert OID = 3731 (  dispell_init     PGNSP PGUID 12 1 0 f f t f i 1 2281 "2281" _null_ _null_ _null_ dispell_init - _null_ ));
 DESCR("");
 DATA(insert OID = 3732 (  dispell_lexize   PGNSP PGUID 12 1 0 f f t f i 4 2281 "2281 2281 2281 2281" _null_ _null_ _null_ dispell_lexize - _null_ ));
 DESCR("");
 
-DATA(insert OID = 3740 (  thesaurus_init   PGNSP PGUID 12 1 0 f f f f i 1 2281 "2281" _null_ _null_ _null_ thesaurus_init - _null_ ));
+DATA(insert OID = 3740 (  thesaurus_init   PGNSP PGUID 12 1 0 f f t f i 1 2281 "2281" _null_ _null_ _null_ thesaurus_init - _null_ ));
 DESCR("");
 DATA(insert OID = 3741 (  thesaurus_lexize PGNSP PGUID 12 1 0 f f t f i 4 2281 "2281 2281 2281 2281" _null_ _null_ _null_ thesaurus_lexize - _null_ ));
 DESCR("");
index 514507d26f08ec283bc877bad425d5e05f964187..e3c0af870df9833051808da8229eebdd92163b21 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.83 2007/08/21 01:11:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.84 2007/08/22 01:39:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -121,6 +121,9 @@ extern void RemoveTSConfigurationById(Oid cfgId);
 extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
 extern void AlterTSConfigurationOwner(List *name, Oid newOwnerId);
 
+extern text *serialize_deflist(List *deflist);
+extern List *deserialize_deflist(Datum txt);
+
 /* support routines in commands/define.c */
 
 extern char *case_translate_language_name(const char *input);
index 8e8fa5cc6ff0ee4109b2787a2f7145da3299db1e..718abdb61d4aee65c90bda693bae48b290f3f469 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1998-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/tsearch/ts_public.h,v 1.1 2007/08/21 01:11:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/tsearch/ts_public.h,v 1.2 2007/08/22 01:39:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,16 +59,6 @@ typedef struct
 /*
  * Common useful things for tsearch subsystem
  */
-
-/* simple parser of cfg string looking like "key=val, key='val'" */
-typedef struct
-{
-   char       *key;
-   char       *value;
-} Map;
-
-extern void parse_keyvalpairs(text *in, Map ** m);
-
 extern char *get_tsearch_config_filename(const char *basename,
                                         const char *extension);