diff --git a/doc/src/sgml/ref/alter_tsdictionary.sgml b/doc/src/sgml/ref/alter_tsdictionary.sgml
index 59c33666557..a2929c70d12 100644
--- a/doc/src/sgml/ref/alter_tsdictionary.sgml
+++ b/doc/src/sgml/ref/alter_tsdictionary.sgml
@@ -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_russian ( option = 'Language=russian, StopWords=my_russian' );
+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_dict ( language = dutch, StopWords );
diff --git a/doc/src/sgml/ref/create_tsdictionary.sgml b/doc/src/sgml/ref/create_tsdictionary.sgml
index 81c6a0c6edb..9aa53a6a7c4 100644
--- a/doc/src/sgml/ref/create_tsdictionary.sgml
+++ b/doc/src/sgml/ref/create_tsdictionary.sgml
@@ -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
+);
+
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index af34c58c7c2..7c5a1c49a33 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -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)
- {
- 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] = ' ';
- }
}
else
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("text search dictionary parameter \"%s\" not recognized",
- defel->defname)));
+ {
+ /* Assume it's an option for the dictionary itself */
+ dictoptions = lappend(dictoptions, defel);
+ }
}
/*
* 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;
+}
diff --git a/src/backend/snowball/dict_snowball.c b/src/backend/snowball/dict_snowball.c
index f0bc2feedec..03f2dd928c2 100644
--- a/src/backend/snowball/dict_snowball.c
+++ b/src/backend/snowball/dict_snowball.c
@@ -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,
diff --git a/src/backend/snowball/snowball.sql.in b/src/backend/snowball/snowball.sql.in
index 5f1f3e772e8..873a5bf5592 100644
--- a/src/backend/snowball/snowball.sql.in
+++ b/src/backend/snowball/snowball.sql.in
@@ -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';
diff --git a/src/backend/tsearch/dict_ispell.c b/src/backend/tsearch/dict_ispell.c
index f7cee107300..802a6450878 100644
--- a/src/backend/tsearch/dict_ispell.c
+++ b/src/backend/tsearch/dict_ispell.c
@@ -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)
{
diff --git a/src/backend/tsearch/dict_simple.c b/src/backend/tsearch/dict_simple.c
index 2c1bc3d017e..fcc08ea180d 100644
--- a/src/backend/tsearch/dict_simple.c
+++ b/src/backend/tsearch/dict_simple.c
@@ -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);
diff --git a/src/backend/tsearch/dict_thesaurus.c b/src/backend/tsearch/dict_thesaurus.c
index 8c544ad4f8a..70700db41fb 100644
--- a/src/backend/tsearch/dict_thesaurus.c
+++ b/src/backend/tsearch/dict_thesaurus.c
@@ -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,
diff --git a/src/backend/tsearch/ts_utils.c b/src/backend/tsearch/ts_utils.c
index bb0a75ca85a..9270c403696 100644
--- a/src/backend/tsearch/ts_utils.c
+++ b/src/backend/tsearch/ts_utils.c
@@ -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 $
*
*-------------------------------------------------------------------------
*/
@@ -24,169 +24,6 @@
#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,
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 0b374e8159e..e927e98aab2 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -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);
diff --git a/src/backend/tsearch/wparser_def.c b/src/backend/tsearch/wparser_def.c
index 8d71e3e914e..5b47f66d07f 100644
--- a/src/backend/tsearch/wparser_def.c
+++ b/src/backend/tsearch/wparser_def.c
@@ -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;
+ DefElem *defel = (DefElem *) lfirst(l);
+ char *val = defGetString(defel);
- 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")));
- }
+ 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 */
diff --git a/src/backend/utils/cache/ts_cache.c b/src/backend/utils/cache/ts_cache.c
index cd3a9dad571..94051b8c32f 100644
--- a/src/backend/utils/cache/ts_cache.c
+++ b/src/backend/utils/cache/ts_cache.c
@@ -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);
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 4d4d7f7986e..7da419db6aa 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -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");
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index a050ff1d3cc..be40e7cf0f3 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -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
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 1a624c6dbe0..a19bda2ab7e 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -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("");
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 514507d26f0..e3c0af870df 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -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);
diff --git a/src/include/tsearch/ts_public.h b/src/include/tsearch/ts_public.h
index 8e8fa5cc6ff..718abdb61d4 100644
--- a/src/include/tsearch/ts_public.h
+++ b/src/include/tsearch/ts_public.h
@@ -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);