diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/commands/tsearchcmds.c | 90 | ||||
-rw-r--r-- | src/test/regress/expected/tsdicts.out | 35 | ||||
-rw-r--r-- | src/test/regress/sql/tsdicts.sql | 13 |
3 files changed, 117 insertions, 21 deletions
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c index 9dca682e874..9da8f7fd579 100644 --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -36,6 +36,7 @@ #include "commands/alter.h" #include "commands/defrem.h" #include "commands/event_trigger.h" +#include "common/string.h" #include "miscadmin.h" #include "nodes/makefuncs.h" #include "parser/parse_func.h" @@ -52,6 +53,8 @@ static void MakeConfigurationMapping(AlterTSConfigurationStmt *stmt, HeapTuple tup, Relation relMap); static void DropConfigurationMapping(AlterTSConfigurationStmt *stmt, HeapTuple tup, Relation relMap); +static DefElem *buildDefItem(const char *name, const char *val, + bool was_quoted); /* --------------------- TS Parser commands ------------------------ */ @@ -1519,9 +1522,6 @@ DropConfigurationMapping(AlterTSConfigurationStmt *stmt, * 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) @@ -1539,19 +1539,30 @@ serialize_deflist(List *deflist) 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) + + /* + * If the value is a T_Integer or T_Float, emit it without quotes, + * otherwise with quotes. This is essential to allow correct + * reconstruction of the node type as well as the value. + */ + if (IsA(defel->arg, Integer) || IsA(defel->arg, Float)) + appendStringInfoString(&buf, val); + else { - char ch = *val++; + /* If backslashes appear, force E syntax to quote them safely */ + if (strchr(val, '\\')) + appendStringInfoChar(&buf, ESCAPE_STRING_SYNTAX); + appendStringInfoChar(&buf, '\''); + while (*val) + { + char ch = *val++; - if (SQL_STR_DOUBLE(ch, true)) + if (SQL_STR_DOUBLE(ch, true)) + appendStringInfoChar(&buf, ch); appendStringInfoChar(&buf, ch); - appendStringInfoChar(&buf, ch); + } + appendStringInfoChar(&buf, '\''); } - appendStringInfoChar(&buf, '\''); if (lnext(deflist, l) != NULL) appendStringInfoString(&buf, ", "); } @@ -1566,7 +1577,7 @@ serialize_deflist(List *deflist) * * 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. + * in particular, unquoted and double-quoted strings. */ List * deserialize_deflist(Datum txt) @@ -1694,8 +1705,9 @@ deserialize_deflist(Datum txt) { *wsptr++ = '\0'; result = lappend(result, - makeDefElem(pstrdup(workspace), - (Node *) makeString(pstrdup(startvalue)), -1)); + buildDefItem(workspace, + startvalue, + true)); state = CS_WAITKEY; } } @@ -1726,8 +1738,9 @@ deserialize_deflist(Datum txt) { *wsptr++ = '\0'; result = lappend(result, - makeDefElem(pstrdup(workspace), - (Node *) makeString(pstrdup(startvalue)), -1)); + buildDefItem(workspace, + startvalue, + true)); state = CS_WAITKEY; } } @@ -1741,8 +1754,9 @@ deserialize_deflist(Datum txt) { *wsptr++ = '\0'; result = lappend(result, - makeDefElem(pstrdup(workspace), - (Node *) makeString(pstrdup(startvalue)), -1)); + buildDefItem(workspace, + startvalue, + false)); state = CS_WAITKEY; } else @@ -1760,8 +1774,9 @@ deserialize_deflist(Datum txt) { *wsptr++ = '\0'; result = lappend(result, - makeDefElem(pstrdup(workspace), - (Node *) makeString(pstrdup(startvalue)), -1)); + buildDefItem(workspace, + startvalue, + false)); } else if (state != CS_WAITKEY) ereport(ERROR, @@ -1773,3 +1788,36 @@ deserialize_deflist(Datum txt) return result; } + +/* + * Build one DefElem for deserialize_deflist + */ +static DefElem * +buildDefItem(const char *name, const char *val, bool was_quoted) +{ + /* If input was quoted, always emit as string */ + if (!was_quoted && val[0] != '\0') + { + int v; + char *endptr; + + /* Try to parse as an integer */ + errno = 0; + v = strtoint(val, &endptr, 10); + if (errno == 0 && *endptr == '\0') + return makeDefElem(pstrdup(name), + (Node *) makeInteger(v), + -1); + /* Nope, how about as a float? */ + errno = 0; + (void) strtod(val, &endptr); + if (errno == 0 && *endptr == '\0') + return makeDefElem(pstrdup(name), + (Node *) makeFloat(pstrdup(val)), + -1); + } + /* Just make it a string */ + return makeDefElem(pstrdup(name), + (Node *) makeString(pstrdup(val)), + -1); +} diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out index 5a927be9485..c8042931429 100644 --- a/src/test/regress/expected/tsdicts.out +++ b/src/test/regress/expected/tsdicts.out @@ -470,6 +470,41 @@ SELECT ts_lexize('synonym', 'indices'); {index} (1 row) +-- test altering boolean parameters +SELECT dictinitoption FROM pg_ts_dict WHERE dictname = 'synonym'; + dictinitoption +----------------------------- + synonyms = 'synonym_sample' +(1 row) + +ALTER TEXT SEARCH DICTIONARY synonym (CaseSensitive = 1); +SELECT ts_lexize('synonym', 'PoStGrEs'); + ts_lexize +----------- + +(1 row) + +SELECT dictinitoption FROM pg_ts_dict WHERE dictname = 'synonym'; + dictinitoption +------------------------------------------------ + synonyms = 'synonym_sample', casesensitive = 1 +(1 row) + +ALTER TEXT SEARCH DICTIONARY synonym (CaseSensitive = 2); -- fail +ERROR: casesensitive requires a Boolean value +ALTER TEXT SEARCH DICTIONARY synonym (CaseSensitive = off); +SELECT ts_lexize('synonym', 'PoStGrEs'); + ts_lexize +----------- + {pgsql} +(1 row) + +SELECT dictinitoption FROM pg_ts_dict WHERE dictname = 'synonym'; + dictinitoption +---------------------------------------------------- + synonyms = 'synonym_sample', casesensitive = 'off' +(1 row) + -- Create and simple test thesaurus dictionary -- More tests in configuration checks because ts_lexize() -- cannot pass more than one word to thesaurus. diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql index 908e6755018..ddc6c7f4453 100644 --- a/src/test/regress/sql/tsdicts.sql +++ b/src/test/regress/sql/tsdicts.sql @@ -148,6 +148,19 @@ SELECT ts_lexize('synonym', 'PoStGrEs'); SELECT ts_lexize('synonym', 'Gogle'); SELECT ts_lexize('synonym', 'indices'); +-- test altering boolean parameters +SELECT dictinitoption FROM pg_ts_dict WHERE dictname = 'synonym'; + +ALTER TEXT SEARCH DICTIONARY synonym (CaseSensitive = 1); +SELECT ts_lexize('synonym', 'PoStGrEs'); +SELECT dictinitoption FROM pg_ts_dict WHERE dictname = 'synonym'; + +ALTER TEXT SEARCH DICTIONARY synonym (CaseSensitive = 2); -- fail + +ALTER TEXT SEARCH DICTIONARY synonym (CaseSensitive = off); +SELECT ts_lexize('synonym', 'PoStGrEs'); +SELECT dictinitoption FROM pg_ts_dict WHERE dictname = 'synonym'; + -- Create and simple test thesaurus dictionary -- More tests in configuration checks because ts_lexize() -- cannot pass more than one word to thesaurus. |