Refactoring identifier checks to consistently use strcmp
Testing DefElem options is done with both strcmp() and pg_strcasecmp() a bit
mixed. Since the option defnames are all lowercased, either via IDENT, keyword
rules or “by hand” with makeString(), using strcmp() is safe (and assumed to be
so in quite a lot of places).
While it’s not incorrect per se to use pg_strcasecmp(), it has the potential to
hide a DefElem created with a mixed-case defname where it in other places is
expected to be in lowercase, which may lead to subtle bugs.
The attached patch refactors to use strcmp() consistently for option processing
in the command code as a pre-emptive belts+suspenders move against such subtle
bugs and to make the code more consistent. Also reorders a few checks to have
all in the same “format” and removes a comment related to the above.
Tested with randomizing case on options in make check (not included in patch).
cheers ./daniel
Attachments:
defname_strcmp.patchapplication/octet-stream; name=defname_strcmp.patchDownload
From 087ba6983ad2b23863c5838e27dc14b4324974fd Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <daniel@yesql.se>
Date: Mon, 3 Apr 2017 11:27:12 +0200
Subject: [PATCH 1/2] Use strcmp() instead of pg_strcasecmp() for identifier
matching
Since these option values are parsed using either the IDENT rule,
via keyword rules, or are created in lowercase with makeString(),
using strcmp() is the correct approach here. While not wrong per
se, using case insensitive matching can hide subtle bugs in case
defnames are created with mixed-case as these options otherwise
are assumed to always be lowercased.
Reorder a few checks while in there such that all checks are in
the same order to make it easier to grep/read.
Also remove comment in tsearchcmds.c:getTokenTypes() regarding
strcmp/pg_strcasecmp as the code is correct. token_type is parsed
using the IDENT rule and will always be in lowercase.
---
src/backend/commands/aggregatecmds.c | 46 +++++++++++++++++-----------------
src/backend/commands/collationcmds.c | 12 ++++-----
src/backend/commands/operatorcmds.c | 44 ++++++++++++++++-----------------
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/tsearchcmds.c | 23 +++++++++--------
src/backend/commands/typecmds.c | 48 ++++++++++++++++++------------------
src/backend/commands/view.c | 4 +--
src/backend/parser/parse_clause.c | 2 +-
src/backend/snowball/dict_snowball.c | 4 +--
src/backend/tsearch/dict_ispell.c | 6 ++---
src/backend/tsearch/dict_simple.c | 4 +--
src/backend/tsearch/dict_synonym.c | 4 +--
src/backend/tsearch/dict_thesaurus.c | 4 +--
13 files changed, 101 insertions(+), 102 deletions(-)
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 2341129..397036f 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -121,33 +121,33 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
* sfunc1, stype1, and initcond1 are accepted as obsolete spellings
* for sfunc, stype, initcond.
*/
- if (pg_strcasecmp(defel->defname, "sfunc") == 0)
+ if (strcmp(defel->defname, "sfunc") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
+ else if (strcmp(defel->defname, "sfunc1") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
+ else if (strcmp(defel->defname, "finalfunc") == 0)
finalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "combinefunc") == 0)
+ else if (strcmp(defel->defname, "combinefunc") == 0)
combinefuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "serialfunc") == 0)
+ else if (strcmp(defel->defname, "serialfunc") == 0)
serialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "deserialfunc") == 0)
+ else if (strcmp(defel->defname, "deserialfunc") == 0)
deserialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "msfunc") == 0)
+ else if (strcmp(defel->defname, "msfunc") == 0)
mtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "minvfunc") == 0)
+ else if (strcmp(defel->defname, "minvfunc") == 0)
minvtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc") == 0)
mfinalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "finalfunc_extra") == 0)
finalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
mfinalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "sortop") == 0)
+ else if (strcmp(defel->defname, "sortop") == 0)
sortoperatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "basetype") == 0)
+ else if (strcmp(defel->defname, "basetype") == 0)
baseType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "hypothetical") == 0)
+ else if (strcmp(defel->defname, "hypothetical") == 0)
{
if (defGetBoolean(defel))
{
@@ -158,23 +158,23 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
aggKind = AGGKIND_HYPOTHETICAL;
}
}
- else if (pg_strcasecmp(defel->defname, "stype") == 0)
+ else if (strcmp(defel->defname, "stype") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "stype1") == 0)
+ else if (strcmp(defel->defname, "stype1") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "sspace") == 0)
+ else if (strcmp(defel->defname, "sspace") == 0)
transSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "mstype") == 0)
+ else if (strcmp(defel->defname, "mstype") == 0)
mtransType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "msspace") == 0)
+ else if (strcmp(defel->defname, "msspace") == 0)
mtransSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "initcond") == 0)
+ else if (strcmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
+ else if (strcmp(defel->defname, "initcond1") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "minitcond") == 0)
+ else if (strcmp(defel->defname, "minitcond") == 0)
minitval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "parallel") == 0)
+ else if (strcmp(defel->defname, "parallel") == 0)
parallel = defGetString(defel);
else
ereport(WARNING,
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index 835cb26..c59c000 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -74,17 +74,17 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
DefElem *defel = castNode(DefElem, lfirst(pl));
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "from") == 0)
+ if (strcmp(defel->defname, "from") == 0)
defelp = &fromEl;
- else if (pg_strcasecmp(defel->defname, "locale") == 0)
+ else if (strcmp(defel->defname, "locale") == 0)
defelp = &localeEl;
- else if (pg_strcasecmp(defel->defname, "lc_collate") == 0)
+ else if (strcmp(defel->defname, "lc_collate") == 0)
defelp = &lccollateEl;
- else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0)
+ else if (strcmp(defel->defname, "lc_ctype") == 0)
defelp = &lcctypeEl;
- else if (pg_strcasecmp(defel->defname, "provider") == 0)
+ else if (strcmp(defel->defname, "provider") == 0)
defelp = &providerEl;
- else if (pg_strcasecmp(defel->defname, "version") == 0)
+ else if (strcmp(defel->defname, "version") == 0)
defelp = &versionEl;
else
{
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 739d587..89da097 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -105,7 +105,7 @@ DefineOperator(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "leftarg") == 0)
+ if (strcmp(defel->defname, "leftarg") == 0)
{
typeName1 = defGetTypeName(defel);
if (typeName1->setof)
@@ -113,7 +113,7 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
+ else if (strcmp(defel->defname, "rightarg") == 0)
{
typeName2 = defGetTypeName(defel);
if (typeName2->setof)
@@ -121,28 +121,28 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "procedure") == 0)
+ else if (strcmp(defel->defname, "procedure") == 0)
functionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "commutator") == 0)
+ else if (strcmp(defel->defname, "commutator") == 0)
commutatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "negator") == 0)
+ else if (strcmp(defel->defname, "negator") == 0)
negatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ else if (strcmp(defel->defname, "restrict") == 0)
restrictionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
joinName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "hashes") == 0)
+ else if (strcmp(defel->defname, "hashes") == 0)
canHash = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "merges") == 0)
canMerge = defGetBoolean(defel);
/* These obsolete options are taken as meaning canMerge */
- else if (pg_strcasecmp(defel->defname, "sort1") == 0)
+ else if (strcmp(defel->defname, "sort1") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "sort2") == 0)
+ else if (strcmp(defel->defname, "sort2") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
+ else if (strcmp(defel->defname, "ltcmp") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
+ else if (strcmp(defel->defname, "gtcmp") == 0)
canMerge = true;
else
{
@@ -420,12 +420,12 @@ AlterOperator(AlterOperatorStmt *stmt)
else
param = defGetQualifiedName(defel);
- if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ if (strcmp(defel->defname, "restrict") == 0)
{
restrictionName = param;
updateRestriction = true;
}
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
{
joinName = param;
updateJoin = true;
@@ -435,13 +435,13 @@ AlterOperator(AlterOperatorStmt *stmt)
* The rest of the options that CREATE accepts cannot be changed.
* Check for them so that we can give a meaningful error message.
*/
- else if (pg_strcasecmp(defel->defname, "leftarg") == 0 ||
- pg_strcasecmp(defel->defname, "rightarg") == 0 ||
- pg_strcasecmp(defel->defname, "procedure") == 0 ||
- pg_strcasecmp(defel->defname, "commutator") == 0 ||
- pg_strcasecmp(defel->defname, "negator") == 0 ||
- pg_strcasecmp(defel->defname, "hashes") == 0 ||
- pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "leftarg") == 0 ||
+ strcmp(defel->defname, "rightarg") == 0 ||
+ strcmp(defel->defname, "procedure") == 0 ||
+ strcmp(defel->defname, "commutator") == 0 ||
+ strcmp(defel->defname, "negator") == 0 ||
+ strcmp(defel->defname, "hashes") == 0 ||
+ strcmp(defel->defname, "merges") == 0)
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d418d56..79da667 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -9997,7 +9997,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index b58d60c..6933871 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -209,27 +209,27 @@ DefineTSParser(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "start") == 0)
+ if (strcmp(defel->defname, "start") == 0)
{
values[Anum_pg_ts_parser_prsstart - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
}
- else if (pg_strcasecmp(defel->defname, "gettoken") == 0)
+ else if (strcmp(defel->defname, "gettoken") == 0)
{
values[Anum_pg_ts_parser_prstoken - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
}
- else if (pg_strcasecmp(defel->defname, "end") == 0)
+ else if (strcmp(defel->defname, "end") == 0)
{
values[Anum_pg_ts_parser_prsend - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
}
- else if (pg_strcasecmp(defel->defname, "headline") == 0)
+ else if (strcmp(defel->defname, "headline") == 0)
{
values[Anum_pg_ts_parser_prsheadline - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
}
- else if (pg_strcasecmp(defel->defname, "lextypes") == 0)
+ else if (strcmp(defel->defname, "lextypes") == 0)
{
values[Anum_pg_ts_parser_prslextype - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
@@ -438,7 +438,7 @@ DefineTSDictionary(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "template") == 0)
+ if (strcmp(defel->defname, "template") == 0)
{
templId = get_ts_template_oid(defGetQualifiedName(defel), false);
}
@@ -580,7 +580,7 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
DefElem *oldel = (DefElem *) lfirst(cell);
next = lnext(cell);
- if (pg_strcasecmp(oldel->defname, defel->defname) == 0)
+ if (strcmp(oldel->defname, defel->defname) == 0)
dictoptions = list_delete_cell(dictoptions, cell, prev);
else
prev = cell;
@@ -765,13 +765,13 @@ DefineTSTemplate(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "init") == 0)
+ if (strcmp(defel->defname, "init") == 0)
{
values[Anum_pg_ts_template_tmplinit - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
nulls[Anum_pg_ts_template_tmplinit - 1] = false;
}
- else if (pg_strcasecmp(defel->defname, "lexize") == 0)
+ else if (strcmp(defel->defname, "lexize") == 0)
{
values[Anum_pg_ts_template_tmpllexize - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
@@ -990,9 +990,9 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "parser") == 0)
+ if (strcmp(defel->defname, "parser") == 0)
prsOid = get_ts_parser_oid(defGetQualifiedName(defel), false);
- else if (pg_strcasecmp(defel->defname, "copy") == 0)
+ else if (strcmp(defel->defname, "copy") == 0)
sourceOid = get_ts_config_oid(defGetQualifiedName(defel), false);
else
ereport(ERROR,
@@ -1251,7 +1251,6 @@ getTokenTypes(Oid prsId, List *tokennames)
j = 0;
while (list && list[j].lexid)
{
- /* XXX should we use pg_strcasecmp here? */
if (strcmp(strVal(val), list[j].alias) == 0)
{
res[i] = list[j].lexid;
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index c765e97..f807b1e 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -245,42 +245,42 @@ DefineType(ParseState *pstate, List *names, List *parameters)
DefElem *defel = (DefElem *) lfirst(pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "like") == 0)
+ if (strcmp(defel->defname, "like") == 0)
defelp = &likeTypeEl;
- else if (pg_strcasecmp(defel->defname, "internallength") == 0)
+ else if (strcmp(defel->defname, "internallength") == 0)
defelp = &internalLengthEl;
- else if (pg_strcasecmp(defel->defname, "input") == 0)
+ else if (strcmp(defel->defname, "input") == 0)
defelp = &inputNameEl;
- else if (pg_strcasecmp(defel->defname, "output") == 0)
+ else if (strcmp(defel->defname, "output") == 0)
defelp = &outputNameEl;
- else if (pg_strcasecmp(defel->defname, "receive") == 0)
+ else if (strcmp(defel->defname, "receive") == 0)
defelp = &receiveNameEl;
- else if (pg_strcasecmp(defel->defname, "send") == 0)
+ else if (strcmp(defel->defname, "send") == 0)
defelp = &sendNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
+ else if (strcmp(defel->defname, "typmod_in") == 0)
defelp = &typmodinNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
+ else if (strcmp(defel->defname, "typmod_out") == 0)
defelp = &typmodoutNameEl;
- else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
- pg_strcasecmp(defel->defname, "analyse") == 0)
+ else if (strcmp(defel->defname, "analyze") == 0 ||
+ strcmp(defel->defname, "analyse") == 0)
defelp = &analyzeNameEl;
- else if (pg_strcasecmp(defel->defname, "category") == 0)
+ else if (strcmp(defel->defname, "category") == 0)
defelp = &categoryEl;
- else if (pg_strcasecmp(defel->defname, "preferred") == 0)
+ else if (strcmp(defel->defname, "preferred") == 0)
defelp = &preferredEl;
- else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
+ else if (strcmp(defel->defname, "delimiter") == 0)
defelp = &delimiterEl;
- else if (pg_strcasecmp(defel->defname, "element") == 0)
+ else if (strcmp(defel->defname, "element") == 0)
defelp = &elemTypeEl;
- else if (pg_strcasecmp(defel->defname, "default") == 0)
+ else if (strcmp(defel->defname, "default") == 0)
defelp = &defaultValueEl;
- else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
+ else if (strcmp(defel->defname, "passedbyvalue") == 0)
defelp = &byValueEl;
- else if (pg_strcasecmp(defel->defname, "alignment") == 0)
+ else if (strcmp(defel->defname, "alignment") == 0)
defelp = &alignmentEl;
- else if (pg_strcasecmp(defel->defname, "storage") == 0)
+ else if (strcmp(defel->defname, "storage") == 0)
defelp = &storageEl;
- else if (pg_strcasecmp(defel->defname, "collatable") == 0)
+ else if (strcmp(defel->defname, "collatable") == 0)
defelp = &collatableEl;
else
{
@@ -1367,7 +1367,7 @@ DefineRange(CreateRangeStmt *stmt)
{
DefElem *defel = (DefElem *) lfirst(lc);
- if (pg_strcasecmp(defel->defname, "subtype") == 0)
+ if (strcmp(defel->defname, "subtype") == 0)
{
if (OidIsValid(rangeSubtype))
ereport(ERROR,
@@ -1376,7 +1376,7 @@ DefineRange(CreateRangeStmt *stmt)
/* we can look up the subtype name immediately */
rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
}
- else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
+ else if (strcmp(defel->defname, "subtype_opclass") == 0)
{
if (rangeSubOpclassName != NIL)
ereport(ERROR,
@@ -1384,7 +1384,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeSubOpclassName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "collation") == 0)
+ else if (strcmp(defel->defname, "collation") == 0)
{
if (rangeCollationName != NIL)
ereport(ERROR,
@@ -1392,7 +1392,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCollationName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "canonical") == 0)
+ else if (strcmp(defel->defname, "canonical") == 0)
{
if (rangeCanonicalName != NIL)
ereport(ERROR,
@@ -1400,7 +1400,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCanonicalName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
+ else if (strcmp(defel->defname, "subtype_diff") == 0)
{
if (rangeSubtypeDiffName != NIL)
ereport(ERROR,
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 6909a67..9ed5ffa 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -46,8 +46,8 @@ void
validateWithCheckOption(char *value)
{
if (value == NULL ||
- (pg_strcasecmp(value, "local") != 0 &&
- pg_strcasecmp(value, "cascaded") != 0))
+ (strcmp(value, "local") != 0 &&
+ strcmp(value, "cascaded") != 0))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index e268a12..9581526 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -262,7 +262,7 @@ interpretOidsOption(List *defList, bool allowOids)
DefElem *def = (DefElem *) lfirst(cell);
if (def->defnamespace == NULL &&
- pg_strcasecmp(def->defname, "oids") == 0)
+ strcmp(def->defname, "oids") == 0)
{
if (!allowOids)
ereport(ERROR,
diff --git a/src/backend/snowball/dict_snowball.c b/src/backend/snowball/dict_snowball.c
index 0c322a4..7d87af9 100644
--- a/src/backend/snowball/dict_snowball.c
+++ b/src/backend/snowball/dict_snowball.c
@@ -192,7 +192,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -201,7 +201,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Language", defel->defname) == 0)
+ else if (strcmp(defel->defname, "language") == 0)
{
if (d->stem)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_ispell.c b/src/backend/tsearch/dict_ispell.c
index b4576bf..8726413 100644
--- a/src/backend/tsearch/dict_ispell.c
+++ b/src/backend/tsearch/dict_ispell.c
@@ -44,7 +44,7 @@ dispell_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "DictFile") == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (dictloaded)
ereport(ERROR,
@@ -55,7 +55,7 @@ dispell_init(PG_FUNCTION_ARGS)
"dict"));
dictloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "AffFile") == 0)
+ else if (strcmp(defel->defname, "afffile") == 0)
{
if (affloaded)
ereport(ERROR,
@@ -66,7 +66,7 @@ dispell_init(PG_FUNCTION_ARGS)
"affix"));
affloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "StopWords") == 0)
+ else if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_simple.c b/src/backend/tsearch/dict_simple.c
index c361362..3cee043 100644
--- a/src/backend/tsearch/dict_simple.c
+++ b/src/backend/tsearch/dict_simple.c
@@ -41,7 +41,7 @@ dsimple_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -50,7 +50,7 @@ dsimple_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Accept", defel->defname) == 0)
+ else if (strcmp(defel->defname, "accept") == 0)
{
if (acceptloaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_synonym.c b/src/backend/tsearch/dict_synonym.c
index e67d2e6..73c4a0b 100644
--- a/src/backend/tsearch/dict_synonym.c
+++ b/src/backend/tsearch/dict_synonym.c
@@ -108,9 +108,9 @@ dsynonym_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("Synonyms", defel->defname) == 0)
+ if (strcmp(defel->defname, "synonyms") == 0)
filename = defGetString(defel);
- else if (pg_strcasecmp("CaseSensitive", defel->defname) == 0)
+ else if (strcmp(defel->defname, "casesensitive") == 0)
case_sensitive = defGetBoolean(defel);
else
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_thesaurus.c b/src/backend/tsearch/dict_thesaurus.c
index 9a01075..0cd29da 100644
--- a/src/backend/tsearch/dict_thesaurus.c
+++ b/src/backend/tsearch/dict_thesaurus.c
@@ -616,7 +616,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("DictFile", defel->defname) == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (fileloaded)
ereport(ERROR,
@@ -625,7 +625,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
thesaurusRead(defGetString(defel), d);
fileloaded = true;
}
- else if (pg_strcasecmp("Dictionary", defel->defname) == 0)
+ else if (strcmp(defel->defname, "dictionary") == 0)
{
if (subdictname)
ereport(ERROR,
--
2.6.4 (Apple Git-63)
Daniel Gustafsson wrote:
Testing DefElem options is done with both strcmp() and pg_strcasecmp() a bit
mixed. Since the option defnames are all lowercased, either via IDENT, keyword
rules or “by hand” with makeString(), using strcmp() is safe (and assumed to be
so in quite a lot of places).While it’s not incorrect per se to use pg_strcasecmp(), it has the potential to
hide a DefElem created with a mixed-case defname where it in other places is
expected to be in lowercase, which may lead to subtle bugs.The attached patch refactors to use strcmp() consistently for option processing
in the command code as a pre-emptive belts+suspenders move against such subtle
bugs and to make the code more consistent. Also reorders a few checks to have
all in the same “format” and removes a comment related to the above.Tested with randomizing case on options in make check (not included in patch).
Does it work correctly in the Turkish locale?
--
Álvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 04 Apr 2017, at 05:52, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:
Daniel Gustafsson wrote:
Testing DefElem options is done with both strcmp() and pg_strcasecmp() a bit
mixed. Since the option defnames are all lowercased, either via IDENT, keyword
rules or “by hand” with makeString(), using strcmp() is safe (and assumed to be
so in quite a lot of places).While it’s not incorrect per se to use pg_strcasecmp(), it has the potential to
hide a DefElem created with a mixed-case defname where it in other places is
expected to be in lowercase, which may lead to subtle bugs.The attached patch refactors to use strcmp() consistently for option processing
in the command code as a pre-emptive belts+suspenders move against such subtle
bugs and to make the code more consistent. Also reorders a few checks to have
all in the same “format” and removes a comment related to the above.Tested with randomizing case on options in make check (not included in patch).
Does it work correctly in the Turkish locale?
Yes, running make check with random case defnames under tr_TR works fine.
cheers ./daniel
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 04/04/2017 10:13 AM, Daniel Gustafsson wrote:
On 04 Apr 2017, at 05:52, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:
Daniel Gustafsson wrote:
Testing DefElem options is done with both strcmp() and pg_strcasecmp() a bit
mixed. Since the option defnames are all lowercased, either via IDENT, keyword
rules or “by hand” with makeString(), using strcmp() is safe (and assumed to be
so in quite a lot of places).While it’s not incorrect per se to use pg_strcasecmp(), it has the potential to
hide a DefElem created with a mixed-case defname where it in other places is
expected to be in lowercase, which may lead to subtle bugs.The attached patch refactors to use strcmp() consistently for option processing
in the command code as a pre-emptive belts+suspenders move against such subtle
bugs and to make the code more consistent. Also reorders a few checks to have
all in the same “format” and removes a comment related to the above.Tested with randomizing case on options in make check (not included in patch).
Does it work correctly in the Turkish locale?
Yes, running make check with random case defnames under tr_TR works fine.
This no longer works:
postgres=# CREATE TEXT SEARCH DICTIONARY public.simple_dict (
TEMPLATE = pg_catalog.simple,
"STOPWORds" = english
);
ERROR: unrecognized simple dictionary parameter: "STOPWORds"
In hindsight, perhaps we should always have been more strict about that
to begin wtih, but let's not break backwards-compatibility without a
better reason. I didn't thoroughly check all of the cases here, to see
if there are more like this.
It'd be nice to have some kind of a rule on when pg_strcasecmp should be
used and when strcmp() is enough. Currently, by looking at the code, I
can't tell.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Heikki Linnakangas <hlinnaka@iki.fi> writes:
This no longer works:
postgres=# CREATE TEXT SEARCH DICTIONARY public.simple_dict (
TEMPLATE = pg_catalog.simple,
"STOPWORds" = english
);
ERROR: unrecognized simple dictionary parameter: "STOPWORds"
In hindsight, perhaps we should always have been more strict about that
to begin wtih, but let's not break backwards-compatibility without a
better reason. I didn't thoroughly check all of the cases here, to see
if there are more like this.
You have a point, but I'm not sure that this is such a bad compatibility
break as to be a reason not to change things to be more consistent.
It'd be nice to have some kind of a rule on when pg_strcasecmp should be
used and when strcmp() is enough. Currently, by looking at the code, I
can't tell.
My thought is that if we are looking at words that have been through the
parser, then it should *always* be plain strcmp; we should expect that
the parser already did the appropriate case-folding. If the user
prevented case-folding by double-quoting, I don't have a lot of sympathy
for any complaints about it. Generally speaking, what we're dealing with
here is things that are logically keywords but we did not wish to make
them real parser keywords. But in SQL, once you quote a keyword, it's
not a keyword at all anymore. So I think the argument that quoting
"stopwords" should be legal at all in this context is pretty weak,
and the argument that quoting a weirdly-cased version of it should
work is even weaker.
pg_strcasecmp would be appropriate, perhaps, if we're dealing with stuff
that somehow came in without going through the parser.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Aug 16, 2017 at 11:51 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
You have a point, but I'm not sure that this is such a bad compatibility
break as to be a reason not to change things to be more consistent.
+1.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 16 Aug 2017, at 17:51, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Heikki Linnakangas <hlinnaka@iki.fi> writes:
This no longer works:
postgres=# CREATE TEXT SEARCH DICTIONARY public.simple_dict (
TEMPLATE = pg_catalog.simple,
"STOPWORds" = english
);
ERROR: unrecognized simple dictionary parameter: "STOPWORds"In hindsight, perhaps we should always have been more strict about that
to begin wtih, but let's not break backwards-compatibility without a
better reason. I didn't thoroughly check all of the cases here, to see
if there are more like this.You have a point, but I'm not sure that this is such a bad compatibility
break as to be a reason not to change things to be more consistent.
I agree with this, but I admittedly have no idea how common the above case
would be in the wild.
It'd be nice to have some kind of a rule on when pg_strcasecmp should be
used and when strcmp() is enough. Currently, by looking at the code, I
can't tell.My thought is that if we are looking at words that have been through the
parser, then it should *always* be plain strcmp; we should expect that
the parser already did the appropriate case-folding.
+1
pg_strcasecmp would be appropriate, perhaps, if we're dealing with stuff
that somehow came in without going through the parser.
In that case it would be up to the consumer of the data to handle required
case-folding for the expected input, so pg_strcasecmp or strcmp depending on
situation.
cheers ./daniel
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 17 Aug 2017, at 11:08, Daniel Gustafsson <daniel@yesql.se> wrote:
On 16 Aug 2017, at 17:51, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Heikki Linnakangas <hlinnaka@iki.fi> writes:
This no longer works:
postgres=# CREATE TEXT SEARCH DICTIONARY public.simple_dict (
TEMPLATE = pg_catalog.simple,
"STOPWORds" = english
);
ERROR: unrecognized simple dictionary parameter: "STOPWORds"In hindsight, perhaps we should always have been more strict about that
to begin wtih, but let's not break backwards-compatibility without a
better reason. I didn't thoroughly check all of the cases here, to see
if there are more like this.You have a point, but I'm not sure that this is such a bad compatibility
break as to be a reason not to change things to be more consistent.I agree with this, but I admittedly have no idea how common the above case
would be in the wild.It'd be nice to have some kind of a rule on when pg_strcasecmp should be
used and when strcmp() is enough. Currently, by looking at the code, I
can't tell.My thought is that if we are looking at words that have been through the
parser, then it should *always* be plain strcmp; we should expect that
the parser already did the appropriate case-folding.+1
pg_strcasecmp would be appropriate, perhaps, if we're dealing with stuff
that somehow came in without going through the parser.In that case it would be up to the consumer of the data to handle required
case-folding for the expected input, so pg_strcasecmp or strcmp depending on
situation.
This patch has been marked “Waiting on Author”, but I’m not sure what the
concensus of this thread came to with regards to quoted keywords and backwards
compatibility. There seems to be a 2-1 vote for allowing a break, and forcing
all keywords out of the parser to be casefolded. Any other opinions?
cheers ./daniel
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Sep 5, 2017 at 5:34 PM, Daniel Gustafsson <daniel@yesql.se> wrote:
On 17 Aug 2017, at 11:08, Daniel Gustafsson <daniel@yesql.se> wrote:
On 16 Aug 2017, at 17:51, Tom Lane <tgl@sss.pgh.pa.us> wrote:
My thought is that if we are looking at words that have been through the
parser, then it should *always* be plain strcmp; we should expect that
the parser already did the appropriate case-folding.+1
pg_strcasecmp would be appropriate, perhaps, if we're dealing with stuff
that somehow came in without going through the parser.In that case it would be up to the consumer of the data to handle required
case-folding for the expected input, so pg_strcasecmp or strcmp depending on
situation.This patch has been marked “Waiting on Author”, but I’m not sure what the
concensus of this thread came to with regards to quoted keywords and backwards
compatibility. There seems to be a 2-1 vote for allowing a break, and forcing
all keywords out of the parser to be casefolded. Any other opinions?
This patch impacts the DDL grammar of aggregates, operators,
collations, text search, views, etc. Still I agree with the purpose of
this thread that it would be nice to get a more consistent behavior
even if it breaks some queries, so +1 for the argument with the
post-parser comparison which should use strcmp.
The patch needs a rebase, and there are a couple of places that need
an extra lookup I think:
$ git grep defname -- *.c | grep strcasecmp | wc -l
39
Switching to "waiting on author" for now.
Thanks,
--
Michael
On 17 Nov 2017, at 03:31, Michael Paquier <michael.paquier@gmail.com> wrote:
On Tue, Sep 5, 2017 at 5:34 PM, Daniel Gustafsson <daniel@yesql.se> wrote:
On 17 Aug 2017, at 11:08, Daniel Gustafsson <daniel@yesql.se> wrote:
On 16 Aug 2017, at 17:51, Tom Lane <tgl@sss.pgh.pa.us> wrote:
My thought is that if we are looking at words that have been through the
parser, then it should *always* be plain strcmp; we should expect that
the parser already did the appropriate case-folding.+1
pg_strcasecmp would be appropriate, perhaps, if we're dealing with stuff
that somehow came in without going through the parser.In that case it would be up to the consumer of the data to handle required
case-folding for the expected input, so pg_strcasecmp or strcmp depending on
situation.This patch has been marked “Waiting on Author”, but I’m not sure what the
concensus of this thread came to with regards to quoted keywords and backwards
compatibility. There seems to be a 2-1 vote for allowing a break, and forcing
all keywords out of the parser to be casefolded. Any other opinions?This patch impacts the DDL grammar of aggregates, operators,
collations, text search, views, etc. Still I agree with the purpose of
this thread that it would be nice to get a more consistent behavior
even if it breaks some queries, so +1 for the argument with the
post-parser comparison which should use strcmp.
Thanks for reviewing!
The patch needs a rebase, and there are a couple of places that need
an extra lookup I think:
$ git grep defname -- *.c | grep strcasecmp | wc -l
39
Rebased and handled a few more places which I had either missed in the last
round, or that had been added in the meantime. “PARALLEL” in aggregatecmds.c
is intentionally using pg_strcasecmp() due to the old-style syntax which is
still supported. AFAICS this covers all relevant codepaths from the 39 above.
cheers ./daniel
Attachments:
defname_strcmp-v2.patchapplication/octet-stream; name=defname_strcmp-v2.patchDownload
From 4b76e34ad50c38755c09c36dc552851383d4e36e Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <daniel@yesql.se>
Date: Mon, 27 Nov 2017 15:21:26 +0100
Subject: [PATCH 1/2] Use strcmp() instead of pg_strcasecmp() for identifier
matching
Since these option values are parsed using either the IDENT rule,
via keyword rules, or are created in lowercase with makeString(),
using strcmp() is the correct approach here. While not wrong per
se, using case insensitive matching can hide subtle bugs in case
defnames are created with mixed-case as these options otherwise
are assumed to always be lowercased.
Reorder a few checks while in there such that all checks are in
the same order to make it easier to grep/read.
Also remove comment in tsearchcmds.c:getTokenTypes() regarding
strcmp/pg_strcasecmp as the code is correct. token_type is parsed
using the IDENT rule and will always be in lowercase.
---
src/backend/access/common/reloptions.c | 2 +-
src/backend/commands/aggregatecmds.c | 54 +++++++++++++++++-----------------
src/backend/commands/collationcmds.c | 12 ++++----
src/backend/commands/functioncmds.c | 4 +--
src/backend/commands/operatorcmds.c | 44 +++++++++++++--------------
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/tsearchcmds.c | 23 +++++++--------
src/backend/commands/typecmds.c | 48 +++++++++++++++---------------
src/backend/commands/view.c | 6 ++--
src/backend/parser/parse_clause.c | 2 +-
src/backend/snowball/dict_snowball.c | 4 +--
src/backend/tsearch/dict_ispell.c | 6 ++--
src/backend/tsearch/dict_simple.c | 4 +--
src/backend/tsearch/dict_synonym.c | 4 +--
src/backend/tsearch/dict_thesaurus.c | 4 +--
15 files changed, 109 insertions(+), 110 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index aa9c0f1bb9..c4a1d80790 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -865,7 +865,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
def->defnamespace)));
}
- if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
+ if (ignoreOids && strcmp(def->defname, "oids") == 0)
continue;
/* ignore if not in the same namespace */
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index adc9877e79..c107639009 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -127,37 +127,37 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
* sfunc1, stype1, and initcond1 are accepted as obsolete spellings
* for sfunc, stype, initcond.
*/
- if (pg_strcasecmp(defel->defname, "sfunc") == 0)
+ if (strcmp(defel->defname, "sfunc") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
+ else if (strcmp(defel->defname, "sfunc1") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
+ else if (strcmp(defel->defname, "finalfunc") == 0)
finalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "combinefunc") == 0)
+ else if (strcmp(defel->defname, "combinefunc") == 0)
combinefuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "serialfunc") == 0)
+ else if (strcmp(defel->defname, "serialfunc") == 0)
serialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "deserialfunc") == 0)
+ else if (strcmp(defel->defname, "deserialfunc") == 0)
deserialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "msfunc") == 0)
+ else if (strcmp(defel->defname, "msfunc") == 0)
mtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "minvfunc") == 0)
+ else if (strcmp(defel->defname, "minvfunc") == 0)
minvtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc") == 0)
mfinalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "finalfunc_extra") == 0)
finalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
mfinalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_modify") == 0)
+ else if (strcmp(defel->defname, "finalfunc_modify") == 0)
finalfuncModify = extractModify(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_modify") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
mfinalfuncModify = extractModify(defel);
- else if (pg_strcasecmp(defel->defname, "sortop") == 0)
+ else if (strcmp(defel->defname, "sortop") == 0)
sortoperatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "basetype") == 0)
+ else if (strcmp(defel->defname, "basetype") == 0)
baseType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "hypothetical") == 0)
+ else if (strcmp(defel->defname, "hypothetical") == 0)
{
if (defGetBoolean(defel))
{
@@ -168,21 +168,21 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
aggKind = AGGKIND_HYPOTHETICAL;
}
}
- else if (pg_strcasecmp(defel->defname, "stype") == 0)
+ else if (strcmp(defel->defname, "stype") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "stype1") == 0)
+ else if (strcmp(defel->defname, "stype1") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "sspace") == 0)
+ else if (strcmp(defel->defname, "sspace") == 0)
transSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "mstype") == 0)
+ else if (strcmp(defel->defname, "mstype") == 0)
mtransType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "msspace") == 0)
+ else if (strcmp(defel->defname, "msspace") == 0)
mtransSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "initcond") == 0)
+ else if (strcmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
+ else if (strcmp(defel->defname, "initcond1") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "minitcond") == 0)
+ else if (strcmp(defel->defname, "minitcond") == 0)
minitval = defGetString(defel);
else if (pg_strcasecmp(defel->defname, "parallel") == 0)
parallel = defGetString(defel);
@@ -420,11 +420,11 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
if (parallel)
{
- if (pg_strcasecmp(parallel, "safe") == 0)
+ if (strcmp(parallel, "safe") == 0)
proparallel = PROPARALLEL_SAFE;
- else if (pg_strcasecmp(parallel, "restricted") == 0)
+ else if (strcmp(parallel, "restricted") == 0)
proparallel = PROPARALLEL_RESTRICTED;
- else if (pg_strcasecmp(parallel, "unsafe") == 0)
+ else if (strcmp(parallel, "unsafe") == 0)
proparallel = PROPARALLEL_UNSAFE;
else
ereport(ERROR,
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index 9437731276..7ba21f54d7 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -82,17 +82,17 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
DefElem *defel = lfirst_node(DefElem, pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "from") == 0)
+ if (strcmp(defel->defname, "from") == 0)
defelp = &fromEl;
- else if (pg_strcasecmp(defel->defname, "locale") == 0)
+ else if (strcmp(defel->defname, "locale") == 0)
defelp = &localeEl;
- else if (pg_strcasecmp(defel->defname, "lc_collate") == 0)
+ else if (strcmp(defel->defname, "lc_collate") == 0)
defelp = &lccollateEl;
- else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0)
+ else if (strcmp(defel->defname, "lc_ctype") == 0)
defelp = &lcctypeEl;
- else if (pg_strcasecmp(defel->defname, "provider") == 0)
+ else if (strcmp(defel->defname, "provider") == 0)
defelp = &providerEl;
- else if (pg_strcasecmp(defel->defname, "version") == 0)
+ else if (strcmp(defel->defname, "version") == 0)
defelp = &versionEl;
else
{
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 7de844b2ca..113e0ae5e6 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -770,9 +770,9 @@ compute_attributes_with_style(ParseState *pstate, List *parameters, bool *isStri
{
DefElem *param = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(param->defname, "isstrict") == 0)
+ if (strcmp(param->defname, "isstrict") == 0)
*isStrict_p = defGetBoolean(param);
- else if (pg_strcasecmp(param->defname, "iscachable") == 0)
+ else if (strcmp(param->defname, "iscachable") == 0)
{
/* obsolete spelling of isImmutable */
if (defGetBoolean(param))
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 6674b41eec..7455644892 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -105,7 +105,7 @@ DefineOperator(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "leftarg") == 0)
+ if (strcmp(defel->defname, "leftarg") == 0)
{
typeName1 = defGetTypeName(defel);
if (typeName1->setof)
@@ -113,7 +113,7 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
+ else if (strcmp(defel->defname, "rightarg") == 0)
{
typeName2 = defGetTypeName(defel);
if (typeName2->setof)
@@ -121,28 +121,28 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "procedure") == 0)
+ else if (strcmp(defel->defname, "procedure") == 0)
functionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "commutator") == 0)
+ else if (strcmp(defel->defname, "commutator") == 0)
commutatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "negator") == 0)
+ else if (strcmp(defel->defname, "negator") == 0)
negatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ else if (strcmp(defel->defname, "restrict") == 0)
restrictionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
joinName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "hashes") == 0)
+ else if (strcmp(defel->defname, "hashes") == 0)
canHash = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "merges") == 0)
canMerge = defGetBoolean(defel);
/* These obsolete options are taken as meaning canMerge */
- else if (pg_strcasecmp(defel->defname, "sort1") == 0)
+ else if (strcmp(defel->defname, "sort1") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "sort2") == 0)
+ else if (strcmp(defel->defname, "sort2") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
+ else if (strcmp(defel->defname, "ltcmp") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
+ else if (strcmp(defel->defname, "gtcmp") == 0)
canMerge = true;
else
{
@@ -420,12 +420,12 @@ AlterOperator(AlterOperatorStmt *stmt)
else
param = defGetQualifiedName(defel);
- if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ if (strcmp(defel->defname, "restrict") == 0)
{
restrictionName = param;
updateRestriction = true;
}
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
{
joinName = param;
updateJoin = true;
@@ -435,13 +435,13 @@ AlterOperator(AlterOperatorStmt *stmt)
* The rest of the options that CREATE accepts cannot be changed.
* Check for them so that we can give a meaningful error message.
*/
- else if (pg_strcasecmp(defel->defname, "leftarg") == 0 ||
- pg_strcasecmp(defel->defname, "rightarg") == 0 ||
- pg_strcasecmp(defel->defname, "procedure") == 0 ||
- pg_strcasecmp(defel->defname, "commutator") == 0 ||
- pg_strcasecmp(defel->defname, "negator") == 0 ||
- pg_strcasecmp(defel->defname, "hashes") == 0 ||
- pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "leftarg") == 0 ||
+ strcmp(defel->defname, "rightarg") == 0 ||
+ strcmp(defel->defname, "procedure") == 0 ||
+ strcmp(defel->defname, "commutator") == 0 ||
+ strcmp(defel->defname, "negator") == 0 ||
+ strcmp(defel->defname, "hashes") == 0 ||
+ strcmp(defel->defname, "merges") == 0)
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d19846d005..55c20d16e7 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -10508,7 +10508,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index adc7cd67a7..c38a3d7783 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -209,27 +209,27 @@ DefineTSParser(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "start") == 0)
+ if (strcmp(defel->defname, "start") == 0)
{
values[Anum_pg_ts_parser_prsstart - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
}
- else if (pg_strcasecmp(defel->defname, "gettoken") == 0)
+ else if (strcmp(defel->defname, "gettoken") == 0)
{
values[Anum_pg_ts_parser_prstoken - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
}
- else if (pg_strcasecmp(defel->defname, "end") == 0)
+ else if (strcmp(defel->defname, "end") == 0)
{
values[Anum_pg_ts_parser_prsend - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
}
- else if (pg_strcasecmp(defel->defname, "headline") == 0)
+ else if (strcmp(defel->defname, "headline") == 0)
{
values[Anum_pg_ts_parser_prsheadline - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
}
- else if (pg_strcasecmp(defel->defname, "lextypes") == 0)
+ else if (strcmp(defel->defname, "lextypes") == 0)
{
values[Anum_pg_ts_parser_prslextype - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
@@ -438,7 +438,7 @@ DefineTSDictionary(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "template") == 0)
+ if (strcmp(defel->defname, "template") == 0)
{
templId = get_ts_template_oid(defGetQualifiedName(defel), false);
}
@@ -580,7 +580,7 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
DefElem *oldel = (DefElem *) lfirst(cell);
next = lnext(cell);
- if (pg_strcasecmp(oldel->defname, defel->defname) == 0)
+ if (strcmp(oldel->defname, defel->defname) == 0)
dictoptions = list_delete_cell(dictoptions, cell, prev);
else
prev = cell;
@@ -765,13 +765,13 @@ DefineTSTemplate(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "init") == 0)
+ if (strcmp(defel->defname, "init") == 0)
{
values[Anum_pg_ts_template_tmplinit - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
nulls[Anum_pg_ts_template_tmplinit - 1] = false;
}
- else if (pg_strcasecmp(defel->defname, "lexize") == 0)
+ else if (strcmp(defel->defname, "lexize") == 0)
{
values[Anum_pg_ts_template_tmpllexize - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
@@ -990,9 +990,9 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "parser") == 0)
+ if (strcmp(defel->defname, "parser") == 0)
prsOid = get_ts_parser_oid(defGetQualifiedName(defel), false);
- else if (pg_strcasecmp(defel->defname, "copy") == 0)
+ else if (strcmp(defel->defname, "copy") == 0)
sourceOid = get_ts_config_oid(defGetQualifiedName(defel), false);
else
ereport(ERROR,
@@ -1251,7 +1251,6 @@ getTokenTypes(Oid prsId, List *tokennames)
j = 0;
while (list && list[j].lexid)
{
- /* XXX should we use pg_strcasecmp here? */
if (strcmp(strVal(val), list[j].alias) == 0)
{
res[i] = list[j].lexid;
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index f86af4c054..56d5b4b4cc 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -245,42 +245,42 @@ DefineType(ParseState *pstate, List *names, List *parameters)
DefElem *defel = (DefElem *) lfirst(pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "like") == 0)
+ if (strcmp(defel->defname, "like") == 0)
defelp = &likeTypeEl;
- else if (pg_strcasecmp(defel->defname, "internallength") == 0)
+ else if (strcmp(defel->defname, "internallength") == 0)
defelp = &internalLengthEl;
- else if (pg_strcasecmp(defel->defname, "input") == 0)
+ else if (strcmp(defel->defname, "input") == 0)
defelp = &inputNameEl;
- else if (pg_strcasecmp(defel->defname, "output") == 0)
+ else if (strcmp(defel->defname, "output") == 0)
defelp = &outputNameEl;
- else if (pg_strcasecmp(defel->defname, "receive") == 0)
+ else if (strcmp(defel->defname, "receive") == 0)
defelp = &receiveNameEl;
- else if (pg_strcasecmp(defel->defname, "send") == 0)
+ else if (strcmp(defel->defname, "send") == 0)
defelp = &sendNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
+ else if (strcmp(defel->defname, "typmod_in") == 0)
defelp = &typmodinNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
+ else if (strcmp(defel->defname, "typmod_out") == 0)
defelp = &typmodoutNameEl;
- else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
- pg_strcasecmp(defel->defname, "analyse") == 0)
+ else if (strcmp(defel->defname, "analyze") == 0 ||
+ strcmp(defel->defname, "analyse") == 0)
defelp = &analyzeNameEl;
- else if (pg_strcasecmp(defel->defname, "category") == 0)
+ else if (strcmp(defel->defname, "category") == 0)
defelp = &categoryEl;
- else if (pg_strcasecmp(defel->defname, "preferred") == 0)
+ else if (strcmp(defel->defname, "preferred") == 0)
defelp = &preferredEl;
- else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
+ else if (strcmp(defel->defname, "delimiter") == 0)
defelp = &delimiterEl;
- else if (pg_strcasecmp(defel->defname, "element") == 0)
+ else if (strcmp(defel->defname, "element") == 0)
defelp = &elemTypeEl;
- else if (pg_strcasecmp(defel->defname, "default") == 0)
+ else if (strcmp(defel->defname, "default") == 0)
defelp = &defaultValueEl;
- else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
+ else if (strcmp(defel->defname, "passedbyvalue") == 0)
defelp = &byValueEl;
- else if (pg_strcasecmp(defel->defname, "alignment") == 0)
+ else if (strcmp(defel->defname, "alignment") == 0)
defelp = &alignmentEl;
- else if (pg_strcasecmp(defel->defname, "storage") == 0)
+ else if (strcmp(defel->defname, "storage") == 0)
defelp = &storageEl;
- else if (pg_strcasecmp(defel->defname, "collatable") == 0)
+ else if (strcmp(defel->defname, "collatable") == 0)
defelp = &collatableEl;
else
{
@@ -1439,7 +1439,7 @@ DefineRange(CreateRangeStmt *stmt)
{
DefElem *defel = (DefElem *) lfirst(lc);
- if (pg_strcasecmp(defel->defname, "subtype") == 0)
+ if (strcmp(defel->defname, "subtype") == 0)
{
if (OidIsValid(rangeSubtype))
ereport(ERROR,
@@ -1448,7 +1448,7 @@ DefineRange(CreateRangeStmt *stmt)
/* we can look up the subtype name immediately */
rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
}
- else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
+ else if (strcmp(defel->defname, "subtype_opclass") == 0)
{
if (rangeSubOpclassName != NIL)
ereport(ERROR,
@@ -1456,7 +1456,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeSubOpclassName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "collation") == 0)
+ else if (strcmp(defel->defname, "collation") == 0)
{
if (rangeCollationName != NIL)
ereport(ERROR,
@@ -1464,7 +1464,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCollationName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "canonical") == 0)
+ else if (strcmp(defel->defname, "canonical") == 0)
{
if (rangeCanonicalName != NIL)
ereport(ERROR,
@@ -1472,7 +1472,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCanonicalName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
+ else if (strcmp(defel->defname, "subtype_diff") == 0)
{
if (rangeSubtypeDiffName != NIL)
ereport(ERROR,
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index c1e80e61d4..4ac7172754 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -46,8 +46,8 @@ void
validateWithCheckOption(const char *value)
{
if (value == NULL ||
- (pg_strcasecmp(value, "local") != 0 &&
- pg_strcasecmp(value, "cascaded") != 0))
+ (strcmp(value, "local") != 0 &&
+ strcmp(value, "cascaded") != 0))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -485,7 +485,7 @@ DefineView(ViewStmt *stmt, const char *queryString,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 2828bbf796..77f330579a 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -262,7 +262,7 @@ interpretOidsOption(List *defList, bool allowOids)
DefElem *def = (DefElem *) lfirst(cell);
if (def->defnamespace == NULL &&
- pg_strcasecmp(def->defname, "oids") == 0)
+ strcmp(def->defname, "oids") == 0)
{
if (!allowOids)
ereport(ERROR,
diff --git a/src/backend/snowball/dict_snowball.c b/src/backend/snowball/dict_snowball.c
index 42384b42b1..6e9f65fc38 100644
--- a/src/backend/snowball/dict_snowball.c
+++ b/src/backend/snowball/dict_snowball.c
@@ -192,7 +192,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -201,7 +201,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Language", defel->defname) == 0)
+ else if (strcmp(defel->defname, "language") == 0)
{
if (d->stem)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_ispell.c b/src/backend/tsearch/dict_ispell.c
index 8f61bd2830..8989cb2e84 100644
--- a/src/backend/tsearch/dict_ispell.c
+++ b/src/backend/tsearch/dict_ispell.c
@@ -44,7 +44,7 @@ dispell_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "DictFile") == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (dictloaded)
ereport(ERROR,
@@ -55,7 +55,7 @@ dispell_init(PG_FUNCTION_ARGS)
"dict"));
dictloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "AffFile") == 0)
+ else if (strcmp(defel->defname, "afffile") == 0)
{
if (affloaded)
ereport(ERROR,
@@ -66,7 +66,7 @@ dispell_init(PG_FUNCTION_ARGS)
"affix"));
affloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "StopWords") == 0)
+ else if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_simple.c b/src/backend/tsearch/dict_simple.c
index a13cdc0743..21480defa9 100644
--- a/src/backend/tsearch/dict_simple.c
+++ b/src/backend/tsearch/dict_simple.c
@@ -41,7 +41,7 @@ dsimple_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -50,7 +50,7 @@ dsimple_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Accept", defel->defname) == 0)
+ else if (strcmp(defel->defname, "accept") == 0)
{
if (acceptloaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_synonym.c b/src/backend/tsearch/dict_synonym.c
index e67d2e6e04..73c4a0bb7e 100644
--- a/src/backend/tsearch/dict_synonym.c
+++ b/src/backend/tsearch/dict_synonym.c
@@ -108,9 +108,9 @@ dsynonym_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("Synonyms", defel->defname) == 0)
+ if (strcmp(defel->defname, "synonyms") == 0)
filename = defGetString(defel);
- else if (pg_strcasecmp("CaseSensitive", defel->defname) == 0)
+ else if (strcmp(defel->defname, "casesensitive") == 0)
case_sensitive = defGetBoolean(defel);
else
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_thesaurus.c b/src/backend/tsearch/dict_thesaurus.c
index 2a458db691..7197e0429e 100644
--- a/src/backend/tsearch/dict_thesaurus.c
+++ b/src/backend/tsearch/dict_thesaurus.c
@@ -616,7 +616,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("DictFile", defel->defname) == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (fileloaded)
ereport(ERROR,
@@ -625,7 +625,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
thesaurusRead(defGetString(defel), d);
fileloaded = true;
}
- else if (pg_strcasecmp("Dictionary", defel->defname) == 0)
+ else if (strcmp(defel->defname, "dictionary") == 0)
{
if (subdictname)
ereport(ERROR,
--
2.14.1.145.gb3622a4ee
On Tue, Nov 28, 2017 at 12:11 AM, Daniel Gustafsson <daniel@yesql.se> wrote:
The patch needs a rebase, and there are a couple of places that need
an extra lookup I think:
$ git grep defname -- *.c | grep strcasecmp | wc -l
39Rebased and handled a few more places which I had either missed in the last
round, or that had been added in the meantime. “PARALLEL” in aggregatecmds.c
is intentionally using pg_strcasecmp() due to the old-style syntax which is
still supported.
This meritates a comment. Code readers may get confused.
AFAICS this covers all relevant codepaths from the 39 above.
I was just looking at the tsearch code which uses pg_strcmpcase, and
those are defined with makeDefElem() so you should switch to strcmp in
this case as well, no? If I patch the code myself I would get an error
when double-quoting, making those command more consistent with the
rest of what you are patching here:
create extension unaccent;
alter text search dictionary unaccent (Rules = 'unaccent'); -- ok
alter text search dictionary unaccent (RuLes = 'unaccent'); -- ok
alter text search dictionary unaccent ("Rules" = 'unaccent'); -- error
--
Michael
On Tue, Nov 28, 2017 at 10:07 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:
I was just looking at the tsearch code which uses pg_strcmpcase, and
those are defined with makeDefElem() so you should switch to strcmp in
this case as well, no? If I patch the code myself I would get an error
when double-quoting, making those command more consistent with the
rest of what you are patching here:
create extension unaccent;
alter text search dictionary unaccent (Rules = 'unaccent'); -- ok
alter text search dictionary unaccent (RuLes = 'unaccent'); -- ok
alter text search dictionary unaccent ("Rules" = 'unaccent'); -- error
Daniel, I am waiting for your input on this one, and you did not have
much time to send an update. So I am moving this patch to next CF.
--
Michael
On 29 Nov 2017, at 04:29, Michael Paquier <michael.paquier@gmail.com> wrote:
On Tue, Nov 28, 2017 at 10:07 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:I was just looking at the tsearch code which uses pg_strcmpcase, and
those are defined with makeDefElem() so you should switch to strcmp in
this case as well, no? If I patch the code myself I would get an error
when double-quoting, making those command more consistent with the
rest of what you are patching here:
create extension unaccent;
alter text search dictionary unaccent (Rules = 'unaccent'); -- ok
alter text search dictionary unaccent (RuLes = 'unaccent'); -- ok
alter text search dictionary unaccent ("Rules" = 'unaccent'); -- errorDaniel, I am waiting for your input on this one, and you did not have
much time to send an update.
Sorry for the slow updates, I managed to catch a nasty fever which turned my
brain closer to a mushroom soup than I’d like.
So I am moving this patch to next CF.
Good move, thanks!
cheers ./daniel
On Thu, Nov 30, 2017 at 7:40 AM, Daniel Gustafsson <daniel@yesql.se> wrote:
On 29 Nov 2017, at 04:29, Michael Paquier <michael.paquier@gmail.com> wrote:
On Tue, Nov 28, 2017 at 10:07 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:I was just looking at the tsearch code which uses pg_strcmpcase, and
those are defined with makeDefElem() so you should switch to strcmp in
this case as well, no? If I patch the code myself I would get an error
when double-quoting, making those command more consistent with the
rest of what you are patching here:
create extension unaccent;
alter text search dictionary unaccent (Rules = 'unaccent'); -- ok
alter text search dictionary unaccent (RuLes = 'unaccent'); -- ok
alter text search dictionary unaccent ("Rules" = 'unaccent'); -- errorDaniel, I am waiting for your input on this one, and you did not have
much time to send an update.Sorry for the slow updates, I managed to catch a nasty fever which turned my
brain closer to a mushroom soup than I’d like.
No problems. Take care.
--
Michael
On 28 Nov 2017, at 02:07, Michael Paquier <michael.paquier@gmail.com> wrote:
On Tue, Nov 28, 2017 at 12:11 AM, Daniel Gustafsson <daniel@yesql.se> wrote:
The patch needs a rebase, and there are a couple of places that need
an extra lookup I think:
$ git grep defname -- *.c | grep strcasecmp | wc -l
39Rebased and handled a few more places which I had either missed in the last
round, or that had been added in the meantime. “PARALLEL” in aggregatecmds.c
is intentionally using pg_strcasecmp() due to the old-style syntax which is
still supported.This meritates a comment. Code readers may get confused.
Good point, added. I also sent a separate doc patch for this to -docs the
other day.
AFAICS this covers all relevant codepaths from the 39 above.
I was just looking at the tsearch code which uses pg_strcmpcase, and
those are defined with makeDefElem() so you should switch to strcmp in
this case as well, no? If I patch the code myself I would get an error
when double-quoting, making those command more consistent with the
rest of what you are patching here:
create extension unaccent;
alter text search dictionary unaccent (Rules = 'unaccent'); -- ok
alter text search dictionary unaccent (RuLes = 'unaccent'); -- ok
alter text search dictionary unaccent ("Rules" = 'unaccent'); — error
For reasons unknown to me I had avoided poking in contrib/. Attached patch
handles the additional defname comparisons in contrib that are applicable.
The remainder of the pg_strcasecmp() calls in the text search code are
operating on a defelem list created in deserialize_deflist() rather than in the
parser, so I opted for keeping that as is rather than casefolding in the list
generation.
cheers ./daniel
Attachments:
defname_strcmp-v3.patchapplication/octet-stream; name=defname_strcmp-v3.patchDownload
From 5e11d97511842f5f9d1d5e8c19a836749480a0dd Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <daniel@yesql.se>
Date: Thu, 30 Nov 2017 12:19:07 +0100
Subject: [PATCH 1/2] Use strcmp() instead of pg_strcasecmp() for identifier
matching
Since these option values are parsed using either the IDENT rule,
via keyword rules, or are created in lowercase with makeString(),
using strcmp() is the correct approach here. While not wrong per
se, using case insensitive matching can hide subtle bugs in case
defnames are created with mixed-case as these options otherwise
are assumed to always be lowercased.
Reorder a few checks while in there such that all checks are in
the same order to make it easier to grep/read.
Also remove comment in tsearchcmds.c:getTokenTypes() regarding
strcmp/pg_strcasecmp as the code is correct. token_type is parsed
using the IDENT rule and will always be in lowercase.
---
contrib/dict_int/dict_int.c | 4 +--
contrib/dict_xsyn/dict_xsyn.c | 10 +++---
contrib/unaccent/unaccent.c | 2 +-
src/backend/access/common/reloptions.c | 2 +-
src/backend/commands/aggregatecmds.c | 59 ++++++++++++++++++----------------
src/backend/commands/collationcmds.c | 12 +++----
src/backend/commands/functioncmds.c | 4 +--
src/backend/commands/operatorcmds.c | 44 ++++++++++++-------------
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/tsearchcmds.c | 23 +++++++------
src/backend/commands/typecmds.c | 48 +++++++++++++--------------
src/backend/commands/view.c | 6 ++--
src/backend/parser/parse_clause.c | 2 +-
src/backend/snowball/dict_snowball.c | 4 +--
src/backend/tsearch/dict_ispell.c | 6 ++--
src/backend/tsearch/dict_simple.c | 4 +--
src/backend/tsearch/dict_synonym.c | 4 +--
src/backend/tsearch/dict_thesaurus.c | 4 +--
18 files changed, 122 insertions(+), 118 deletions(-)
diff --git a/contrib/dict_int/dict_int.c b/contrib/dict_int/dict_int.c
index 55427c4bc7..9b42caecad 100644
--- a/contrib/dict_int/dict_int.c
+++ b/contrib/dict_int/dict_int.c
@@ -42,11 +42,11 @@ dintdict_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "MAXLEN") == 0)
+ if (strcmp(defel->defname, "maxlen") == 0)
{
d->maxlen = atoi(defGetString(defel));
}
- else if (pg_strcasecmp(defel->defname, "REJECTLONG") == 0)
+ else if (strcmp(defel->defname, "rejectlong") == 0)
{
d->rejectlong = defGetBoolean(defel);
}
diff --git a/contrib/dict_xsyn/dict_xsyn.c b/contrib/dict_xsyn/dict_xsyn.c
index 977162951a..a1cd02bc74 100644
--- a/contrib/dict_xsyn/dict_xsyn.c
+++ b/contrib/dict_xsyn/dict_xsyn.c
@@ -157,23 +157,23 @@ dxsyn_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "MATCHORIG") == 0)
+ if (strcmp(defel->defname, "matchorig") == 0)
{
d->matchorig = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "KEEPORIG") == 0)
+ else if (strcmp(defel->defname, "keeporig") == 0)
{
d->keeporig = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "MATCHSYNONYMS") == 0)
+ else if (strcmp(defel->defname, "matchsynonyms") == 0)
{
d->matchsynonyms = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "KEEPSYNONYMS") == 0)
+ else if (strcmp(defel->defname, "keepsynonyms") == 0)
{
d->keepsynonyms = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "RULES") == 0)
+ else if (strcmp(defel->defname, "rules") == 0)
{
/* we can't read the rules before parsing all options! */
filename = defGetString(defel);
diff --git a/contrib/unaccent/unaccent.c b/contrib/unaccent/unaccent.c
index e68b098b78..805e94d613 100644
--- a/contrib/unaccent/unaccent.c
+++ b/contrib/unaccent/unaccent.c
@@ -276,7 +276,7 @@ unaccent_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("Rules", defel->defname) == 0)
+ if (strcmp(defel->defname, "rules") == 0)
{
if (fileloaded)
ereport(ERROR,
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index aa9c0f1bb9..c4a1d80790 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -865,7 +865,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
def->defnamespace)));
}
- if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
+ if (ignoreOids && strcmp(def->defname, "oids") == 0)
continue;
/* ignore if not in the same namespace */
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index adc9877e79..14bc4cd853 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -127,37 +127,37 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
* sfunc1, stype1, and initcond1 are accepted as obsolete spellings
* for sfunc, stype, initcond.
*/
- if (pg_strcasecmp(defel->defname, "sfunc") == 0)
+ if (strcmp(defel->defname, "sfunc") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
+ else if (strcmp(defel->defname, "sfunc1") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
+ else if (strcmp(defel->defname, "finalfunc") == 0)
finalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "combinefunc") == 0)
+ else if (strcmp(defel->defname, "combinefunc") == 0)
combinefuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "serialfunc") == 0)
+ else if (strcmp(defel->defname, "serialfunc") == 0)
serialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "deserialfunc") == 0)
+ else if (strcmp(defel->defname, "deserialfunc") == 0)
deserialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "msfunc") == 0)
+ else if (strcmp(defel->defname, "msfunc") == 0)
mtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "minvfunc") == 0)
+ else if (strcmp(defel->defname, "minvfunc") == 0)
minvtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc") == 0)
mfinalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "finalfunc_extra") == 0)
finalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
mfinalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_modify") == 0)
+ else if (strcmp(defel->defname, "finalfunc_modify") == 0)
finalfuncModify = extractModify(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_modify") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
mfinalfuncModify = extractModify(defel);
- else if (pg_strcasecmp(defel->defname, "sortop") == 0)
+ else if (strcmp(defel->defname, "sortop") == 0)
sortoperatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "basetype") == 0)
+ else if (strcmp(defel->defname, "basetype") == 0)
baseType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "hypothetical") == 0)
+ else if (strcmp(defel->defname, "hypothetical") == 0)
{
if (defGetBoolean(defel))
{
@@ -168,22 +168,27 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
aggKind = AGGKIND_HYPOTHETICAL;
}
}
- else if (pg_strcasecmp(defel->defname, "stype") == 0)
+ else if (strcmp(defel->defname, "stype") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "stype1") == 0)
+ else if (strcmp(defel->defname, "stype1") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "sspace") == 0)
+ else if (strcmp(defel->defname, "sspace") == 0)
transSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "mstype") == 0)
+ else if (strcmp(defel->defname, "mstype") == 0)
mtransType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "msspace") == 0)
+ else if (strcmp(defel->defname, "msspace") == 0)
mtransSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "initcond") == 0)
+ else if (strcmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
+ else if (strcmp(defel->defname, "initcond1") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "minitcond") == 0)
+ else if (strcmp(defel->defname, "minitcond") == 0)
minitval = defGetString(defel);
+ /*
+ * Opposed to the other defelements, 'parallel' must use case
+ * insensitive matching due to the old style CREATE AGGREGATE syntax
+ * which is still supported.
+ */
else if (pg_strcasecmp(defel->defname, "parallel") == 0)
parallel = defGetString(defel);
else
@@ -420,11 +425,11 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
if (parallel)
{
- if (pg_strcasecmp(parallel, "safe") == 0)
+ if (strcmp(parallel, "safe") == 0)
proparallel = PROPARALLEL_SAFE;
- else if (pg_strcasecmp(parallel, "restricted") == 0)
+ else if (strcmp(parallel, "restricted") == 0)
proparallel = PROPARALLEL_RESTRICTED;
- else if (pg_strcasecmp(parallel, "unsafe") == 0)
+ else if (strcmp(parallel, "unsafe") == 0)
proparallel = PROPARALLEL_UNSAFE;
else
ereport(ERROR,
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index 9437731276..7ba21f54d7 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -82,17 +82,17 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
DefElem *defel = lfirst_node(DefElem, pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "from") == 0)
+ if (strcmp(defel->defname, "from") == 0)
defelp = &fromEl;
- else if (pg_strcasecmp(defel->defname, "locale") == 0)
+ else if (strcmp(defel->defname, "locale") == 0)
defelp = &localeEl;
- else if (pg_strcasecmp(defel->defname, "lc_collate") == 0)
+ else if (strcmp(defel->defname, "lc_collate") == 0)
defelp = &lccollateEl;
- else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0)
+ else if (strcmp(defel->defname, "lc_ctype") == 0)
defelp = &lcctypeEl;
- else if (pg_strcasecmp(defel->defname, "provider") == 0)
+ else if (strcmp(defel->defname, "provider") == 0)
defelp = &providerEl;
- else if (pg_strcasecmp(defel->defname, "version") == 0)
+ else if (strcmp(defel->defname, "version") == 0)
defelp = &versionEl;
else
{
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 7de844b2ca..113e0ae5e6 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -770,9 +770,9 @@ compute_attributes_with_style(ParseState *pstate, List *parameters, bool *isStri
{
DefElem *param = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(param->defname, "isstrict") == 0)
+ if (strcmp(param->defname, "isstrict") == 0)
*isStrict_p = defGetBoolean(param);
- else if (pg_strcasecmp(param->defname, "iscachable") == 0)
+ else if (strcmp(param->defname, "iscachable") == 0)
{
/* obsolete spelling of isImmutable */
if (defGetBoolean(param))
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 6674b41eec..7455644892 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -105,7 +105,7 @@ DefineOperator(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "leftarg") == 0)
+ if (strcmp(defel->defname, "leftarg") == 0)
{
typeName1 = defGetTypeName(defel);
if (typeName1->setof)
@@ -113,7 +113,7 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
+ else if (strcmp(defel->defname, "rightarg") == 0)
{
typeName2 = defGetTypeName(defel);
if (typeName2->setof)
@@ -121,28 +121,28 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "procedure") == 0)
+ else if (strcmp(defel->defname, "procedure") == 0)
functionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "commutator") == 0)
+ else if (strcmp(defel->defname, "commutator") == 0)
commutatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "negator") == 0)
+ else if (strcmp(defel->defname, "negator") == 0)
negatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ else if (strcmp(defel->defname, "restrict") == 0)
restrictionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
joinName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "hashes") == 0)
+ else if (strcmp(defel->defname, "hashes") == 0)
canHash = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "merges") == 0)
canMerge = defGetBoolean(defel);
/* These obsolete options are taken as meaning canMerge */
- else if (pg_strcasecmp(defel->defname, "sort1") == 0)
+ else if (strcmp(defel->defname, "sort1") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "sort2") == 0)
+ else if (strcmp(defel->defname, "sort2") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
+ else if (strcmp(defel->defname, "ltcmp") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
+ else if (strcmp(defel->defname, "gtcmp") == 0)
canMerge = true;
else
{
@@ -420,12 +420,12 @@ AlterOperator(AlterOperatorStmt *stmt)
else
param = defGetQualifiedName(defel);
- if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ if (strcmp(defel->defname, "restrict") == 0)
{
restrictionName = param;
updateRestriction = true;
}
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
{
joinName = param;
updateJoin = true;
@@ -435,13 +435,13 @@ AlterOperator(AlterOperatorStmt *stmt)
* The rest of the options that CREATE accepts cannot be changed.
* Check for them so that we can give a meaningful error message.
*/
- else if (pg_strcasecmp(defel->defname, "leftarg") == 0 ||
- pg_strcasecmp(defel->defname, "rightarg") == 0 ||
- pg_strcasecmp(defel->defname, "procedure") == 0 ||
- pg_strcasecmp(defel->defname, "commutator") == 0 ||
- pg_strcasecmp(defel->defname, "negator") == 0 ||
- pg_strcasecmp(defel->defname, "hashes") == 0 ||
- pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "leftarg") == 0 ||
+ strcmp(defel->defname, "rightarg") == 0 ||
+ strcmp(defel->defname, "procedure") == 0 ||
+ strcmp(defel->defname, "commutator") == 0 ||
+ strcmp(defel->defname, "negator") == 0 ||
+ strcmp(defel->defname, "hashes") == 0 ||
+ strcmp(defel->defname, "merges") == 0)
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d979ce266d..f32c6c5c70 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -10508,7 +10508,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index adc7cd67a7..c38a3d7783 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -209,27 +209,27 @@ DefineTSParser(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "start") == 0)
+ if (strcmp(defel->defname, "start") == 0)
{
values[Anum_pg_ts_parser_prsstart - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
}
- else if (pg_strcasecmp(defel->defname, "gettoken") == 0)
+ else if (strcmp(defel->defname, "gettoken") == 0)
{
values[Anum_pg_ts_parser_prstoken - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
}
- else if (pg_strcasecmp(defel->defname, "end") == 0)
+ else if (strcmp(defel->defname, "end") == 0)
{
values[Anum_pg_ts_parser_prsend - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
}
- else if (pg_strcasecmp(defel->defname, "headline") == 0)
+ else if (strcmp(defel->defname, "headline") == 0)
{
values[Anum_pg_ts_parser_prsheadline - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
}
- else if (pg_strcasecmp(defel->defname, "lextypes") == 0)
+ else if (strcmp(defel->defname, "lextypes") == 0)
{
values[Anum_pg_ts_parser_prslextype - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
@@ -438,7 +438,7 @@ DefineTSDictionary(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "template") == 0)
+ if (strcmp(defel->defname, "template") == 0)
{
templId = get_ts_template_oid(defGetQualifiedName(defel), false);
}
@@ -580,7 +580,7 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
DefElem *oldel = (DefElem *) lfirst(cell);
next = lnext(cell);
- if (pg_strcasecmp(oldel->defname, defel->defname) == 0)
+ if (strcmp(oldel->defname, defel->defname) == 0)
dictoptions = list_delete_cell(dictoptions, cell, prev);
else
prev = cell;
@@ -765,13 +765,13 @@ DefineTSTemplate(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "init") == 0)
+ if (strcmp(defel->defname, "init") == 0)
{
values[Anum_pg_ts_template_tmplinit - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
nulls[Anum_pg_ts_template_tmplinit - 1] = false;
}
- else if (pg_strcasecmp(defel->defname, "lexize") == 0)
+ else if (strcmp(defel->defname, "lexize") == 0)
{
values[Anum_pg_ts_template_tmpllexize - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
@@ -990,9 +990,9 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "parser") == 0)
+ if (strcmp(defel->defname, "parser") == 0)
prsOid = get_ts_parser_oid(defGetQualifiedName(defel), false);
- else if (pg_strcasecmp(defel->defname, "copy") == 0)
+ else if (strcmp(defel->defname, "copy") == 0)
sourceOid = get_ts_config_oid(defGetQualifiedName(defel), false);
else
ereport(ERROR,
@@ -1251,7 +1251,6 @@ getTokenTypes(Oid prsId, List *tokennames)
j = 0;
while (list && list[j].lexid)
{
- /* XXX should we use pg_strcasecmp here? */
if (strcmp(strVal(val), list[j].alias) == 0)
{
res[i] = list[j].lexid;
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index f86af4c054..56d5b4b4cc 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -245,42 +245,42 @@ DefineType(ParseState *pstate, List *names, List *parameters)
DefElem *defel = (DefElem *) lfirst(pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "like") == 0)
+ if (strcmp(defel->defname, "like") == 0)
defelp = &likeTypeEl;
- else if (pg_strcasecmp(defel->defname, "internallength") == 0)
+ else if (strcmp(defel->defname, "internallength") == 0)
defelp = &internalLengthEl;
- else if (pg_strcasecmp(defel->defname, "input") == 0)
+ else if (strcmp(defel->defname, "input") == 0)
defelp = &inputNameEl;
- else if (pg_strcasecmp(defel->defname, "output") == 0)
+ else if (strcmp(defel->defname, "output") == 0)
defelp = &outputNameEl;
- else if (pg_strcasecmp(defel->defname, "receive") == 0)
+ else if (strcmp(defel->defname, "receive") == 0)
defelp = &receiveNameEl;
- else if (pg_strcasecmp(defel->defname, "send") == 0)
+ else if (strcmp(defel->defname, "send") == 0)
defelp = &sendNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
+ else if (strcmp(defel->defname, "typmod_in") == 0)
defelp = &typmodinNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
+ else if (strcmp(defel->defname, "typmod_out") == 0)
defelp = &typmodoutNameEl;
- else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
- pg_strcasecmp(defel->defname, "analyse") == 0)
+ else if (strcmp(defel->defname, "analyze") == 0 ||
+ strcmp(defel->defname, "analyse") == 0)
defelp = &analyzeNameEl;
- else if (pg_strcasecmp(defel->defname, "category") == 0)
+ else if (strcmp(defel->defname, "category") == 0)
defelp = &categoryEl;
- else if (pg_strcasecmp(defel->defname, "preferred") == 0)
+ else if (strcmp(defel->defname, "preferred") == 0)
defelp = &preferredEl;
- else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
+ else if (strcmp(defel->defname, "delimiter") == 0)
defelp = &delimiterEl;
- else if (pg_strcasecmp(defel->defname, "element") == 0)
+ else if (strcmp(defel->defname, "element") == 0)
defelp = &elemTypeEl;
- else if (pg_strcasecmp(defel->defname, "default") == 0)
+ else if (strcmp(defel->defname, "default") == 0)
defelp = &defaultValueEl;
- else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
+ else if (strcmp(defel->defname, "passedbyvalue") == 0)
defelp = &byValueEl;
- else if (pg_strcasecmp(defel->defname, "alignment") == 0)
+ else if (strcmp(defel->defname, "alignment") == 0)
defelp = &alignmentEl;
- else if (pg_strcasecmp(defel->defname, "storage") == 0)
+ else if (strcmp(defel->defname, "storage") == 0)
defelp = &storageEl;
- else if (pg_strcasecmp(defel->defname, "collatable") == 0)
+ else if (strcmp(defel->defname, "collatable") == 0)
defelp = &collatableEl;
else
{
@@ -1439,7 +1439,7 @@ DefineRange(CreateRangeStmt *stmt)
{
DefElem *defel = (DefElem *) lfirst(lc);
- if (pg_strcasecmp(defel->defname, "subtype") == 0)
+ if (strcmp(defel->defname, "subtype") == 0)
{
if (OidIsValid(rangeSubtype))
ereport(ERROR,
@@ -1448,7 +1448,7 @@ DefineRange(CreateRangeStmt *stmt)
/* we can look up the subtype name immediately */
rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
}
- else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
+ else if (strcmp(defel->defname, "subtype_opclass") == 0)
{
if (rangeSubOpclassName != NIL)
ereport(ERROR,
@@ -1456,7 +1456,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeSubOpclassName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "collation") == 0)
+ else if (strcmp(defel->defname, "collation") == 0)
{
if (rangeCollationName != NIL)
ereport(ERROR,
@@ -1464,7 +1464,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCollationName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "canonical") == 0)
+ else if (strcmp(defel->defname, "canonical") == 0)
{
if (rangeCanonicalName != NIL)
ereport(ERROR,
@@ -1472,7 +1472,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCanonicalName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
+ else if (strcmp(defel->defname, "subtype_diff") == 0)
{
if (rangeSubtypeDiffName != NIL)
ereport(ERROR,
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index c1e80e61d4..4ac7172754 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -46,8 +46,8 @@ void
validateWithCheckOption(const char *value)
{
if (value == NULL ||
- (pg_strcasecmp(value, "local") != 0 &&
- pg_strcasecmp(value, "cascaded") != 0))
+ (strcmp(value, "local") != 0 &&
+ strcmp(value, "cascaded") != 0))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -485,7 +485,7 @@ DefineView(ViewStmt *stmt, const char *queryString,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 2828bbf796..77f330579a 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -262,7 +262,7 @@ interpretOidsOption(List *defList, bool allowOids)
DefElem *def = (DefElem *) lfirst(cell);
if (def->defnamespace == NULL &&
- pg_strcasecmp(def->defname, "oids") == 0)
+ strcmp(def->defname, "oids") == 0)
{
if (!allowOids)
ereport(ERROR,
diff --git a/src/backend/snowball/dict_snowball.c b/src/backend/snowball/dict_snowball.c
index 42384b42b1..6e9f65fc38 100644
--- a/src/backend/snowball/dict_snowball.c
+++ b/src/backend/snowball/dict_snowball.c
@@ -192,7 +192,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -201,7 +201,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Language", defel->defname) == 0)
+ else if (strcmp(defel->defname, "language") == 0)
{
if (d->stem)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_ispell.c b/src/backend/tsearch/dict_ispell.c
index 8f61bd2830..8989cb2e84 100644
--- a/src/backend/tsearch/dict_ispell.c
+++ b/src/backend/tsearch/dict_ispell.c
@@ -44,7 +44,7 @@ dispell_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "DictFile") == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (dictloaded)
ereport(ERROR,
@@ -55,7 +55,7 @@ dispell_init(PG_FUNCTION_ARGS)
"dict"));
dictloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "AffFile") == 0)
+ else if (strcmp(defel->defname, "afffile") == 0)
{
if (affloaded)
ereport(ERROR,
@@ -66,7 +66,7 @@ dispell_init(PG_FUNCTION_ARGS)
"affix"));
affloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "StopWords") == 0)
+ else if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_simple.c b/src/backend/tsearch/dict_simple.c
index a13cdc0743..21480defa9 100644
--- a/src/backend/tsearch/dict_simple.c
+++ b/src/backend/tsearch/dict_simple.c
@@ -41,7 +41,7 @@ dsimple_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -50,7 +50,7 @@ dsimple_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Accept", defel->defname) == 0)
+ else if (strcmp(defel->defname, "accept") == 0)
{
if (acceptloaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_synonym.c b/src/backend/tsearch/dict_synonym.c
index e67d2e6e04..73c4a0bb7e 100644
--- a/src/backend/tsearch/dict_synonym.c
+++ b/src/backend/tsearch/dict_synonym.c
@@ -108,9 +108,9 @@ dsynonym_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("Synonyms", defel->defname) == 0)
+ if (strcmp(defel->defname, "synonyms") == 0)
filename = defGetString(defel);
- else if (pg_strcasecmp("CaseSensitive", defel->defname) == 0)
+ else if (strcmp(defel->defname, "casesensitive") == 0)
case_sensitive = defGetBoolean(defel);
else
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_thesaurus.c b/src/backend/tsearch/dict_thesaurus.c
index 2a458db691..7197e0429e 100644
--- a/src/backend/tsearch/dict_thesaurus.c
+++ b/src/backend/tsearch/dict_thesaurus.c
@@ -616,7 +616,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("DictFile", defel->defname) == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (fileloaded)
ereport(ERROR,
@@ -625,7 +625,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
thesaurusRead(defGetString(defel), d);
fileloaded = true;
}
- else if (pg_strcasecmp("Dictionary", defel->defname) == 0)
+ else if (strcmp(defel->defname, "dictionary") == 0)
{
if (subdictname)
ereport(ERROR,
--
2.14.1.145.gb3622a4ee
On Thu, Nov 30, 2017 at 6:40 AM, Daniel Gustafsson <daniel@yesql.se> wrote:
For reasons unknown to me I had avoided poking in contrib/. Attached patch
handles the additional defname comparisons in contrib that are applicable.
I am having a bit of trouble understanding why the first hunk in
DefineAggregate() is taking PARALLEL as a special case. The
documentation gives three separate synopses for CREATE AGGREGATE, but
parallel appears in all of them, and there are other options that do
too, so the comment doesn't really help me understand why it's special
as compared to other, similar options.
I think the changes in DefineView and ATExecSetRelOptions is wrong,
because transformRelOptions() is still using pg_strcasecmp. With the
patch:
rhaas=# create view v(x) with ("Check_option"="local") as select 1;
CREATE VIEW
rhaas=# create view v(x) with ("check_option"="local") as select 1;
ERROR: WITH CHECK OPTION is supported only on automatically updatable views
HINT: Views that do not select from a single table or view are not
automatically updatable.
Oops.
Here are, for the record, examples of SQL that will be generate errors
or warnings with the patch, but not presently, with a note about which
function got changed at the C level to affect the behavior.
transformRelOptions/interpretOidsOption: create table a () with ("OiDs"=true);
DefineAggregate, second hunk: CREATE AGGREGATE avg (float8) (sfunc =
float8_accum, stype = float8[], finalfunc = float8_avg, initcond =
'{0,0,0}', parallel = 'sAfe');
DefineCollation: CREATE COLLATION stunk ("LoCaLeS" = "C");
compute_attributes_with_style: create function one() returns int as
$$select 1$$ language sql with ("isStrict" = 'true');
DefineOperator: create operator @ (procedure = pg_catalog.int4eq,
leftarg = int4, "RIGHTARG" = int4);
DefineType: create type awesome (input = int4in, "OuTpUt" = int4out);
validateWithCheckOption: create table t(a int, b text, unique(a));
create view x with (check_option = 'loCal') as select * from t;
I have not yet managed to figure out what the impact of the contrib
changes, or the text search changes in core, is. This is partly a
lack of subject matter expertise, but the fact that the functions
being modified in contrib have a grand total of 0 lines of comments
between them does not help. That's not this patch's fault, nor this
patch's job to fix, but it is a barrier to understanding. I think it
would be nice to have a complete list of examples of what syntax this
patch is affecting.
I am actually pretty dubious that we want to do this. I found one bug
already (see above), and I don't think there's any guarantee that it's
the only one, because it's pretty hard to be sure that none of the
remaining calls to pg_strcasecmp are being applied to any of these
values in some other part of the code. I'm not sure that the backward
compatibility issue is a huge deal, but from my point of view this
carries a significant risk of introducing new bugs, might annoy users
who spell any of these keywords in all caps with surrounding quotation
marks, and really has no clear benefit that I can see. The
originally-offered justification is that making this consistent would
help us avoid subtle bugs, but it seems at least as likely to CREATE
subtle bugs, and the status quo is AFAICT harming nobody.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Fri, Dec 1, 2017 at 4:14 AM, Robert Haas <robertmhaas@gmail.com> wrote:
I think the changes in DefineView and ATExecSetRelOptions is wrong,
because transformRelOptions() is still using pg_strcasecmp. With the
patch:rhaas=# create view v(x) with ("Check_option"="local") as select 1;
CREATE VIEW
rhaas=# create view v(x) with ("check_option"="local") as select 1;
ERROR: WITH CHECK OPTION is supported only on automatically updatable views
HINT: Views that do not select from a single table or view are not
automatically updatable.Oops.
I am getting the feeling that there could be other issues than this
one... If this patch ever gets integrated, I think that this should
actually be shaped as two patches:
- One patch with the set of DDL queries taking advantage of the
current grammar with pg_strcasecmp.
- A second patch that does the switch from pg_strcasecmp to strcmp,
and allows checking which paths of patch 1 are getting changed.
Patch 1 is the hard part to figure out all the possible patterns that
could be changed.
I am actually pretty dubious that we want to do this. I found one bug
already (see above), and I don't think there's any guarantee that it's
the only one, because it's pretty hard to be sure that none of the
remaining calls to pg_strcasecmp are being applied to any of these
values in some other part of the code. I'm not sure that the backward
compatibility issue is a huge deal, but from my point of view this
carries a significant risk of introducing new bugs, might annoy users
who spell any of these keywords in all caps with surrounding quotation
marks, and really has no clear benefit that I can see. The
originally-offered justification is that making this consistent would
help us avoid subtle bugs, but it seems at least as likely to CREATE
subtle bugs, and the status quo is AFAICT harming nobody.
Changing opinion here ;)
Yes, I agree that the risk of bugs may not be worth the compatibility
effort at the end. I still see value in this patch for long-term
purposes by making the code more consistent though.
--
Michael
Greetings Michael, Daniel, all,
* Michael Paquier (michael.paquier@gmail.com) wrote:
On Fri, Dec 1, 2017 at 4:14 AM, Robert Haas <robertmhaas@gmail.com> wrote:
I think the changes in DefineView and ATExecSetRelOptions is wrong,
because transformRelOptions() is still using pg_strcasecmp. With the
patch:rhaas=# create view v(x) with ("Check_option"="local") as select 1;
CREATE VIEW
rhaas=# create view v(x) with ("check_option"="local") as select 1;
ERROR: WITH CHECK OPTION is supported only on automatically updatable views
HINT: Views that do not select from a single table or view are not
automatically updatable.Oops.
I am getting the feeling that there could be other issues than this
one... If this patch ever gets integrated, I think that this should
actually be shaped as two patches:
- One patch with the set of DDL queries taking advantage of the
current grammar with pg_strcasecmp.
- A second patch that does the switch from pg_strcasecmp to strcmp,
and allows checking which paths of patch 1 are getting changed.
Patch 1 is the hard part to figure out all the possible patterns that
could be changed.I am actually pretty dubious that we want to do this. I found one bug
already (see above), and I don't think there's any guarantee that it's
the only one, because it's pretty hard to be sure that none of the
remaining calls to pg_strcasecmp are being applied to any of these
values in some other part of the code. I'm not sure that the backward
compatibility issue is a huge deal, but from my point of view this
carries a significant risk of introducing new bugs, might annoy users
who spell any of these keywords in all caps with surrounding quotation
marks, and really has no clear benefit that I can see. The
originally-offered justification is that making this consistent would
help us avoid subtle bugs, but it seems at least as likely to CREATE
subtle bugs, and the status quo is AFAICT harming nobody.Changing opinion here ;)
Yes, I agree that the risk of bugs may not be worth the compatibility
effort at the end. I still see value in this patch for long-term
purposes by making the code more consistent though.
Looks like this discussion has progressed to where this patch should
really be marked as Rejected. Does anyone else want to voice an opinion
regarding it, or perhaps Daniel could post a rebuttal to the concerns
raised here?
Thinking through it, for my own 2c on this, I tend to agree with Tom
that, really, we should be using strcmp() for anything coming out of the
parser and that the backward-compatibility break from that is
acceptable. I also understand Robert's concern that there may be other
bugs hiding and I wonder if there might be a way to check for them,
though no great ideas spring to mind offhand. Would be great to hear
your thoughts, Daniel, so leaving this in Waiting on Author for now.
Thanks!
Stephen
Stephen Frost <sfrost@snowman.net> writes:
Thinking through it, for my own 2c on this, I tend to agree with Tom
that, really, we should be using strcmp() for anything coming out of the
parser and that the backward-compatibility break from that is
acceptable. I also understand Robert's concern that there may be other
bugs hiding and I wonder if there might be a way to check for them,
though no great ideas spring to mind offhand. Would be great to hear
your thoughts, Daniel, so leaving this in Waiting on Author for now.
FWIW, I don't especially agree with Robert's position, because I think
he is ignoring the argument that it's a bug that some things are
case-sensitive and other seemingly similar things are not.
It's definitely concerning that the submitted patch introduced a new bug,
but we have seldom taken the position that bugs in an initial submission
are sufficient grounds for rejecting the entire concept.
ISTM that if this patch gets rid of a large fraction of the uses of
pg_strcasecmp in the backend, which is what I expect it should, then
it might not be out of reach to go through all the surviving ones to
make sure they are not processing strings that originate in the parser.
regards, tom lane
On Sun, Jan 7, 2018 at 9:38 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
ISTM that if this patch gets rid of a large fraction of the uses of
pg_strcasecmp in the backend, which is what I expect it should, then
it might not be out of reach to go through all the surviving ones to
make sure they are not processing strings that originate in the parser.
Yeah, that's why I think that it is important for this patch to
provide as well tests to make sure that all the code paths are working
as they should with this patch.
--
Michael
On Sat, Jan 6, 2018 at 7:38 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
It's definitely concerning that the submitted patch introduced a new bug,
but we have seldom taken the position that bugs in an initial submission
are sufficient grounds for rejecting the entire concept.
Fair point. I withdraw my categorical -1 vote and replace it with the
statement that the patch hasn't been sufficiently-carefully checked by
the patch author or other reviewers for bugs to consider committing it
-- nor has anyone taken the trouble to list with precision all of the
places where the behavior will change. I think the latter is
absolutely indispensable, which is why I started to compile such a
list in my previous post. The former needs to be done as well, of
course.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On 08 Jan 2018, at 17:27, Robert Haas <robertmhaas@gmail.com> wrote:
On Sat, Jan 6, 2018 at 7:38 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
It's definitely concerning that the submitted patch introduced a new bug,
but we have seldom taken the position that bugs in an initial submission
are sufficient grounds for rejecting the entire concept.Fair point. I withdraw my categorical -1 vote and replace it with the
statement that the patch hasn't been sufficiently-carefully checked by
the patch author or other reviewers for bugs to consider committing it
-- nor has anyone taken the trouble to list with precision all of the
places where the behavior will change. I think the latter is
absolutely indispensable, which is why I started to compile such a
list in my previous post.
Sorry for dropping off the radar, my available time for hacking was severely
limited (well, down to zero really).
Seeing the surface again I’ve started on the complete list and hope to have
something quite soon, and I think (as seems to be the consensus on this thread)
that that list is a prerequisite for the review.
cheers ./daniel
On 07 Jan 2018, at 01:17, Stephen Frost <sfrost@snowman.net> wrote:
Would be great to hear your thoughts, Daniel, so leaving this in Waiting on
Author for now.
I am still of the opinion that it’s worth going through and ensuring that we
are matching against parser output in a consistent way, if only to lower the
risk of subtle hard to find bugs. This patch is a first stab, but there are
more string comparisons to consider should we decide to ahead with this patch
(or the general approach in some other fashion than this implementation).
Collating the responses so far with an updated patch, thanks to everyone who
has reviewed this patch! Sorry being slow to respond, $life hasn’t allowed for
much hacking lately.
On 30 Nov 2017, at 20:14, Robert Haas <robertmhaas@gmail.com> wrote:
I am having a bit of trouble understanding why the first hunk in
DefineAggregate() is taking PARALLEL as a special case. The
documentation gives three separate synopses for CREATE AGGREGATE, but
parallel appears in all of them, and there are other options that do
too, so the comment doesn't really help me understand why it's special
as compared to other, similar options.
The reason for the special handling of parallel in the old-style CREATE
AGGREGATE syntax is that it’s parsed with IDENT rather than ColLabel. AFAICT
that works for all parameters except parallel as it’s an unreserved keyword
since 7aea8e4f2da. Extending old_aggr_elem to handle PARALLEL separately seems
to work for not requiring the quoting, but I may be missing something as the
parser hacking isn’t my speciality. The patch has been updated with this (and
the documentation + tests changes to go with it) but it clearly needs a close
eye.
I think the changes in DefineView and ATExecSetRelOptions is wrong,
because transformRelOptions() is still using pg_strcasecmp.
Correct, I had missed that reloptions case, sorry about that. The hunk in
AlterTableGetRelOptionsLockLevel() seems correct to me, and testing didn’t
break anything, but I wonder if there is a case where it would need
pg_strncasecmp?
On 08 Jan 2018, at 17:27, Robert Haas <robertmhaas@gmail.com> wrote:
nor has anyone taken the trouble to list with precision all of the
places where the behavior will change. I think the latter is
absolutely indispensable,
I had a look at the available commands in postgres and compiled a list of them
in options.sql based on if they have options, and how those options and matched
(case sensitive of insensitive). The queries in the file are nonsensical, they
are just meant to show the handling of the options. The idea was to illustrate
the impact of this proposal by running examples. Running this file with and
without the patches applied shows the following commands being affected:
CREATE TABLE
CREATE TABLE AS
ALTER TABLE
CREATE TABLESPACE
ALTER TABLESPACE
CREATE VIEW
ALTER VIEW
CREATE INDEX
ALTER INDEX
CREATE AGGREGATE (new and old syntax)
CREATE COLLATION
CREATE FUNCTION
CREATE OPERATOR
ALTER OPERATOR
CREATE TYPE
CREATE TEXT SEARCH CONFIGURATION
CREATE TEXT SEARCH DICTIONARY
ALTER TEXT SEARCH DICTIONARY
The output with the patch is attached as options_patched.out, and the output
from master as options_master.out. Diffing the two files is rather helpful I
think.
All possible options aren’t excercised, and I hope I didn’t miss any statements
that should’ve been covered. The options.sql file makes it quite obvious that
we currently have quite a mix of case sensitive and insensitive commands. Is
this in line with what you were thinking Robert? I’m definitely up for better
ideas.
One open question from this excercise is how to write a good test for this. It
can either be made part of the already existing test queries or a separate
suite. I’m leaning on the latter simply because the case-flipping existing
tests seems like something that can be cleaned up years from now accidentally
because it looks odd.
On 07 Jan 2018, at 01:38, Tom Lane <tgl@sss.pgh.pa.us> wrote:
ISTM that if this patch gets rid of a large fraction of the uses of
pg_strcasecmp in the backend, which is what I expect it should, then
it might not be out of reach to go through all the surviving ones to
make sure they are not processing strings that originate in the parser.
I completely agree, but I have not expanded this patch with this. One case was
actually instead put back, since I did see a mention in the documentation for
isStrict and isCachable they aren’t case sensitive. Instead I removed that
section from the documentation in a hope that we some day can make these case
sensitive.
Additionally, while poking at the commands I noticed an inconsistency in
checking for conflicting options in CREATE FUNCTION. The below statement is
correctly erroring on IMMUTABLE and VOLATILE being conflicting:
create function int42(cstring) returns int42 AS 'int4in'
language internal strict immutable volatile;
If you however combine the new and old syntax, the statement works and the WITH
option wins by overwriting any previous value. The below statement creates an
IMMUTABLE function:
create function int42(cstring) returns int42 AS 'int4in'
language internal strict volatile with (isstrict, iscachable);
It’s arguably a pretty silly statement to write, and may very well never have
been seen in production, but I would still expect that query to error out.
Attached volatility.patch fixes it in a hacky way to behave like the former
statement, there is probably a cleaner way but I didn’t want to spend too much
time on it before hearing if others think it’s not worth fixing.
Thanks for looking at this!
cheers ./daniel
Attachments:
defname_strcmp-v4.patchapplication/octet-stream; name=defname_strcmp-v4.patchDownload
From 25ae6bfd25ff9eeabc01f55a9b1825f7ccf90ba6 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <daniel@yesql.se>
Date: Wed, 10 Jan 2018 23:26:45 +0100
Subject: [PATCH 1/2] Use strcmp() instead of pg_strcasecmp() for identifier
matching
Since these option values are parsed using either the IDENT rule,
via keyword rules, or are created in lowercase with makeString(),
using strcmp() is the correct approach here. While not wrong per
se, using case insensitive matching can hide subtle bugs in case
defnames are created with mixed-case as these options otherwise
are assumed to always be lowercased.
The parsing of the PARALLEL option in the old style syntax for
CREATE AGGREGATE was fixed to allow using strcmp as well.
Reorder a few checks while in there such that all checks are in
the same order to make it easier to grep/read.
Also remove comment in tsearchcmds.c:getTokenTypes() regarding
strcmp/pg_strcasecmp as the code is correct. token_type is parsed
using the IDENT rule and will always be in lowercase.
---
contrib/dict_int/dict_int.c | 4 +--
contrib/dict_xsyn/dict_xsyn.c | 10 +++---
contrib/unaccent/unaccent.c | 2 +-
doc/src/sgml/ref/create_aggregate.sgml | 1 +
doc/src/sgml/ref/create_function.sgml | 1 -
src/backend/access/common/reloptions.c | 11 +++----
src/backend/commands/aggregatecmds.c | 56 ++++++++++++++++----------------
src/backend/commands/collationcmds.c | 12 +++----
src/backend/commands/functioncmds.c | 6 ++++
src/backend/commands/operatorcmds.c | 44 ++++++++++++-------------
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/tsearchcmds.c | 23 +++++++------
src/backend/commands/typecmds.c | 48 +++++++++++++--------------
src/backend/commands/view.c | 6 ++--
src/backend/parser/gram.y | 12 ++++---
src/backend/parser/parse_clause.c | 2 +-
src/backend/snowball/dict_snowball.c | 4 +--
src/backend/tsearch/dict_ispell.c | 6 ++--
src/backend/tsearch/dict_simple.c | 4 +--
src/backend/tsearch/dict_synonym.c | 4 +--
src/backend/tsearch/dict_thesaurus.c | 4 +--
src/test/regress/expected/aggregates.out | 4 +--
src/test/regress/sql/aggregates.sql | 4 +--
23 files changed, 139 insertions(+), 131 deletions(-)
diff --git a/contrib/dict_int/dict_int.c b/contrib/dict_int/dict_int.c
index 8b45532938..56ede37089 100644
--- a/contrib/dict_int/dict_int.c
+++ b/contrib/dict_int/dict_int.c
@@ -42,11 +42,11 @@ dintdict_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "MAXLEN") == 0)
+ if (strcmp(defel->defname, "maxlen") == 0)
{
d->maxlen = atoi(defGetString(defel));
}
- else if (pg_strcasecmp(defel->defname, "REJECTLONG") == 0)
+ else if (strcmp(defel->defname, "rejectlong") == 0)
{
d->rejectlong = defGetBoolean(defel);
}
diff --git a/contrib/dict_xsyn/dict_xsyn.c b/contrib/dict_xsyn/dict_xsyn.c
index 8a3abf7e3c..a79ece240c 100644
--- a/contrib/dict_xsyn/dict_xsyn.c
+++ b/contrib/dict_xsyn/dict_xsyn.c
@@ -157,23 +157,23 @@ dxsyn_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "MATCHORIG") == 0)
+ if (strcmp(defel->defname, "matchorig") == 0)
{
d->matchorig = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "KEEPORIG") == 0)
+ else if (strcmp(defel->defname, "keeporig") == 0)
{
d->keeporig = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "MATCHSYNONYMS") == 0)
+ else if (strcmp(defel->defname, "matchsynonyms") == 0)
{
d->matchsynonyms = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "KEEPSYNONYMS") == 0)
+ else if (strcmp(defel->defname, "keepsynonyms") == 0)
{
d->keepsynonyms = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "RULES") == 0)
+ else if (strcmp(defel->defname, "rules") == 0)
{
/* we can't read the rules before parsing all options! */
filename = defGetString(defel);
diff --git a/contrib/unaccent/unaccent.c b/contrib/unaccent/unaccent.c
index 82f9c7fcfe..247c202755 100644
--- a/contrib/unaccent/unaccent.c
+++ b/contrib/unaccent/unaccent.c
@@ -276,7 +276,7 @@ unaccent_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("Rules", defel->defname) == 0)
+ if (strcmp(defel->defname, "rules") == 0)
{
if (fileloaded)
ereport(ERROR,
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index a4aaae876e..c46491991b 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -80,6 +80,7 @@ CREATE AGGREGATE <replaceable class="parameter">name</replaceable> (
[ , MFINALFUNC_MODIFY = { READ_ONLY | SHARABLE | READ_WRITE } ]
[ , MINITCOND = <replaceable class="parameter">minitial_condition</replaceable> ]
[ , SORTOP = <replaceable class="parameter">sort_operator</replaceable> ]
+ [ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ]
)
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml
index fd229d1193..869b8b396c 100644
--- a/doc/src/sgml/ref/create_function.sgml
+++ b/doc/src/sgml/ref/create_function.sgml
@@ -590,7 +590,6 @@ CREATE [ OR REPLACE ] FUNCTION
</variablelist>
- Attribute names are not case-sensitive.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 425bc5d06e..fde2790bbe 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -865,7 +865,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
def->defnamespace)));
}
- if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
+ if (ignoreOids && strcmp(def->defname, "oids") == 0)
continue;
/* ignore if not in the same namespace */
@@ -1081,8 +1081,7 @@ parseRelOptions(Datum options, bool validate, relopt_kind kind,
int kw_len = reloptions[j].gen->namelen;
if (text_len > kw_len && text_str[kw_len] == '=' &&
- pg_strncasecmp(text_str, reloptions[j].gen->name,
- kw_len) == 0)
+ strncmp(text_str, reloptions[j].gen->name, kw_len) == 0)
{
parse_one_reloption(&reloptions[j], text_str, text_len,
validate);
@@ -1555,9 +1554,9 @@ AlterTableGetRelOptionsLockLevel(List *defList)
for (i = 0; relOpts[i]; i++)
{
- if (pg_strncasecmp(relOpts[i]->name,
- def->defname,
- relOpts[i]->namelen + 1) == 0)
+ if (strncmp(relOpts[i]->name,
+ def->defname,
+ relOpts[i]->namelen + 1) == 0)
{
if (lockmode < relOpts[i]->lockmode)
lockmode = relOpts[i]->lockmode;
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 15378a9d4d..ced80fb155 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -127,37 +127,37 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
* sfunc1, stype1, and initcond1 are accepted as obsolete spellings
* for sfunc, stype, initcond.
*/
- if (pg_strcasecmp(defel->defname, "sfunc") == 0)
+ if (strcmp(defel->defname, "sfunc") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
+ else if (strcmp(defel->defname, "sfunc1") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
+ else if (strcmp(defel->defname, "finalfunc") == 0)
finalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "combinefunc") == 0)
+ else if (strcmp(defel->defname, "combinefunc") == 0)
combinefuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "serialfunc") == 0)
+ else if (strcmp(defel->defname, "serialfunc") == 0)
serialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "deserialfunc") == 0)
+ else if (strcmp(defel->defname, "deserialfunc") == 0)
deserialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "msfunc") == 0)
+ else if (strcmp(defel->defname, "msfunc") == 0)
mtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "minvfunc") == 0)
+ else if (strcmp(defel->defname, "minvfunc") == 0)
minvtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc") == 0)
mfinalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "finalfunc_extra") == 0)
finalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
mfinalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_modify") == 0)
+ else if (strcmp(defel->defname, "finalfunc_modify") == 0)
finalfuncModify = extractModify(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_modify") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
mfinalfuncModify = extractModify(defel);
- else if (pg_strcasecmp(defel->defname, "sortop") == 0)
+ else if (strcmp(defel->defname, "sortop") == 0)
sortoperatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "basetype") == 0)
+ else if (strcmp(defel->defname, "basetype") == 0)
baseType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "hypothetical") == 0)
+ else if (strcmp(defel->defname, "hypothetical") == 0)
{
if (defGetBoolean(defel))
{
@@ -168,23 +168,23 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
aggKind = AGGKIND_HYPOTHETICAL;
}
}
- else if (pg_strcasecmp(defel->defname, "stype") == 0)
+ else if (strcmp(defel->defname, "stype") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "stype1") == 0)
+ else if (strcmp(defel->defname, "stype1") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "sspace") == 0)
+ else if (strcmp(defel->defname, "sspace") == 0)
transSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "mstype") == 0)
+ else if (strcmp(defel->defname, "mstype") == 0)
mtransType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "msspace") == 0)
+ else if (strcmp(defel->defname, "msspace") == 0)
mtransSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "initcond") == 0)
+ else if (strcmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
+ else if (strcmp(defel->defname, "initcond1") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "minitcond") == 0)
+ else if (strcmp(defel->defname, "minitcond") == 0)
minitval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "parallel") == 0)
+ else if (strcmp(defel->defname, "parallel") == 0)
parallel = defGetString(defel);
else
ereport(WARNING,
@@ -420,11 +420,11 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
if (parallel)
{
- if (pg_strcasecmp(parallel, "safe") == 0)
+ if (strcmp(parallel, "safe") == 0)
proparallel = PROPARALLEL_SAFE;
- else if (pg_strcasecmp(parallel, "restricted") == 0)
+ else if (strcmp(parallel, "restricted") == 0)
proparallel = PROPARALLEL_RESTRICTED;
- else if (pg_strcasecmp(parallel, "unsafe") == 0)
+ else if (strcmp(parallel, "unsafe") == 0)
proparallel = PROPARALLEL_UNSAFE;
else
ereport(ERROR,
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index 6c6877395f..35fd0c64e2 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -82,17 +82,17 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
DefElem *defel = lfirst_node(DefElem, pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "from") == 0)
+ if (strcmp(defel->defname, "from") == 0)
defelp = &fromEl;
- else if (pg_strcasecmp(defel->defname, "locale") == 0)
+ else if (strcmp(defel->defname, "locale") == 0)
defelp = &localeEl;
- else if (pg_strcasecmp(defel->defname, "lc_collate") == 0)
+ else if (strcmp(defel->defname, "lc_collate") == 0)
defelp = &lccollateEl;
- else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0)
+ else if (strcmp(defel->defname, "lc_ctype") == 0)
defelp = &lcctypeEl;
- else if (pg_strcasecmp(defel->defname, "provider") == 0)
+ else if (strcmp(defel->defname, "provider") == 0)
defelp = &providerEl;
- else if (pg_strcasecmp(defel->defname, "version") == 0)
+ else if (strcmp(defel->defname, "version") == 0)
defelp = &versionEl;
else
{
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 12ab33f418..8eed5a0166 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -811,6 +811,12 @@ compute_attributes_with_style(ParseState *pstate, bool is_procedure, List *param
{
DefElem *param = (DefElem *) lfirst(pl);
+ /*
+ * Attribute names from the parser should always be in casefolded into
+ * lowercase, but for the old attributes isStrict and isCachable the
+ * manual has since 7.3 stated that they are not case-sensitive so for
+ * now use pg_strcasecmp().
+ */
if (pg_strcasecmp(param->defname, "isstrict") == 0)
{
if (is_procedure)
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 81ef532184..70090b9b97 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -105,7 +105,7 @@ DefineOperator(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "leftarg") == 0)
+ if (strcmp(defel->defname, "leftarg") == 0)
{
typeName1 = defGetTypeName(defel);
if (typeName1->setof)
@@ -113,7 +113,7 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
+ else if (strcmp(defel->defname, "rightarg") == 0)
{
typeName2 = defGetTypeName(defel);
if (typeName2->setof)
@@ -121,28 +121,28 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "procedure") == 0)
+ else if (strcmp(defel->defname, "procedure") == 0)
functionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "commutator") == 0)
+ else if (strcmp(defel->defname, "commutator") == 0)
commutatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "negator") == 0)
+ else if (strcmp(defel->defname, "negator") == 0)
negatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ else if (strcmp(defel->defname, "restrict") == 0)
restrictionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
joinName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "hashes") == 0)
+ else if (strcmp(defel->defname, "hashes") == 0)
canHash = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "merges") == 0)
canMerge = defGetBoolean(defel);
/* These obsolete options are taken as meaning canMerge */
- else if (pg_strcasecmp(defel->defname, "sort1") == 0)
+ else if (strcmp(defel->defname, "sort1") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "sort2") == 0)
+ else if (strcmp(defel->defname, "sort2") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
+ else if (strcmp(defel->defname, "ltcmp") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
+ else if (strcmp(defel->defname, "gtcmp") == 0)
canMerge = true;
else
{
@@ -420,12 +420,12 @@ AlterOperator(AlterOperatorStmt *stmt)
else
param = defGetQualifiedName(defel);
- if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ if (strcmp(defel->defname, "restrict") == 0)
{
restrictionName = param;
updateRestriction = true;
}
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
{
joinName = param;
updateJoin = true;
@@ -435,13 +435,13 @@ AlterOperator(AlterOperatorStmt *stmt)
* The rest of the options that CREATE accepts cannot be changed.
* Check for them so that we can give a meaningful error message.
*/
- else if (pg_strcasecmp(defel->defname, "leftarg") == 0 ||
- pg_strcasecmp(defel->defname, "rightarg") == 0 ||
- pg_strcasecmp(defel->defname, "procedure") == 0 ||
- pg_strcasecmp(defel->defname, "commutator") == 0 ||
- pg_strcasecmp(defel->defname, "negator") == 0 ||
- pg_strcasecmp(defel->defname, "hashes") == 0 ||
- pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "leftarg") == 0 ||
+ strcmp(defel->defname, "rightarg") == 0 ||
+ strcmp(defel->defname, "procedure") == 0 ||
+ strcmp(defel->defname, "commutator") == 0 ||
+ strcmp(defel->defname, "negator") == 0 ||
+ strcmp(defel->defname, "hashes") == 0 ||
+ strcmp(defel->defname, "merges") == 0)
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f2a928b823..2e10b5c7ee 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -10449,7 +10449,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index bf06ed9318..4642c9fe8a 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -209,27 +209,27 @@ DefineTSParser(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "start") == 0)
+ if (strcmp(defel->defname, "start") == 0)
{
values[Anum_pg_ts_parser_prsstart - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
}
- else if (pg_strcasecmp(defel->defname, "gettoken") == 0)
+ else if (strcmp(defel->defname, "gettoken") == 0)
{
values[Anum_pg_ts_parser_prstoken - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
}
- else if (pg_strcasecmp(defel->defname, "end") == 0)
+ else if (strcmp(defel->defname, "end") == 0)
{
values[Anum_pg_ts_parser_prsend - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
}
- else if (pg_strcasecmp(defel->defname, "headline") == 0)
+ else if (strcmp(defel->defname, "headline") == 0)
{
values[Anum_pg_ts_parser_prsheadline - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
}
- else if (pg_strcasecmp(defel->defname, "lextypes") == 0)
+ else if (strcmp(defel->defname, "lextypes") == 0)
{
values[Anum_pg_ts_parser_prslextype - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
@@ -438,7 +438,7 @@ DefineTSDictionary(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "template") == 0)
+ if (strcmp(defel->defname, "template") == 0)
{
templId = get_ts_template_oid(defGetQualifiedName(defel), false);
}
@@ -580,7 +580,7 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
DefElem *oldel = (DefElem *) lfirst(cell);
next = lnext(cell);
- if (pg_strcasecmp(oldel->defname, defel->defname) == 0)
+ if (strcmp(oldel->defname, defel->defname) == 0)
dictoptions = list_delete_cell(dictoptions, cell, prev);
else
prev = cell;
@@ -765,13 +765,13 @@ DefineTSTemplate(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "init") == 0)
+ if (strcmp(defel->defname, "init") == 0)
{
values[Anum_pg_ts_template_tmplinit - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
nulls[Anum_pg_ts_template_tmplinit - 1] = false;
}
- else if (pg_strcasecmp(defel->defname, "lexize") == 0)
+ else if (strcmp(defel->defname, "lexize") == 0)
{
values[Anum_pg_ts_template_tmpllexize - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
@@ -990,9 +990,9 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "parser") == 0)
+ if (strcmp(defel->defname, "parser") == 0)
prsOid = get_ts_parser_oid(defGetQualifiedName(defel), false);
- else if (pg_strcasecmp(defel->defname, "copy") == 0)
+ else if (strcmp(defel->defname, "copy") == 0)
sourceOid = get_ts_config_oid(defGetQualifiedName(defel), false);
else
ereport(ERROR,
@@ -1251,7 +1251,6 @@ getTokenTypes(Oid prsId, List *tokennames)
j = 0;
while (list && list[j].lexid)
{
- /* XXX should we use pg_strcasecmp here? */
if (strcmp(strVal(val), list[j].alias) == 0)
{
res[i] = list[j].lexid;
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index a40b3cf752..94d6a17ed3 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -245,42 +245,42 @@ DefineType(ParseState *pstate, List *names, List *parameters)
DefElem *defel = (DefElem *) lfirst(pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "like") == 0)
+ if (strcmp(defel->defname, "like") == 0)
defelp = &likeTypeEl;
- else if (pg_strcasecmp(defel->defname, "internallength") == 0)
+ else if (strcmp(defel->defname, "internallength") == 0)
defelp = &internalLengthEl;
- else if (pg_strcasecmp(defel->defname, "input") == 0)
+ else if (strcmp(defel->defname, "input") == 0)
defelp = &inputNameEl;
- else if (pg_strcasecmp(defel->defname, "output") == 0)
+ else if (strcmp(defel->defname, "output") == 0)
defelp = &outputNameEl;
- else if (pg_strcasecmp(defel->defname, "receive") == 0)
+ else if (strcmp(defel->defname, "receive") == 0)
defelp = &receiveNameEl;
- else if (pg_strcasecmp(defel->defname, "send") == 0)
+ else if (strcmp(defel->defname, "send") == 0)
defelp = &sendNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
+ else if (strcmp(defel->defname, "typmod_in") == 0)
defelp = &typmodinNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
+ else if (strcmp(defel->defname, "typmod_out") == 0)
defelp = &typmodoutNameEl;
- else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
- pg_strcasecmp(defel->defname, "analyse") == 0)
+ else if (strcmp(defel->defname, "analyze") == 0 ||
+ strcmp(defel->defname, "analyse") == 0)
defelp = &analyzeNameEl;
- else if (pg_strcasecmp(defel->defname, "category") == 0)
+ else if (strcmp(defel->defname, "category") == 0)
defelp = &categoryEl;
- else if (pg_strcasecmp(defel->defname, "preferred") == 0)
+ else if (strcmp(defel->defname, "preferred") == 0)
defelp = &preferredEl;
- else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
+ else if (strcmp(defel->defname, "delimiter") == 0)
defelp = &delimiterEl;
- else if (pg_strcasecmp(defel->defname, "element") == 0)
+ else if (strcmp(defel->defname, "element") == 0)
defelp = &elemTypeEl;
- else if (pg_strcasecmp(defel->defname, "default") == 0)
+ else if (strcmp(defel->defname, "default") == 0)
defelp = &defaultValueEl;
- else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
+ else if (strcmp(defel->defname, "passedbyvalue") == 0)
defelp = &byValueEl;
- else if (pg_strcasecmp(defel->defname, "alignment") == 0)
+ else if (strcmp(defel->defname, "alignment") == 0)
defelp = &alignmentEl;
- else if (pg_strcasecmp(defel->defname, "storage") == 0)
+ else if (strcmp(defel->defname, "storage") == 0)
defelp = &storageEl;
- else if (pg_strcasecmp(defel->defname, "collatable") == 0)
+ else if (strcmp(defel->defname, "collatable") == 0)
defelp = &collatableEl;
else
{
@@ -1439,7 +1439,7 @@ DefineRange(CreateRangeStmt *stmt)
{
DefElem *defel = (DefElem *) lfirst(lc);
- if (pg_strcasecmp(defel->defname, "subtype") == 0)
+ if (strcmp(defel->defname, "subtype") == 0)
{
if (OidIsValid(rangeSubtype))
ereport(ERROR,
@@ -1448,7 +1448,7 @@ DefineRange(CreateRangeStmt *stmt)
/* we can look up the subtype name immediately */
rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
}
- else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
+ else if (strcmp(defel->defname, "subtype_opclass") == 0)
{
if (rangeSubOpclassName != NIL)
ereport(ERROR,
@@ -1456,7 +1456,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeSubOpclassName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "collation") == 0)
+ else if (strcmp(defel->defname, "collation") == 0)
{
if (rangeCollationName != NIL)
ereport(ERROR,
@@ -1464,7 +1464,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCollationName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "canonical") == 0)
+ else if (strcmp(defel->defname, "canonical") == 0)
{
if (rangeCanonicalName != NIL)
ereport(ERROR,
@@ -1472,7 +1472,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCanonicalName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
+ else if (strcmp(defel->defname, "subtype_diff") == 0)
{
if (rangeSubtypeDiffName != NIL)
ereport(ERROR,
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 04ad76a210..7d4511c585 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -46,8 +46,8 @@ void
validateWithCheckOption(const char *value)
{
if (value == NULL ||
- (pg_strcasecmp(value, "local") != 0 &&
- pg_strcasecmp(value, "cascaded") != 0))
+ (strcmp(value, "local") != 0 &&
+ strcmp(value, "cascaded") != 0))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -485,7 +485,7 @@ DefineView(ViewStmt *stmt, const char *queryString,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e42b7caff6..24d1b06927 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -5823,11 +5823,15 @@ old_aggr_list: old_aggr_elem { $$ = list_make1($1); }
;
/*
- * Must use IDENT here to avoid reduce/reduce conflicts; fortunately none of
- * the item names needed in old aggregate definitions are likely to become
- * SQL keywords.
+ * Must use IDENT here to avoid reduce/reduce conflicts; fortunately, with
+ * the exception of PARALLEL, none of the item names needed in old aggregate
+ * definitions are likely to become keywords.
*/
-old_aggr_elem: IDENT '=' def_arg
+old_aggr_elem: PARALLEL '=' def_arg
+ {
+ $$ = makeDefElem("parallel", (Node *)$3, @1);
+ }
+ | IDENT '=' def_arg
{
$$ = makeDefElem($1, (Node *)$3, @1);
}
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 9fbcfd4fa6..406cd1dad0 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -262,7 +262,7 @@ interpretOidsOption(List *defList, bool allowOids)
DefElem *def = (DefElem *) lfirst(cell);
if (def->defnamespace == NULL &&
- pg_strcasecmp(def->defname, "oids") == 0)
+ strcmp(def->defname, "oids") == 0)
{
if (!allowOids)
ereport(ERROR,
diff --git a/src/backend/snowball/dict_snowball.c b/src/backend/snowball/dict_snowball.c
index 043681ec2d..78c9f73ef0 100644
--- a/src/backend/snowball/dict_snowball.c
+++ b/src/backend/snowball/dict_snowball.c
@@ -192,7 +192,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -201,7 +201,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Language", defel->defname) == 0)
+ else if (strcmp(defel->defname, "language") == 0)
{
if (d->stem)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_ispell.c b/src/backend/tsearch/dict_ispell.c
index 0d706795ad..edc6547700 100644
--- a/src/backend/tsearch/dict_ispell.c
+++ b/src/backend/tsearch/dict_ispell.c
@@ -44,7 +44,7 @@ dispell_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "DictFile") == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (dictloaded)
ereport(ERROR,
@@ -55,7 +55,7 @@ dispell_init(PG_FUNCTION_ARGS)
"dict"));
dictloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "AffFile") == 0)
+ else if (strcmp(defel->defname, "afffile") == 0)
{
if (affloaded)
ereport(ERROR,
@@ -66,7 +66,7 @@ dispell_init(PG_FUNCTION_ARGS)
"affix"));
affloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "StopWords") == 0)
+ else if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_simple.c b/src/backend/tsearch/dict_simple.c
index 268b4e48cf..ac6a24eba5 100644
--- a/src/backend/tsearch/dict_simple.c
+++ b/src/backend/tsearch/dict_simple.c
@@ -41,7 +41,7 @@ dsimple_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -50,7 +50,7 @@ dsimple_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Accept", defel->defname) == 0)
+ else if (strcmp(defel->defname, "accept") == 0)
{
if (acceptloaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_synonym.c b/src/backend/tsearch/dict_synonym.c
index 8ca65f3ded..c011886cb0 100644
--- a/src/backend/tsearch/dict_synonym.c
+++ b/src/backend/tsearch/dict_synonym.c
@@ -108,9 +108,9 @@ dsynonym_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("Synonyms", defel->defname) == 0)
+ if (strcmp(defel->defname, "synonyms") == 0)
filename = defGetString(defel);
- else if (pg_strcasecmp("CaseSensitive", defel->defname) == 0)
+ else if (strcmp(defel->defname, "casesensitive") == 0)
case_sensitive = defGetBoolean(defel);
else
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_thesaurus.c b/src/backend/tsearch/dict_thesaurus.c
index 23aaac8d07..24364e646d 100644
--- a/src/backend/tsearch/dict_thesaurus.c
+++ b/src/backend/tsearch/dict_thesaurus.c
@@ -616,7 +616,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("DictFile", defel->defname) == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (fileloaded)
ereport(ERROR,
@@ -625,7 +625,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
thesaurusRead(defGetString(defel), d);
fileloaded = true;
}
- else if (pg_strcasecmp("Dictionary", defel->defname) == 0)
+ else if (strcmp(defel->defname, "dictionary") == 0)
{
if (subdictname)
ereport(ERROR,
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out
index dbce7d3e8b..81943f3396 100644
--- a/src/test/regress/expected/aggregates.out
+++ b/src/test/regress/expected/aggregates.out
@@ -2011,7 +2011,7 @@ CREATE AGGREGATE balk(
BASETYPE = int4,
SFUNC = balkifnull(int8, int4),
STYPE = int8,
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0');
SELECT balk(hundred) FROM tenk1;
balk
@@ -2040,7 +2040,7 @@ CREATE AGGREGATE balk(
SFUNC = int4_sum(int8, int4),
STYPE = int8,
COMBINEFUNC = balkifnull(int8, int8),
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0'
);
-- force use of parallelism
diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql
index 6c9b86a616..6833b7ffce 100644
--- a/src/test/regress/sql/aggregates.sql
+++ b/src/test/regress/sql/aggregates.sql
@@ -865,7 +865,7 @@ CREATE AGGREGATE balk(
BASETYPE = int4,
SFUNC = balkifnull(int8, int4),
STYPE = int8,
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0');
SELECT balk(hundred) FROM tenk1;
@@ -893,7 +893,7 @@ CREATE AGGREGATE balk(
SFUNC = int4_sum(int8, int4),
STYPE = int8,
COMBINEFUNC = balkifnull(int8, int8),
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0'
);
--
2.14.1.145.gb3622a4ee
volatility.patchapplication/octet-stream; name=volatility.patchDownload
From 30ab5a3b8aa140444cafab5d0f86c86b1b53b1ae Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <daniel@yesql.se>
Date: Wed, 10 Jan 2018 23:26:47 +0100
Subject: [PATCH 2/2] Avoid silently changing volatilty in create function
A function cannot be declared both immutable and volatile, the
command will error out on conflicting options:
create function int42(cstring) returns int42 AS 'int4in'
language internal strict immutable volatile;
The following statement would however silently create an immutable
function due to iscachable in the with() clause being handled last
and overwriting the previous volatility setting.
create function int42(cstring) returns int42 AS 'int4in'
language internal strict volatile with (isstrict, iscachable);
With this patch, compute_attributes_with_style() checks if volatility
has been defined elsewhere in the statement and errors out in case
conflicting options are detected.
---
src/backend/commands/functioncmds.c | 27 ++++++++++++++++++++-----
src/test/regress/expected/create_function_3.out | 3 +++
src/test/regress/sql/create_function_3.sql | 2 ++
3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 8eed5a0166..2291b00180 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -650,7 +650,8 @@ compute_attributes_sql_style(ParseState *pstate,
ArrayType **proconfig,
float4 *procost,
float4 *prorows,
- char *parallel_p)
+ char *parallel_p,
+ bool *has_volatile)
{
ListCell *option;
DefElem *as_item = NULL;
@@ -758,7 +759,12 @@ compute_attributes_sql_style(ParseState *pstate,
if (windowfunc_item)
*windowfunc_p = intVal(windowfunc_item->arg);
if (volatility_item)
+ {
+ *has_volatile = true;
*volatility_p = interpret_func_volatility(volatility_item);
+ }
+ else
+ *has_volatile = false;
if (strict_item)
*strict_p = intVal(strict_item->arg);
if (security_item)
@@ -790,7 +796,8 @@ compute_attributes_sql_style(ParseState *pstate,
/*-------------
* Interpret the parameters *parameters and return their contents via
- * *isStrict_p and *volatility_p.
+ * *isStrict_p and *volatility_p. If has_volatile is true then volatility
+ * has been defined already in the syntax.
*
* These parameters supply optional information about a function.
* All have defaults if not specified. Parameters:
@@ -803,7 +810,7 @@ compute_attributes_sql_style(ParseState *pstate,
*------------
*/
static void
-compute_attributes_with_style(ParseState *pstate, bool is_procedure, List *parameters, bool *isStrict_p, char *volatility_p)
+compute_attributes_with_style(ParseState *pstate, bool is_procedure, List *parameters, bool *isStrict_p, char *volatility_p, bool has_volatile)
{
ListCell *pl;
@@ -834,8 +841,15 @@ compute_attributes_with_style(ParseState *pstate, bool is_procedure, List *param
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("invalid attribute in procedure definition"),
parser_errposition(pstate, param->location)));
+
if (defGetBoolean(param))
+ {
+ if (has_volatile && *volatility_p != PROVOLATILE_IMMUTABLE)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
*volatility_p = PROVOLATILE_IMMUTABLE;
+ }
}
else
ereport(WARNING,
@@ -943,6 +957,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
isStrict,
security,
isLeakProof;
+ bool hasVolatile;
char volatility;
ArrayType *proconfig;
float4 procost;
@@ -980,7 +995,8 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
&as_clause, &language, &transformDefElem,
&isWindowFunc, &volatility,
&isStrict, &security, &isLeakProof,
- &proconfig, &procost, &prorows, ¶llel);
+ &proconfig, &procost, &prorows, ¶llel,
+ &hasVolatile);
/* Look up the language and validate permissions */
languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
@@ -1112,7 +1128,8 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
trftypes = NULL;
}
- compute_attributes_with_style(pstate, stmt->is_procedure, stmt->withClause, &isStrict, &volatility);
+ compute_attributes_with_style(pstate, stmt->is_procedure, stmt->withClause,
+ &isStrict, &volatility, hasVolatile);
interpret_AS_clause(languageOid, language, funcname, as_clause,
&prosrc_str, &probin_str);
diff --git a/src/test/regress/expected/create_function_3.out b/src/test/regress/expected/create_function_3.out
index b5e19485e5..3d522c974c 100644
--- a/src/test/regress/expected/create_function_3.out
+++ b/src/test/regress/expected/create_function_3.out
@@ -66,6 +66,9 @@ SELECT proname, provolatile FROM pg_proc
functest_b_4 | v
(4 rows)
+CREATE FUNCTION functest_B_5(int) RETURNS bool LANGUAGE 'sql'
+ VOLATILE AS 'SELECT $1 < 0' WITH (iscachable);
+ERROR: conflicting or redundant options
--
-- SECURITY DEFINER | INVOKER
--
diff --git a/src/test/regress/sql/create_function_3.sql b/src/test/regress/sql/create_function_3.sql
index 0a0e407aab..187454b643 100644
--- a/src/test/regress/sql/create_function_3.sql
+++ b/src/test/regress/sql/create_function_3.sql
@@ -48,6 +48,8 @@ SELECT proname, provolatile FROM pg_proc
'functest_B_2'::regproc,
'functest_B_3'::regproc,
'functest_B_4'::regproc) ORDER BY proname;
+CREATE FUNCTION functest_B_5(int) RETURNS bool LANGUAGE 'sql'
+ VOLATILE AS 'SELECT $1 < 0' WITH (iscachable);
--
-- SECURITY DEFINER | INVOKER
--
2.14.1.145.gb3622a4ee
On Wed, Jan 10, 2018 at 11:49:47PM +0100, Daniel Gustafsson wrote:
On 08 Jan 2018, at 17:27, Robert Haas <robertmhaas@gmail.com> wrote:
nor has anyone taken the trouble to list with precision all of the
places where the behavior will change. I think the latter is
absolutely indispensable,I had a look at the available commands in postgres and compiled a list
of them in options.sql based on if they have options, and how those
options and matched (case sensitive of insensitive). The queries in
the file are nonsensical, they are just meant to show the handling of
the options. The idea was to illustrate the impact of this proposal
by running examples. Running this file with and without the patches
applied shows the following commands being affected:<snip>
The output with the patch is attached as options_patched.out, and the output
from master as options_master.out. Diffing the two files is rather helpful I
think.
Thanks. This is saving me hours of lookups and testing during the
review, as now reviewers just have to map you test series with the code
modified. I can't help to notice that tests for code paths with
contrib modules are missing. This brings up the point: do we want those
tests to be in the patch? I would like to think that a special section
dedicated to option compatibility for each command would be welcome to
track which grammar is supported and which grammar is not supported.
All possible options aren’t excercised, and I hope I didn’t miss any
statements that should’ve been covered. The options.sql file makes it
quite obvious that we currently have quite a mix of case sensitive and
insensitive commands. Is this in line with what you were thinking
Robert? I’m definitely up for better ideas.
I would think that one option tested in the series is fine to cover
grounds. Most of those code paths are made of a series of if/elif using
strcmp so all of them should be consistent..
One open question from this excercise is how to write a good test for
this. It can either be made part of the already existing test queries
or a separate suite. I’m leaning on the latter simply because the
case-flipping existing tests seems like something that can be cleaned
up years from now accidentally because it looks odd.
Adding them into src/test/regress/ sounds like a good plan to me.
If you however combine the new and old syntax, the statement works and the WITH
option wins by overwriting any previous value. The below statement creates an
IMMUTABLE function:create function int42(cstring) returns int42 AS 'int4in'
language internal strict volatile with (isstrict, iscachable);
Here is another idea: nuking isstrict and iscachable from CREATE
FUNCTION syntax and forget about them. I would be tempted of the opinion
to do that before the rest.
-old_aggr_elem: IDENT '=' def_arg
+old_aggr_elem: PARALLEL '=' def_arg
+ {
+ $$ = makeDefElem("parallel", (Node *)$3, @1);
+ }
+ | IDENT '=' def_arg
Nit: alphabetical order.
I have spent a couple of hours reviewing all the calls to pg_strcasecmp,
and the only thing I have noticed is in transformRelOptions(), where the
namespace string should be evaluated as well by strcmp, no? On HEAD:
=# create table a1 (a text) with ( "Toast"."Autovacuum_vacuum_cost_limit" = 1);
CREATE TABLE
=# create table a2 (a text) with ( "Toast.Autovacuum_vacuum_cost_limit" = 1);
ERROR: 22023: unrecognized parameter "Toast.Autovacuum_vacuum_cost_limit"
=# create table a3 (a text) with ( "Toast".autovacuum_vacuum_cost_limit = 1);
CREATE TABLE
=# create table a4 (a text) with ( toast."Autovacuum_vacuum_cost_limit" = 1);
CREATE TABLE
With your patch:
=# create table a1 (a text) with ( "Toast"."Autovacuum_vacuum_cost_limit" = 1);
ERROR: 22023: unrecognized parameter "Autovacuum_vacuum_cost_limit"
=# create table a2 (a text) with ( "Toast.Autovacuum_vacuum_cost_limit" = 1);
ERROR: 22023: unrecognized parameter "Toast.Autovacuum_vacuum_cost_limit"
=# create table a3 (a text) with ( "Toast".autovacuum_vacuum_cost_limit = 1);
CREATE TABLE
=# create table a4 (a text) with ( toast."Autovacuum_vacuum_cost_limit" = 1);
ERROR: 22023: unrecognized parameter "Autovacuum_vacuum_cost_limit"
LOCATION: parseRelOptions, reloptions.c:1103
So per my set of examples, the evaluation of the schema name should fail
when creating relation a3 with your patch applied. As the patch does
things, the experience for the user is not consistent, and the schema
name goes through parser via reloption_elem using makeDefElemExtended,
so this should use strcmp.
--
Michael
On 11 Jan 2018, at 09:01, Michael Paquier <michael.paquier@gmail.com> wrote:
On Wed, Jan 10, 2018 at 11:49:47PM +0100, Daniel Gustafsson wrote:
On 08 Jan 2018, at 17:27, Robert Haas <robertmhaas@gmail.com> wrote:
nor has anyone taken the trouble to list with precision all of the
places where the behavior will change. I think the latter is
absolutely indispensable,I had a look at the available commands in postgres and compiled a list
of them in options.sql based on if they have options, and how those
options and matched (case sensitive of insensitive). The queries in
the file are nonsensical, they are just meant to show the handling of
the options. The idea was to illustrate the impact of this proposal
by running examples. Running this file with and without the patches
applied shows the following commands being affected:<snip>
The output with the patch is attached as options_patched.out, and the output
from master as options_master.out. Diffing the two files is rather helpful I
think.Thanks. This is saving me hours of lookups and testing during the
review, as now reviewers just have to map you test series with the code
modified.
Well, being the one proposing the patch I should be the one spending those
hours and not you. Sorry for not including in the original submission.
I can't help to notice that tests for code paths with
contrib modules are missing. This brings up the point: do we want those
tests to be in the patch?
I left them out since they are version of ALTER TEXT SEARCH .. rather than new
statements.
I would like to think that a special section
dedicated to option compatibility for each command would be welcome to
track which grammar is supported and which grammar is not supported.
I’m not sure I follow?
One open question from this excercise is how to write a good test for
this. It can either be made part of the already existing test queries
or a separate suite. I’m leaning on the latter simply because the
case-flipping existing tests seems like something that can be cleaned
up years from now accidentally because it looks odd.Adding them into src/test/regress/ sounds like a good plan to me.
If there is interest in this patch now that the list exists and aids review, I
can turn the list into a proper test that makes a little more sense than the
current list which is rather aimed at helping reviewers.
If you however combine the new and old syntax, the statement works and the WITH
option wins by overwriting any previous value. The below statement creates an
IMMUTABLE function:create function int42(cstring) returns int42 AS 'int4in'
language internal strict volatile with (isstrict, iscachable);Here is another idea: nuking isstrict and iscachable from CREATE
FUNCTION syntax and forget about them. I would be tempted of the opinion
to do that before the rest.
Thats certainly an option, I have no idea about the prevalence in real life
production environments to have much an opinion to offer.
-old_aggr_elem: IDENT '=' def_arg +old_aggr_elem: PARALLEL '=' def_arg + { + $$ = makeDefElem("parallel", (Node *)$3, @1); + } + | IDENT '=' def_arg Nit: alphabetical order.
Fixed.
I have spent a couple of hours reviewing all the calls to pg_strcasecmp,
and the only thing I have noticed is in transformRelOptions(), where the
namespace string should be evaluated as well by strcmp, no?
<snip>
So per my set of examples, the evaluation of the schema name should fail
when creating relation a3 with your patch applied. As the patch does
things, the experience for the user is not consistent, and the schema
name goes through parser via reloption_elem using makeDefElemExtended,
so this should use strcmp.
I believe you are entirely correct, the attached v5 patch is updated with this
behavior. The volatility patch is unchanged by this so didn’t submit a new
version of that one.
Thanks for the review!
cheers ./daniel
Attachments:
defname_strcmp-v5.patchapplication/octet-stream; name=defname_strcmp-v5.patchDownload
From 528be70e7d64ecbe29ef0a5ed357abddeeb672bf Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <daniel@yesql.se>
Date: Wed, 10 Jan 2018 23:26:45 +0100
Subject: [PATCH 1/2] Use strcmp() instead of pg_strcasecmp() for identifier
matching
Since these option values are parsed using either the IDENT rule,
via keyword rules, or are created in lowercase with makeString(),
using strcmp() is the correct approach here. While not wrong per
se, using case insensitive matching can hide subtle bugs in case
defnames are created with mixed-case as these options otherwise
are assumed to always be lowercased.
The parsing of the PARALLEL option in the old style syntax for
CREATE AGGREGATE was fixed to allow using strcmp as well.
Reorder a few checks while in there such that all checks are in
the same order to make it easier to grep/read.
Also remove comment in tsearchcmds.c:getTokenTypes() regarding
strcmp/pg_strcasecmp as the code is correct. token_type is parsed
using the IDENT rule and will always be in lowercase.
---
contrib/dict_int/dict_int.c | 4 +--
contrib/dict_xsyn/dict_xsyn.c | 10 +++---
contrib/unaccent/unaccent.c | 2 +-
doc/src/sgml/ref/create_aggregate.sgml | 1 +
doc/src/sgml/ref/create_function.sgml | 1 -
src/backend/access/common/reloptions.c | 18 +++++-----
src/backend/commands/aggregatecmds.c | 56 ++++++++++++++++----------------
src/backend/commands/collationcmds.c | 12 +++----
src/backend/commands/functioncmds.c | 6 ++++
src/backend/commands/operatorcmds.c | 44 ++++++++++++-------------
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/tsearchcmds.c | 23 +++++++------
src/backend/commands/typecmds.c | 48 +++++++++++++--------------
src/backend/commands/view.c | 6 ++--
src/backend/parser/gram.y | 10 ++++--
src/backend/parser/parse_clause.c | 2 +-
src/backend/snowball/dict_snowball.c | 4 +--
src/backend/tsearch/dict_ispell.c | 6 ++--
src/backend/tsearch/dict_simple.c | 4 +--
src/backend/tsearch/dict_synonym.c | 4 +--
src/backend/tsearch/dict_thesaurus.c | 4 +--
src/test/regress/expected/aggregates.out | 4 +--
src/test/regress/sql/aggregates.sql | 4 +--
23 files changed, 141 insertions(+), 134 deletions(-)
diff --git a/contrib/dict_int/dict_int.c b/contrib/dict_int/dict_int.c
index 8b45532938..56ede37089 100644
--- a/contrib/dict_int/dict_int.c
+++ b/contrib/dict_int/dict_int.c
@@ -42,11 +42,11 @@ dintdict_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "MAXLEN") == 0)
+ if (strcmp(defel->defname, "maxlen") == 0)
{
d->maxlen = atoi(defGetString(defel));
}
- else if (pg_strcasecmp(defel->defname, "REJECTLONG") == 0)
+ else if (strcmp(defel->defname, "rejectlong") == 0)
{
d->rejectlong = defGetBoolean(defel);
}
diff --git a/contrib/dict_xsyn/dict_xsyn.c b/contrib/dict_xsyn/dict_xsyn.c
index 8a3abf7e3c..a79ece240c 100644
--- a/contrib/dict_xsyn/dict_xsyn.c
+++ b/contrib/dict_xsyn/dict_xsyn.c
@@ -157,23 +157,23 @@ dxsyn_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "MATCHORIG") == 0)
+ if (strcmp(defel->defname, "matchorig") == 0)
{
d->matchorig = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "KEEPORIG") == 0)
+ else if (strcmp(defel->defname, "keeporig") == 0)
{
d->keeporig = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "MATCHSYNONYMS") == 0)
+ else if (strcmp(defel->defname, "matchsynonyms") == 0)
{
d->matchsynonyms = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "KEEPSYNONYMS") == 0)
+ else if (strcmp(defel->defname, "keepsynonyms") == 0)
{
d->keepsynonyms = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "RULES") == 0)
+ else if (strcmp(defel->defname, "rules") == 0)
{
/* we can't read the rules before parsing all options! */
filename = defGetString(defel);
diff --git a/contrib/unaccent/unaccent.c b/contrib/unaccent/unaccent.c
index 82f9c7fcfe..247c202755 100644
--- a/contrib/unaccent/unaccent.c
+++ b/contrib/unaccent/unaccent.c
@@ -276,7 +276,7 @@ unaccent_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("Rules", defel->defname) == 0)
+ if (strcmp(defel->defname, "rules") == 0)
{
if (fileloaded)
ereport(ERROR,
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index a4aaae876e..c46491991b 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -80,6 +80,7 @@ CREATE AGGREGATE <replaceable class="parameter">name</replaceable> (
[ , MFINALFUNC_MODIFY = { READ_ONLY | SHARABLE | READ_WRITE } ]
[ , MINITCOND = <replaceable class="parameter">minitial_condition</replaceable> ]
[ , SORTOP = <replaceable class="parameter">sort_operator</replaceable> ]
+ [ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ]
)
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml
index fd229d1193..869b8b396c 100644
--- a/doc/src/sgml/ref/create_function.sgml
+++ b/doc/src/sgml/ref/create_function.sgml
@@ -590,7 +590,6 @@ CREATE [ OR REPLACE ] FUNCTION
</variablelist>
- Attribute names are not case-sensitive.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 425bc5d06e..b037802a53 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -796,7 +796,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
}
else if (def->defnamespace == NULL)
continue;
- else if (pg_strcasecmp(def->defnamespace, namspace) != 0)
+ else if (strcmp(def->defnamespace, namspace) != 0)
continue;
kw_len = strlen(def->defname);
@@ -849,8 +849,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
{
for (i = 0; validnsps[i]; i++)
{
- if (pg_strcasecmp(def->defnamespace,
- validnsps[i]) == 0)
+ if (strcmp(def->defnamespace, validnsps[i]) == 0)
{
valid = true;
break;
@@ -865,7 +864,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
def->defnamespace)));
}
- if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
+ if (ignoreOids && strcmp(def->defname, "oids") == 0)
continue;
/* ignore if not in the same namespace */
@@ -876,7 +875,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
}
else if (def->defnamespace == NULL)
continue;
- else if (pg_strcasecmp(def->defnamespace, namspace) != 0)
+ else if (strcmp(def->defnamespace, namspace) != 0)
continue;
/*
@@ -1081,8 +1080,7 @@ parseRelOptions(Datum options, bool validate, relopt_kind kind,
int kw_len = reloptions[j].gen->namelen;
if (text_len > kw_len && text_str[kw_len] == '=' &&
- pg_strncasecmp(text_str, reloptions[j].gen->name,
- kw_len) == 0)
+ strncmp(text_str, reloptions[j].gen->name, kw_len) == 0)
{
parse_one_reloption(&reloptions[j], text_str, text_len,
validate);
@@ -1555,9 +1553,9 @@ AlterTableGetRelOptionsLockLevel(List *defList)
for (i = 0; relOpts[i]; i++)
{
- if (pg_strncasecmp(relOpts[i]->name,
- def->defname,
- relOpts[i]->namelen + 1) == 0)
+ if (strncmp(relOpts[i]->name,
+ def->defname,
+ relOpts[i]->namelen + 1) == 0)
{
if (lockmode < relOpts[i]->lockmode)
lockmode = relOpts[i]->lockmode;
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 15378a9d4d..ced80fb155 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -127,37 +127,37 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
* sfunc1, stype1, and initcond1 are accepted as obsolete spellings
* for sfunc, stype, initcond.
*/
- if (pg_strcasecmp(defel->defname, "sfunc") == 0)
+ if (strcmp(defel->defname, "sfunc") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
+ else if (strcmp(defel->defname, "sfunc1") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
+ else if (strcmp(defel->defname, "finalfunc") == 0)
finalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "combinefunc") == 0)
+ else if (strcmp(defel->defname, "combinefunc") == 0)
combinefuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "serialfunc") == 0)
+ else if (strcmp(defel->defname, "serialfunc") == 0)
serialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "deserialfunc") == 0)
+ else if (strcmp(defel->defname, "deserialfunc") == 0)
deserialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "msfunc") == 0)
+ else if (strcmp(defel->defname, "msfunc") == 0)
mtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "minvfunc") == 0)
+ else if (strcmp(defel->defname, "minvfunc") == 0)
minvtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc") == 0)
mfinalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "finalfunc_extra") == 0)
finalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
mfinalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_modify") == 0)
+ else if (strcmp(defel->defname, "finalfunc_modify") == 0)
finalfuncModify = extractModify(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_modify") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
mfinalfuncModify = extractModify(defel);
- else if (pg_strcasecmp(defel->defname, "sortop") == 0)
+ else if (strcmp(defel->defname, "sortop") == 0)
sortoperatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "basetype") == 0)
+ else if (strcmp(defel->defname, "basetype") == 0)
baseType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "hypothetical") == 0)
+ else if (strcmp(defel->defname, "hypothetical") == 0)
{
if (defGetBoolean(defel))
{
@@ -168,23 +168,23 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
aggKind = AGGKIND_HYPOTHETICAL;
}
}
- else if (pg_strcasecmp(defel->defname, "stype") == 0)
+ else if (strcmp(defel->defname, "stype") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "stype1") == 0)
+ else if (strcmp(defel->defname, "stype1") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "sspace") == 0)
+ else if (strcmp(defel->defname, "sspace") == 0)
transSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "mstype") == 0)
+ else if (strcmp(defel->defname, "mstype") == 0)
mtransType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "msspace") == 0)
+ else if (strcmp(defel->defname, "msspace") == 0)
mtransSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "initcond") == 0)
+ else if (strcmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
+ else if (strcmp(defel->defname, "initcond1") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "minitcond") == 0)
+ else if (strcmp(defel->defname, "minitcond") == 0)
minitval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "parallel") == 0)
+ else if (strcmp(defel->defname, "parallel") == 0)
parallel = defGetString(defel);
else
ereport(WARNING,
@@ -420,11 +420,11 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
if (parallel)
{
- if (pg_strcasecmp(parallel, "safe") == 0)
+ if (strcmp(parallel, "safe") == 0)
proparallel = PROPARALLEL_SAFE;
- else if (pg_strcasecmp(parallel, "restricted") == 0)
+ else if (strcmp(parallel, "restricted") == 0)
proparallel = PROPARALLEL_RESTRICTED;
- else if (pg_strcasecmp(parallel, "unsafe") == 0)
+ else if (strcmp(parallel, "unsafe") == 0)
proparallel = PROPARALLEL_UNSAFE;
else
ereport(ERROR,
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index 6c6877395f..35fd0c64e2 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -82,17 +82,17 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
DefElem *defel = lfirst_node(DefElem, pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "from") == 0)
+ if (strcmp(defel->defname, "from") == 0)
defelp = &fromEl;
- else if (pg_strcasecmp(defel->defname, "locale") == 0)
+ else if (strcmp(defel->defname, "locale") == 0)
defelp = &localeEl;
- else if (pg_strcasecmp(defel->defname, "lc_collate") == 0)
+ else if (strcmp(defel->defname, "lc_collate") == 0)
defelp = &lccollateEl;
- else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0)
+ else if (strcmp(defel->defname, "lc_ctype") == 0)
defelp = &lcctypeEl;
- else if (pg_strcasecmp(defel->defname, "provider") == 0)
+ else if (strcmp(defel->defname, "provider") == 0)
defelp = &providerEl;
- else if (pg_strcasecmp(defel->defname, "version") == 0)
+ else if (strcmp(defel->defname, "version") == 0)
defelp = &versionEl;
else
{
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 12ab33f418..8eed5a0166 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -811,6 +811,12 @@ compute_attributes_with_style(ParseState *pstate, bool is_procedure, List *param
{
DefElem *param = (DefElem *) lfirst(pl);
+ /*
+ * Attribute names from the parser should always be in casefolded into
+ * lowercase, but for the old attributes isStrict and isCachable the
+ * manual has since 7.3 stated that they are not case-sensitive so for
+ * now use pg_strcasecmp().
+ */
if (pg_strcasecmp(param->defname, "isstrict") == 0)
{
if (is_procedure)
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 81ef532184..70090b9b97 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -105,7 +105,7 @@ DefineOperator(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "leftarg") == 0)
+ if (strcmp(defel->defname, "leftarg") == 0)
{
typeName1 = defGetTypeName(defel);
if (typeName1->setof)
@@ -113,7 +113,7 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
+ else if (strcmp(defel->defname, "rightarg") == 0)
{
typeName2 = defGetTypeName(defel);
if (typeName2->setof)
@@ -121,28 +121,28 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "procedure") == 0)
+ else if (strcmp(defel->defname, "procedure") == 0)
functionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "commutator") == 0)
+ else if (strcmp(defel->defname, "commutator") == 0)
commutatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "negator") == 0)
+ else if (strcmp(defel->defname, "negator") == 0)
negatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ else if (strcmp(defel->defname, "restrict") == 0)
restrictionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
joinName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "hashes") == 0)
+ else if (strcmp(defel->defname, "hashes") == 0)
canHash = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "merges") == 0)
canMerge = defGetBoolean(defel);
/* These obsolete options are taken as meaning canMerge */
- else if (pg_strcasecmp(defel->defname, "sort1") == 0)
+ else if (strcmp(defel->defname, "sort1") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "sort2") == 0)
+ else if (strcmp(defel->defname, "sort2") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
+ else if (strcmp(defel->defname, "ltcmp") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
+ else if (strcmp(defel->defname, "gtcmp") == 0)
canMerge = true;
else
{
@@ -420,12 +420,12 @@ AlterOperator(AlterOperatorStmt *stmt)
else
param = defGetQualifiedName(defel);
- if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ if (strcmp(defel->defname, "restrict") == 0)
{
restrictionName = param;
updateRestriction = true;
}
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
{
joinName = param;
updateJoin = true;
@@ -435,13 +435,13 @@ AlterOperator(AlterOperatorStmt *stmt)
* The rest of the options that CREATE accepts cannot be changed.
* Check for them so that we can give a meaningful error message.
*/
- else if (pg_strcasecmp(defel->defname, "leftarg") == 0 ||
- pg_strcasecmp(defel->defname, "rightarg") == 0 ||
- pg_strcasecmp(defel->defname, "procedure") == 0 ||
- pg_strcasecmp(defel->defname, "commutator") == 0 ||
- pg_strcasecmp(defel->defname, "negator") == 0 ||
- pg_strcasecmp(defel->defname, "hashes") == 0 ||
- pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "leftarg") == 0 ||
+ strcmp(defel->defname, "rightarg") == 0 ||
+ strcmp(defel->defname, "procedure") == 0 ||
+ strcmp(defel->defname, "commutator") == 0 ||
+ strcmp(defel->defname, "negator") == 0 ||
+ strcmp(defel->defname, "hashes") == 0 ||
+ strcmp(defel->defname, "merges") == 0)
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f2a928b823..2e10b5c7ee 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -10449,7 +10449,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index bf06ed9318..4642c9fe8a 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -209,27 +209,27 @@ DefineTSParser(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "start") == 0)
+ if (strcmp(defel->defname, "start") == 0)
{
values[Anum_pg_ts_parser_prsstart - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
}
- else if (pg_strcasecmp(defel->defname, "gettoken") == 0)
+ else if (strcmp(defel->defname, "gettoken") == 0)
{
values[Anum_pg_ts_parser_prstoken - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
}
- else if (pg_strcasecmp(defel->defname, "end") == 0)
+ else if (strcmp(defel->defname, "end") == 0)
{
values[Anum_pg_ts_parser_prsend - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
}
- else if (pg_strcasecmp(defel->defname, "headline") == 0)
+ else if (strcmp(defel->defname, "headline") == 0)
{
values[Anum_pg_ts_parser_prsheadline - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
}
- else if (pg_strcasecmp(defel->defname, "lextypes") == 0)
+ else if (strcmp(defel->defname, "lextypes") == 0)
{
values[Anum_pg_ts_parser_prslextype - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
@@ -438,7 +438,7 @@ DefineTSDictionary(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "template") == 0)
+ if (strcmp(defel->defname, "template") == 0)
{
templId = get_ts_template_oid(defGetQualifiedName(defel), false);
}
@@ -580,7 +580,7 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
DefElem *oldel = (DefElem *) lfirst(cell);
next = lnext(cell);
- if (pg_strcasecmp(oldel->defname, defel->defname) == 0)
+ if (strcmp(oldel->defname, defel->defname) == 0)
dictoptions = list_delete_cell(dictoptions, cell, prev);
else
prev = cell;
@@ -765,13 +765,13 @@ DefineTSTemplate(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "init") == 0)
+ if (strcmp(defel->defname, "init") == 0)
{
values[Anum_pg_ts_template_tmplinit - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
nulls[Anum_pg_ts_template_tmplinit - 1] = false;
}
- else if (pg_strcasecmp(defel->defname, "lexize") == 0)
+ else if (strcmp(defel->defname, "lexize") == 0)
{
values[Anum_pg_ts_template_tmpllexize - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
@@ -990,9 +990,9 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "parser") == 0)
+ if (strcmp(defel->defname, "parser") == 0)
prsOid = get_ts_parser_oid(defGetQualifiedName(defel), false);
- else if (pg_strcasecmp(defel->defname, "copy") == 0)
+ else if (strcmp(defel->defname, "copy") == 0)
sourceOid = get_ts_config_oid(defGetQualifiedName(defel), false);
else
ereport(ERROR,
@@ -1251,7 +1251,6 @@ getTokenTypes(Oid prsId, List *tokennames)
j = 0;
while (list && list[j].lexid)
{
- /* XXX should we use pg_strcasecmp here? */
if (strcmp(strVal(val), list[j].alias) == 0)
{
res[i] = list[j].lexid;
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index a40b3cf752..94d6a17ed3 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -245,42 +245,42 @@ DefineType(ParseState *pstate, List *names, List *parameters)
DefElem *defel = (DefElem *) lfirst(pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "like") == 0)
+ if (strcmp(defel->defname, "like") == 0)
defelp = &likeTypeEl;
- else if (pg_strcasecmp(defel->defname, "internallength") == 0)
+ else if (strcmp(defel->defname, "internallength") == 0)
defelp = &internalLengthEl;
- else if (pg_strcasecmp(defel->defname, "input") == 0)
+ else if (strcmp(defel->defname, "input") == 0)
defelp = &inputNameEl;
- else if (pg_strcasecmp(defel->defname, "output") == 0)
+ else if (strcmp(defel->defname, "output") == 0)
defelp = &outputNameEl;
- else if (pg_strcasecmp(defel->defname, "receive") == 0)
+ else if (strcmp(defel->defname, "receive") == 0)
defelp = &receiveNameEl;
- else if (pg_strcasecmp(defel->defname, "send") == 0)
+ else if (strcmp(defel->defname, "send") == 0)
defelp = &sendNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
+ else if (strcmp(defel->defname, "typmod_in") == 0)
defelp = &typmodinNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
+ else if (strcmp(defel->defname, "typmod_out") == 0)
defelp = &typmodoutNameEl;
- else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
- pg_strcasecmp(defel->defname, "analyse") == 0)
+ else if (strcmp(defel->defname, "analyze") == 0 ||
+ strcmp(defel->defname, "analyse") == 0)
defelp = &analyzeNameEl;
- else if (pg_strcasecmp(defel->defname, "category") == 0)
+ else if (strcmp(defel->defname, "category") == 0)
defelp = &categoryEl;
- else if (pg_strcasecmp(defel->defname, "preferred") == 0)
+ else if (strcmp(defel->defname, "preferred") == 0)
defelp = &preferredEl;
- else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
+ else if (strcmp(defel->defname, "delimiter") == 0)
defelp = &delimiterEl;
- else if (pg_strcasecmp(defel->defname, "element") == 0)
+ else if (strcmp(defel->defname, "element") == 0)
defelp = &elemTypeEl;
- else if (pg_strcasecmp(defel->defname, "default") == 0)
+ else if (strcmp(defel->defname, "default") == 0)
defelp = &defaultValueEl;
- else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
+ else if (strcmp(defel->defname, "passedbyvalue") == 0)
defelp = &byValueEl;
- else if (pg_strcasecmp(defel->defname, "alignment") == 0)
+ else if (strcmp(defel->defname, "alignment") == 0)
defelp = &alignmentEl;
- else if (pg_strcasecmp(defel->defname, "storage") == 0)
+ else if (strcmp(defel->defname, "storage") == 0)
defelp = &storageEl;
- else if (pg_strcasecmp(defel->defname, "collatable") == 0)
+ else if (strcmp(defel->defname, "collatable") == 0)
defelp = &collatableEl;
else
{
@@ -1439,7 +1439,7 @@ DefineRange(CreateRangeStmt *stmt)
{
DefElem *defel = (DefElem *) lfirst(lc);
- if (pg_strcasecmp(defel->defname, "subtype") == 0)
+ if (strcmp(defel->defname, "subtype") == 0)
{
if (OidIsValid(rangeSubtype))
ereport(ERROR,
@@ -1448,7 +1448,7 @@ DefineRange(CreateRangeStmt *stmt)
/* we can look up the subtype name immediately */
rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
}
- else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
+ else if (strcmp(defel->defname, "subtype_opclass") == 0)
{
if (rangeSubOpclassName != NIL)
ereport(ERROR,
@@ -1456,7 +1456,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeSubOpclassName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "collation") == 0)
+ else if (strcmp(defel->defname, "collation") == 0)
{
if (rangeCollationName != NIL)
ereport(ERROR,
@@ -1464,7 +1464,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCollationName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "canonical") == 0)
+ else if (strcmp(defel->defname, "canonical") == 0)
{
if (rangeCanonicalName != NIL)
ereport(ERROR,
@@ -1472,7 +1472,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCanonicalName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
+ else if (strcmp(defel->defname, "subtype_diff") == 0)
{
if (rangeSubtypeDiffName != NIL)
ereport(ERROR,
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 04ad76a210..7d4511c585 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -46,8 +46,8 @@ void
validateWithCheckOption(const char *value)
{
if (value == NULL ||
- (pg_strcasecmp(value, "local") != 0 &&
- pg_strcasecmp(value, "cascaded") != 0))
+ (strcmp(value, "local") != 0 &&
+ strcmp(value, "cascaded") != 0))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -485,7 +485,7 @@ DefineView(ViewStmt *stmt, const char *queryString,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e42b7caff6..e1197dea50 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -5823,14 +5823,18 @@ old_aggr_list: old_aggr_elem { $$ = list_make1($1); }
;
/*
- * Must use IDENT here to avoid reduce/reduce conflicts; fortunately none of
- * the item names needed in old aggregate definitions are likely to become
- * SQL keywords.
+ * Must use IDENT here to avoid reduce/reduce conflicts; fortunately, with
+ * the exception of PARALLEL, none of the item names needed in old aggregate
+ * definitions are likely to become keywords.
*/
old_aggr_elem: IDENT '=' def_arg
{
$$ = makeDefElem($1, (Node *)$3, @1);
}
+ | PARALLEL '=' def_arg
+ {
+ $$ = makeDefElem("parallel", (Node *)$3, @1);
+ }
;
opt_enum_val_list:
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 9fbcfd4fa6..406cd1dad0 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -262,7 +262,7 @@ interpretOidsOption(List *defList, bool allowOids)
DefElem *def = (DefElem *) lfirst(cell);
if (def->defnamespace == NULL &&
- pg_strcasecmp(def->defname, "oids") == 0)
+ strcmp(def->defname, "oids") == 0)
{
if (!allowOids)
ereport(ERROR,
diff --git a/src/backend/snowball/dict_snowball.c b/src/backend/snowball/dict_snowball.c
index 043681ec2d..78c9f73ef0 100644
--- a/src/backend/snowball/dict_snowball.c
+++ b/src/backend/snowball/dict_snowball.c
@@ -192,7 +192,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -201,7 +201,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Language", defel->defname) == 0)
+ else if (strcmp(defel->defname, "language") == 0)
{
if (d->stem)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_ispell.c b/src/backend/tsearch/dict_ispell.c
index 0d706795ad..edc6547700 100644
--- a/src/backend/tsearch/dict_ispell.c
+++ b/src/backend/tsearch/dict_ispell.c
@@ -44,7 +44,7 @@ dispell_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "DictFile") == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (dictloaded)
ereport(ERROR,
@@ -55,7 +55,7 @@ dispell_init(PG_FUNCTION_ARGS)
"dict"));
dictloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "AffFile") == 0)
+ else if (strcmp(defel->defname, "afffile") == 0)
{
if (affloaded)
ereport(ERROR,
@@ -66,7 +66,7 @@ dispell_init(PG_FUNCTION_ARGS)
"affix"));
affloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "StopWords") == 0)
+ else if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_simple.c b/src/backend/tsearch/dict_simple.c
index 268b4e48cf..ac6a24eba5 100644
--- a/src/backend/tsearch/dict_simple.c
+++ b/src/backend/tsearch/dict_simple.c
@@ -41,7 +41,7 @@ dsimple_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -50,7 +50,7 @@ dsimple_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Accept", defel->defname) == 0)
+ else if (strcmp(defel->defname, "accept") == 0)
{
if (acceptloaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_synonym.c b/src/backend/tsearch/dict_synonym.c
index 8ca65f3ded..c011886cb0 100644
--- a/src/backend/tsearch/dict_synonym.c
+++ b/src/backend/tsearch/dict_synonym.c
@@ -108,9 +108,9 @@ dsynonym_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("Synonyms", defel->defname) == 0)
+ if (strcmp(defel->defname, "synonyms") == 0)
filename = defGetString(defel);
- else if (pg_strcasecmp("CaseSensitive", defel->defname) == 0)
+ else if (strcmp(defel->defname, "casesensitive") == 0)
case_sensitive = defGetBoolean(defel);
else
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_thesaurus.c b/src/backend/tsearch/dict_thesaurus.c
index 23aaac8d07..24364e646d 100644
--- a/src/backend/tsearch/dict_thesaurus.c
+++ b/src/backend/tsearch/dict_thesaurus.c
@@ -616,7 +616,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("DictFile", defel->defname) == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (fileloaded)
ereport(ERROR,
@@ -625,7 +625,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
thesaurusRead(defGetString(defel), d);
fileloaded = true;
}
- else if (pg_strcasecmp("Dictionary", defel->defname) == 0)
+ else if (strcmp(defel->defname, "dictionary") == 0)
{
if (subdictname)
ereport(ERROR,
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out
index dbce7d3e8b..81943f3396 100644
--- a/src/test/regress/expected/aggregates.out
+++ b/src/test/regress/expected/aggregates.out
@@ -2011,7 +2011,7 @@ CREATE AGGREGATE balk(
BASETYPE = int4,
SFUNC = balkifnull(int8, int4),
STYPE = int8,
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0');
SELECT balk(hundred) FROM tenk1;
balk
@@ -2040,7 +2040,7 @@ CREATE AGGREGATE balk(
SFUNC = int4_sum(int8, int4),
STYPE = int8,
COMBINEFUNC = balkifnull(int8, int8),
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0'
);
-- force use of parallelism
diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql
index 6c9b86a616..6833b7ffce 100644
--- a/src/test/regress/sql/aggregates.sql
+++ b/src/test/regress/sql/aggregates.sql
@@ -865,7 +865,7 @@ CREATE AGGREGATE balk(
BASETYPE = int4,
SFUNC = balkifnull(int8, int4),
STYPE = int8,
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0');
SELECT balk(hundred) FROM tenk1;
@@ -893,7 +893,7 @@ CREATE AGGREGATE balk(
SFUNC = int4_sum(int8, int4),
STYPE = int8,
COMBINEFUNC = balkifnull(int8, int8),
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0'
);
--
2.14.1.145.gb3622a4ee
On Fri, Jan 12, 2018 at 11:35:48PM +0100, Daniel Gustafsson wrote:
On 11 Jan 2018, at 09:01, Michael Paquier <michael.paquier@gmail.com> wrote:
I would like to think that a special section
dedicated to option compatibility for each command would be welcome to
track which grammar is supported and which grammar is not supported.I’m not sure I follow?
One open question from this excercise is how to write a good test for
this. It can either be made part of the already existing test queries
or a separate suite. I’m leaning on the latter simply because the
case-flipping existing tests seems like something that can be cleaned
up years from now accidentally because it looks odd.Adding them into src/test/regress/ sounds like a good plan to me.
If there is interest in this patch now that the list exists and aids review, I
can turn the list into a proper test that makes a little more sense than the
current list which is rather aimed at helping reviewers.
Sorry if my words were hard to catch here. What I mean here is to add in
each command's test file the set of commands which check the
compatibility. There is no need to test all the options in my opinion,
as just testing one option is enoughto show the purpose. So for example
to cover the grounds of DefineAggregate(), you could add a set of
commands in create_aggregate.sql. For DefineCollation(), those can go in
collate.sql, etc.
Here is another idea: nuking isstrict and iscachable from CREATE
FUNCTION syntax and forget about them. I would be tempted of the opinion
to do that before the rest.Thats certainly an option, I have no idea about the prevalence in real life
production environments to have much an opinion to offer.
Please let me raise a new thread about this point with a proper
patch. That's rather separate to the work you are doing here, even if
those parameters are using pg_strcasecmp().
--
Michael
On 15 Jan 2018, at 02:33, Michael Paquier <michael.paquier@gmail.com> wrote:
On Fri, Jan 12, 2018 at 11:35:48PM +0100, Daniel Gustafsson wrote:On 11 Jan 2018, at 09:01, Michael Paquier <michael.paquier@gmail.com> wrote:
One open question from this excercise is how to write a good test for
this. It can either be made part of the already existing test queries
or a separate suite. I’m leaning on the latter simply because the
case-flipping existing tests seems like something that can be cleaned
up years from now accidentally because it looks odd.Adding them into src/test/regress/ sounds like a good plan to me.
If there is interest in this patch now that the list exists and aids review, I
can turn the list into a proper test that makes a little more sense than the
current list which is rather aimed at helping reviewers.Sorry if my words were hard to catch here. What I mean here is to add in
each command's test file the set of commands which check the
compatibility. There is no need to test all the options in my opinion,
as just testing one option is enoughto show the purpose. So for example
to cover the grounds of DefineAggregate(), you could add a set of
commands in create_aggregate.sql. For DefineCollation(), those can go in
collate.sql, etc.
Gotcha. I’ve added some tests to the patch. The test for CREATE FUNCTION was
omitted for now awaiting the outcome of the discussion around isStrict
isCachable.
Not sure how much they’re worth in "make check” though as it’s quite easy to
add a new option checked with pg_strcasecmp which then isn’t tested. Still, it
might aid review so definitely worth it.
cheers ./daniel
Attachments:
defname_strcmp-v6.patchapplication/octet-stream; name=defname_strcmp-v6.patchDownload
From 3df6b46c313333f897dec3e2455a6fe1b75893b2 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <daniel@yesql.se>
Date: Wed, 10 Jan 2018 23:26:45 +0100
Subject: [PATCH 1/2] Use strcmp() instead of pg_strcasecmp() for identifier
matching
Since these option values are parsed using either the IDENT rule,
via keyword rules, or are created in lowercase with makeString(),
using strcmp() is the correct approach here. While not wrong per
se, using case insensitive matching can hide subtle bugs in case
defnames are created with mixed-case as these options otherwise
are assumed to always be lowercased.
The parsing of the PARALLEL option in the old style syntax for
CREATE AGGREGATE was fixed to allow using strcmp as well.
Reorder a few checks while in there such that all checks are in
the same order to make it easier to grep/read.
Also remove comment in tsearchcmds.c:getTokenTypes() regarding
strcmp/pg_strcasecmp as the code is correct. token_type is parsed
using the IDENT rule and will always be in lowercase.
---
contrib/dict_int/dict_int.c | 4 +-
contrib/dict_xsyn/dict_xsyn.c | 10 ++---
contrib/unaccent/unaccent.c | 2 +-
doc/src/sgml/ref/create_aggregate.sgml | 1 +
doc/src/sgml/ref/create_function.sgml | 1 -
src/backend/access/common/reloptions.c | 18 ++++-----
src/backend/commands/aggregatecmds.c | 56 +++++++++++++-------------
src/backend/commands/collationcmds.c | 12 +++---
src/backend/commands/functioncmds.c | 6 +++
src/backend/commands/operatorcmds.c | 44 ++++++++++----------
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/tsearchcmds.c | 23 +++++------
src/backend/commands/typecmds.c | 48 +++++++++++-----------
src/backend/commands/view.c | 6 +--
src/backend/parser/gram.y | 10 +++--
src/backend/parser/parse_clause.c | 2 +-
src/backend/snowball/dict_snowball.c | 4 +-
src/backend/tsearch/dict_ispell.c | 6 +--
src/backend/tsearch/dict_simple.c | 4 +-
src/backend/tsearch/dict_synonym.c | 4 +-
src/backend/tsearch/dict_thesaurus.c | 4 +-
src/test/regress/expected/aggregates.out | 4 +-
src/test/regress/expected/alter_generic.out | 6 +++
src/test/regress/expected/alter_operator.out | 3 ++
src/test/regress/expected/collate.out | 5 +++
src/test/regress/expected/create_aggregate.out | 30 ++++++++++++++
src/test/regress/expected/create_operator.out | 23 +++++++++++
src/test/regress/expected/create_table.out | 3 ++
src/test/regress/expected/create_type.out | 28 +++++++++++++
src/test/regress/expected/tsdicts.out | 10 +++++
src/test/regress/sql/aggregates.sql | 4 +-
src/test/regress/sql/alter_generic.sql | 6 +++
src/test/regress/sql/alter_operator.sql | 3 ++
src/test/regress/sql/collate.sql | 2 +
src/test/regress/sql/create_aggregate.sql | 19 +++++++++
src/test/regress/sql/create_operator.sql | 14 +++++++
src/test/regress/sql/create_table.sql | 3 ++
src/test/regress/sql/create_type.sql | 11 +++++
src/test/regress/sql/tsdicts.sql | 10 +++++
39 files changed, 317 insertions(+), 134 deletions(-)
diff --git a/contrib/dict_int/dict_int.c b/contrib/dict_int/dict_int.c
index 8b45532938..56ede37089 100644
--- a/contrib/dict_int/dict_int.c
+++ b/contrib/dict_int/dict_int.c
@@ -42,11 +42,11 @@ dintdict_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "MAXLEN") == 0)
+ if (strcmp(defel->defname, "maxlen") == 0)
{
d->maxlen = atoi(defGetString(defel));
}
- else if (pg_strcasecmp(defel->defname, "REJECTLONG") == 0)
+ else if (strcmp(defel->defname, "rejectlong") == 0)
{
d->rejectlong = defGetBoolean(defel);
}
diff --git a/contrib/dict_xsyn/dict_xsyn.c b/contrib/dict_xsyn/dict_xsyn.c
index 8a3abf7e3c..a79ece240c 100644
--- a/contrib/dict_xsyn/dict_xsyn.c
+++ b/contrib/dict_xsyn/dict_xsyn.c
@@ -157,23 +157,23 @@ dxsyn_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "MATCHORIG") == 0)
+ if (strcmp(defel->defname, "matchorig") == 0)
{
d->matchorig = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "KEEPORIG") == 0)
+ else if (strcmp(defel->defname, "keeporig") == 0)
{
d->keeporig = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "MATCHSYNONYMS") == 0)
+ else if (strcmp(defel->defname, "matchsynonyms") == 0)
{
d->matchsynonyms = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "KEEPSYNONYMS") == 0)
+ else if (strcmp(defel->defname, "keepsynonyms") == 0)
{
d->keepsynonyms = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "RULES") == 0)
+ else if (strcmp(defel->defname, "rules") == 0)
{
/* we can't read the rules before parsing all options! */
filename = defGetString(defel);
diff --git a/contrib/unaccent/unaccent.c b/contrib/unaccent/unaccent.c
index 82f9c7fcfe..247c202755 100644
--- a/contrib/unaccent/unaccent.c
+++ b/contrib/unaccent/unaccent.c
@@ -276,7 +276,7 @@ unaccent_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("Rules", defel->defname) == 0)
+ if (strcmp(defel->defname, "rules") == 0)
{
if (fileloaded)
ereport(ERROR,
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index a4aaae876e..c46491991b 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -80,6 +80,7 @@ CREATE AGGREGATE <replaceable class="parameter">name</replaceable> (
[ , MFINALFUNC_MODIFY = { READ_ONLY | SHARABLE | READ_WRITE } ]
[ , MINITCOND = <replaceable class="parameter">minitial_condition</replaceable> ]
[ , SORTOP = <replaceable class="parameter">sort_operator</replaceable> ]
+ [ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ]
)
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml
index fd229d1193..869b8b396c 100644
--- a/doc/src/sgml/ref/create_function.sgml
+++ b/doc/src/sgml/ref/create_function.sgml
@@ -590,7 +590,6 @@ CREATE [ OR REPLACE ] FUNCTION
</variablelist>
- Attribute names are not case-sensitive.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 274f7aa8e9..a6de891eec 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -796,7 +796,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
}
else if (def->defnamespace == NULL)
continue;
- else if (pg_strcasecmp(def->defnamespace, namspace) != 0)
+ else if (strcmp(def->defnamespace, namspace) != 0)
continue;
kw_len = strlen(def->defname);
@@ -849,8 +849,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
{
for (i = 0; validnsps[i]; i++)
{
- if (pg_strcasecmp(def->defnamespace,
- validnsps[i]) == 0)
+ if (strcmp(def->defnamespace, validnsps[i]) == 0)
{
valid = true;
break;
@@ -865,7 +864,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
def->defnamespace)));
}
- if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
+ if (ignoreOids && strcmp(def->defname, "oids") == 0)
continue;
/* ignore if not in the same namespace */
@@ -876,7 +875,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
}
else if (def->defnamespace == NULL)
continue;
- else if (pg_strcasecmp(def->defnamespace, namspace) != 0)
+ else if (strcmp(def->defnamespace, namspace) != 0)
continue;
/*
@@ -1082,8 +1081,7 @@ parseRelOptions(Datum options, bool validate, relopt_kind kind,
int kw_len = reloptions[j].gen->namelen;
if (text_len > kw_len && text_str[kw_len] == '=' &&
- pg_strncasecmp(text_str, reloptions[j].gen->name,
- kw_len) == 0)
+ strncmp(text_str, reloptions[j].gen->name, kw_len) == 0)
{
parse_one_reloption(&reloptions[j], text_str, text_len,
validate);
@@ -1556,9 +1554,9 @@ AlterTableGetRelOptionsLockLevel(List *defList)
for (i = 0; relOpts[i]; i++)
{
- if (pg_strncasecmp(relOpts[i]->name,
- def->defname,
- relOpts[i]->namelen + 1) == 0)
+ if (strncmp(relOpts[i]->name,
+ def->defname,
+ relOpts[i]->namelen + 1) == 0)
{
if (lockmode < relOpts[i]->lockmode)
lockmode = relOpts[i]->lockmode;
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 1779ba7bcb..a48c3ac572 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -127,37 +127,37 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
* sfunc1, stype1, and initcond1 are accepted as obsolete spellings
* for sfunc, stype, initcond.
*/
- if (pg_strcasecmp(defel->defname, "sfunc") == 0)
+ if (strcmp(defel->defname, "sfunc") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
+ else if (strcmp(defel->defname, "sfunc1") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
+ else if (strcmp(defel->defname, "finalfunc") == 0)
finalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "combinefunc") == 0)
+ else if (strcmp(defel->defname, "combinefunc") == 0)
combinefuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "serialfunc") == 0)
+ else if (strcmp(defel->defname, "serialfunc") == 0)
serialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "deserialfunc") == 0)
+ else if (strcmp(defel->defname, "deserialfunc") == 0)
deserialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "msfunc") == 0)
+ else if (strcmp(defel->defname, "msfunc") == 0)
mtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "minvfunc") == 0)
+ else if (strcmp(defel->defname, "minvfunc") == 0)
minvtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc") == 0)
mfinalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "finalfunc_extra") == 0)
finalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
mfinalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_modify") == 0)
+ else if (strcmp(defel->defname, "finalfunc_modify") == 0)
finalfuncModify = extractModify(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_modify") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
mfinalfuncModify = extractModify(defel);
- else if (pg_strcasecmp(defel->defname, "sortop") == 0)
+ else if (strcmp(defel->defname, "sortop") == 0)
sortoperatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "basetype") == 0)
+ else if (strcmp(defel->defname, "basetype") == 0)
baseType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "hypothetical") == 0)
+ else if (strcmp(defel->defname, "hypothetical") == 0)
{
if (defGetBoolean(defel))
{
@@ -168,23 +168,23 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
aggKind = AGGKIND_HYPOTHETICAL;
}
}
- else if (pg_strcasecmp(defel->defname, "stype") == 0)
+ else if (strcmp(defel->defname, "stype") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "stype1") == 0)
+ else if (strcmp(defel->defname, "stype1") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "sspace") == 0)
+ else if (strcmp(defel->defname, "sspace") == 0)
transSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "mstype") == 0)
+ else if (strcmp(defel->defname, "mstype") == 0)
mtransType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "msspace") == 0)
+ else if (strcmp(defel->defname, "msspace") == 0)
mtransSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "initcond") == 0)
+ else if (strcmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
+ else if (strcmp(defel->defname, "initcond1") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "minitcond") == 0)
+ else if (strcmp(defel->defname, "minitcond") == 0)
minitval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "parallel") == 0)
+ else if (strcmp(defel->defname, "parallel") == 0)
parallel = defGetString(defel);
else
ereport(WARNING,
@@ -420,11 +420,11 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
if (parallel)
{
- if (pg_strcasecmp(parallel, "safe") == 0)
+ if (strcmp(parallel, "safe") == 0)
proparallel = PROPARALLEL_SAFE;
- else if (pg_strcasecmp(parallel, "restricted") == 0)
+ else if (strcmp(parallel, "restricted") == 0)
proparallel = PROPARALLEL_RESTRICTED;
- else if (pg_strcasecmp(parallel, "unsafe") == 0)
+ else if (strcmp(parallel, "unsafe") == 0)
proparallel = PROPARALLEL_UNSAFE;
else
ereport(ERROR,
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index fdfb3dcd2c..d0b5cdb69a 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -82,17 +82,17 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
DefElem *defel = lfirst_node(DefElem, pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "from") == 0)
+ if (strcmp(defel->defname, "from") == 0)
defelp = &fromEl;
- else if (pg_strcasecmp(defel->defname, "locale") == 0)
+ else if (strcmp(defel->defname, "locale") == 0)
defelp = &localeEl;
- else if (pg_strcasecmp(defel->defname, "lc_collate") == 0)
+ else if (strcmp(defel->defname, "lc_collate") == 0)
defelp = &lccollateEl;
- else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0)
+ else if (strcmp(defel->defname, "lc_ctype") == 0)
defelp = &lcctypeEl;
- else if (pg_strcasecmp(defel->defname, "provider") == 0)
+ else if (strcmp(defel->defname, "provider") == 0)
defelp = &providerEl;
- else if (pg_strcasecmp(defel->defname, "version") == 0)
+ else if (strcmp(defel->defname, "version") == 0)
defelp = &versionEl;
else
{
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index ea08c3237c..3ede99ef67 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -811,6 +811,12 @@ compute_attributes_with_style(ParseState *pstate, bool is_procedure, List *param
{
DefElem *param = (DefElem *) lfirst(pl);
+ /*
+ * Attribute names from the parser should always be in casefolded into
+ * lowercase, but for the old attributes isStrict and isCachable the
+ * manual has since 7.3 stated that they are not case-sensitive so for
+ * now use pg_strcasecmp().
+ */
if (pg_strcasecmp(param->defname, "isstrict") == 0)
{
if (is_procedure)
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 35404ac39a..585382d758 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -105,7 +105,7 @@ DefineOperator(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "leftarg") == 0)
+ if (strcmp(defel->defname, "leftarg") == 0)
{
typeName1 = defGetTypeName(defel);
if (typeName1->setof)
@@ -113,7 +113,7 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
+ else if (strcmp(defel->defname, "rightarg") == 0)
{
typeName2 = defGetTypeName(defel);
if (typeName2->setof)
@@ -121,28 +121,28 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "procedure") == 0)
+ else if (strcmp(defel->defname, "procedure") == 0)
functionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "commutator") == 0)
+ else if (strcmp(defel->defname, "commutator") == 0)
commutatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "negator") == 0)
+ else if (strcmp(defel->defname, "negator") == 0)
negatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ else if (strcmp(defel->defname, "restrict") == 0)
restrictionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
joinName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "hashes") == 0)
+ else if (strcmp(defel->defname, "hashes") == 0)
canHash = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "merges") == 0)
canMerge = defGetBoolean(defel);
/* These obsolete options are taken as meaning canMerge */
- else if (pg_strcasecmp(defel->defname, "sort1") == 0)
+ else if (strcmp(defel->defname, "sort1") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "sort2") == 0)
+ else if (strcmp(defel->defname, "sort2") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
+ else if (strcmp(defel->defname, "ltcmp") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
+ else if (strcmp(defel->defname, "gtcmp") == 0)
canMerge = true;
else
{
@@ -420,12 +420,12 @@ AlterOperator(AlterOperatorStmt *stmt)
else
param = defGetQualifiedName(defel);
- if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ if (strcmp(defel->defname, "restrict") == 0)
{
restrictionName = param;
updateRestriction = true;
}
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
{
joinName = param;
updateJoin = true;
@@ -435,13 +435,13 @@ AlterOperator(AlterOperatorStmt *stmt)
* The rest of the options that CREATE accepts cannot be changed.
* Check for them so that we can give a meaningful error message.
*/
- else if (pg_strcasecmp(defel->defname, "leftarg") == 0 ||
- pg_strcasecmp(defel->defname, "rightarg") == 0 ||
- pg_strcasecmp(defel->defname, "procedure") == 0 ||
- pg_strcasecmp(defel->defname, "commutator") == 0 ||
- pg_strcasecmp(defel->defname, "negator") == 0 ||
- pg_strcasecmp(defel->defname, "hashes") == 0 ||
- pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "leftarg") == 0 ||
+ strcmp(defel->defname, "rightarg") == 0 ||
+ strcmp(defel->defname, "procedure") == 0 ||
+ strcmp(defel->defname, "commutator") == 0 ||
+ strcmp(defel->defname, "negator") == 0 ||
+ strcmp(defel->defname, "hashes") == 0 ||
+ strcmp(defel->defname, "merges") == 0)
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 2e768dd5e4..ea03fd2ecf 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -10536,7 +10536,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index bdf3857ce4..3a843512d1 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -209,27 +209,27 @@ DefineTSParser(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "start") == 0)
+ if (strcmp(defel->defname, "start") == 0)
{
values[Anum_pg_ts_parser_prsstart - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
}
- else if (pg_strcasecmp(defel->defname, "gettoken") == 0)
+ else if (strcmp(defel->defname, "gettoken") == 0)
{
values[Anum_pg_ts_parser_prstoken - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
}
- else if (pg_strcasecmp(defel->defname, "end") == 0)
+ else if (strcmp(defel->defname, "end") == 0)
{
values[Anum_pg_ts_parser_prsend - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
}
- else if (pg_strcasecmp(defel->defname, "headline") == 0)
+ else if (strcmp(defel->defname, "headline") == 0)
{
values[Anum_pg_ts_parser_prsheadline - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
}
- else if (pg_strcasecmp(defel->defname, "lextypes") == 0)
+ else if (strcmp(defel->defname, "lextypes") == 0)
{
values[Anum_pg_ts_parser_prslextype - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
@@ -438,7 +438,7 @@ DefineTSDictionary(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "template") == 0)
+ if (strcmp(defel->defname, "template") == 0)
{
templId = get_ts_template_oid(defGetQualifiedName(defel), false);
}
@@ -580,7 +580,7 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
DefElem *oldel = (DefElem *) lfirst(cell);
next = lnext(cell);
- if (pg_strcasecmp(oldel->defname, defel->defname) == 0)
+ if (strcmp(oldel->defname, defel->defname) == 0)
dictoptions = list_delete_cell(dictoptions, cell, prev);
else
prev = cell;
@@ -765,13 +765,13 @@ DefineTSTemplate(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "init") == 0)
+ if (strcmp(defel->defname, "init") == 0)
{
values[Anum_pg_ts_template_tmplinit - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
nulls[Anum_pg_ts_template_tmplinit - 1] = false;
}
- else if (pg_strcasecmp(defel->defname, "lexize") == 0)
+ else if (strcmp(defel->defname, "lexize") == 0)
{
values[Anum_pg_ts_template_tmpllexize - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
@@ -990,9 +990,9 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "parser") == 0)
+ if (strcmp(defel->defname, "parser") == 0)
prsOid = get_ts_parser_oid(defGetQualifiedName(defel), false);
- else if (pg_strcasecmp(defel->defname, "copy") == 0)
+ else if (strcmp(defel->defname, "copy") == 0)
sourceOid = get_ts_config_oid(defGetQualifiedName(defel), false);
else
ereport(ERROR,
@@ -1251,7 +1251,6 @@ getTokenTypes(Oid prsId, List *tokennames)
j = 0;
while (list && list[j].lexid)
{
- /* XXX should we use pg_strcasecmp here? */
if (strcmp(strVal(val), list[j].alias) == 0)
{
res[i] = list[j].lexid;
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 74eb430f96..899a5c4cd4 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -245,42 +245,42 @@ DefineType(ParseState *pstate, List *names, List *parameters)
DefElem *defel = (DefElem *) lfirst(pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "like") == 0)
+ if (strcmp(defel->defname, "like") == 0)
defelp = &likeTypeEl;
- else if (pg_strcasecmp(defel->defname, "internallength") == 0)
+ else if (strcmp(defel->defname, "internallength") == 0)
defelp = &internalLengthEl;
- else if (pg_strcasecmp(defel->defname, "input") == 0)
+ else if (strcmp(defel->defname, "input") == 0)
defelp = &inputNameEl;
- else if (pg_strcasecmp(defel->defname, "output") == 0)
+ else if (strcmp(defel->defname, "output") == 0)
defelp = &outputNameEl;
- else if (pg_strcasecmp(defel->defname, "receive") == 0)
+ else if (strcmp(defel->defname, "receive") == 0)
defelp = &receiveNameEl;
- else if (pg_strcasecmp(defel->defname, "send") == 0)
+ else if (strcmp(defel->defname, "send") == 0)
defelp = &sendNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
+ else if (strcmp(defel->defname, "typmod_in") == 0)
defelp = &typmodinNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
+ else if (strcmp(defel->defname, "typmod_out") == 0)
defelp = &typmodoutNameEl;
- else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
- pg_strcasecmp(defel->defname, "analyse") == 0)
+ else if (strcmp(defel->defname, "analyze") == 0 ||
+ strcmp(defel->defname, "analyse") == 0)
defelp = &analyzeNameEl;
- else if (pg_strcasecmp(defel->defname, "category") == 0)
+ else if (strcmp(defel->defname, "category") == 0)
defelp = &categoryEl;
- else if (pg_strcasecmp(defel->defname, "preferred") == 0)
+ else if (strcmp(defel->defname, "preferred") == 0)
defelp = &preferredEl;
- else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
+ else if (strcmp(defel->defname, "delimiter") == 0)
defelp = &delimiterEl;
- else if (pg_strcasecmp(defel->defname, "element") == 0)
+ else if (strcmp(defel->defname, "element") == 0)
defelp = &elemTypeEl;
- else if (pg_strcasecmp(defel->defname, "default") == 0)
+ else if (strcmp(defel->defname, "default") == 0)
defelp = &defaultValueEl;
- else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
+ else if (strcmp(defel->defname, "passedbyvalue") == 0)
defelp = &byValueEl;
- else if (pg_strcasecmp(defel->defname, "alignment") == 0)
+ else if (strcmp(defel->defname, "alignment") == 0)
defelp = &alignmentEl;
- else if (pg_strcasecmp(defel->defname, "storage") == 0)
+ else if (strcmp(defel->defname, "storage") == 0)
defelp = &storageEl;
- else if (pg_strcasecmp(defel->defname, "collatable") == 0)
+ else if (strcmp(defel->defname, "collatable") == 0)
defelp = &collatableEl;
else
{
@@ -1439,7 +1439,7 @@ DefineRange(CreateRangeStmt *stmt)
{
DefElem *defel = (DefElem *) lfirst(lc);
- if (pg_strcasecmp(defel->defname, "subtype") == 0)
+ if (strcmp(defel->defname, "subtype") == 0)
{
if (OidIsValid(rangeSubtype))
ereport(ERROR,
@@ -1448,7 +1448,7 @@ DefineRange(CreateRangeStmt *stmt)
/* we can look up the subtype name immediately */
rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
}
- else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
+ else if (strcmp(defel->defname, "subtype_opclass") == 0)
{
if (rangeSubOpclassName != NIL)
ereport(ERROR,
@@ -1456,7 +1456,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeSubOpclassName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "collation") == 0)
+ else if (strcmp(defel->defname, "collation") == 0)
{
if (rangeCollationName != NIL)
ereport(ERROR,
@@ -1464,7 +1464,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCollationName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "canonical") == 0)
+ else if (strcmp(defel->defname, "canonical") == 0)
{
if (rangeCanonicalName != NIL)
ereport(ERROR,
@@ -1472,7 +1472,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCanonicalName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
+ else if (strcmp(defel->defname, "subtype_diff") == 0)
{
if (rangeSubtypeDiffName != NIL)
ereport(ERROR,
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 04ad76a210..7d4511c585 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -46,8 +46,8 @@ void
validateWithCheckOption(const char *value)
{
if (value == NULL ||
- (pg_strcasecmp(value, "local") != 0 &&
- pg_strcasecmp(value, "cascaded") != 0))
+ (strcmp(value, "local") != 0 &&
+ strcmp(value, "cascaded") != 0))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -485,7 +485,7 @@ DefineView(ViewStmt *stmt, const char *queryString,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 459a227e57..9fb8a8ee6f 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -5848,14 +5848,18 @@ old_aggr_list: old_aggr_elem { $$ = list_make1($1); }
;
/*
- * Must use IDENT here to avoid reduce/reduce conflicts; fortunately none of
- * the item names needed in old aggregate definitions are likely to become
- * SQL keywords.
+ * Must use IDENT here to avoid reduce/reduce conflicts; fortunately, with
+ * the exception of PARALLEL, none of the item names needed in old aggregate
+ * definitions are likely to become keywords.
*/
old_aggr_elem: IDENT '=' def_arg
{
$$ = makeDefElem($1, (Node *)$3, @1);
}
+ | PARALLEL '=' def_arg
+ {
+ $$ = makeDefElem("parallel", (Node *)$3, @1);
+ }
;
opt_enum_val_list:
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 9fbcfd4fa6..406cd1dad0 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -262,7 +262,7 @@ interpretOidsOption(List *defList, bool allowOids)
DefElem *def = (DefElem *) lfirst(cell);
if (def->defnamespace == NULL &&
- pg_strcasecmp(def->defname, "oids") == 0)
+ strcmp(def->defname, "oids") == 0)
{
if (!allowOids)
ereport(ERROR,
diff --git a/src/backend/snowball/dict_snowball.c b/src/backend/snowball/dict_snowball.c
index 043681ec2d..78c9f73ef0 100644
--- a/src/backend/snowball/dict_snowball.c
+++ b/src/backend/snowball/dict_snowball.c
@@ -192,7 +192,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -201,7 +201,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Language", defel->defname) == 0)
+ else if (strcmp(defel->defname, "language") == 0)
{
if (d->stem)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_ispell.c b/src/backend/tsearch/dict_ispell.c
index 0d706795ad..edc6547700 100644
--- a/src/backend/tsearch/dict_ispell.c
+++ b/src/backend/tsearch/dict_ispell.c
@@ -44,7 +44,7 @@ dispell_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "DictFile") == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (dictloaded)
ereport(ERROR,
@@ -55,7 +55,7 @@ dispell_init(PG_FUNCTION_ARGS)
"dict"));
dictloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "AffFile") == 0)
+ else if (strcmp(defel->defname, "afffile") == 0)
{
if (affloaded)
ereport(ERROR,
@@ -66,7 +66,7 @@ dispell_init(PG_FUNCTION_ARGS)
"affix"));
affloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "StopWords") == 0)
+ else if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_simple.c b/src/backend/tsearch/dict_simple.c
index 268b4e48cf..ac6a24eba5 100644
--- a/src/backend/tsearch/dict_simple.c
+++ b/src/backend/tsearch/dict_simple.c
@@ -41,7 +41,7 @@ dsimple_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -50,7 +50,7 @@ dsimple_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Accept", defel->defname) == 0)
+ else if (strcmp(defel->defname, "accept") == 0)
{
if (acceptloaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_synonym.c b/src/backend/tsearch/dict_synonym.c
index 8ca65f3ded..c011886cb0 100644
--- a/src/backend/tsearch/dict_synonym.c
+++ b/src/backend/tsearch/dict_synonym.c
@@ -108,9 +108,9 @@ dsynonym_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("Synonyms", defel->defname) == 0)
+ if (strcmp(defel->defname, "synonyms") == 0)
filename = defGetString(defel);
- else if (pg_strcasecmp("CaseSensitive", defel->defname) == 0)
+ else if (strcmp(defel->defname, "casesensitive") == 0)
case_sensitive = defGetBoolean(defel);
else
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_thesaurus.c b/src/backend/tsearch/dict_thesaurus.c
index 23aaac8d07..24364e646d 100644
--- a/src/backend/tsearch/dict_thesaurus.c
+++ b/src/backend/tsearch/dict_thesaurus.c
@@ -616,7 +616,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("DictFile", defel->defname) == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (fileloaded)
ereport(ERROR,
@@ -625,7 +625,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
thesaurusRead(defGetString(defel), d);
fileloaded = true;
}
- else if (pg_strcasecmp("Dictionary", defel->defname) == 0)
+ else if (strcmp(defel->defname, "dictionary") == 0)
{
if (subdictname)
ereport(ERROR,
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out
index dbce7d3e8b..81943f3396 100644
--- a/src/test/regress/expected/aggregates.out
+++ b/src/test/regress/expected/aggregates.out
@@ -2011,7 +2011,7 @@ CREATE AGGREGATE balk(
BASETYPE = int4,
SFUNC = balkifnull(int8, int4),
STYPE = int8,
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0');
SELECT balk(hundred) FROM tenk1;
balk
@@ -2040,7 +2040,7 @@ CREATE AGGREGATE balk(
SFUNC = int4_sum(int8, int4),
STYPE = int8,
COMBINEFUNC = balkifnull(int8, int8),
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0'
);
-- force use of parallelism
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 767c09bec5..10efca6d8c 100644
--- a/src/test/regress/expected/alter_generic.out
+++ b/src/test/regress/expected/alter_generic.out
@@ -644,6 +644,9 @@ SELECT nspname, tmplname
alt_nsp2 | alt_ts_temp2
(3 rows)
+-- invalid: non-lowercase quoted identifiers
+CREATE TEXT SEARCH TEMPLATE tstemp_case ("Init" = init_function);
+ERROR: text search template parameter "Init" not recognized
--
-- Text Search Parser
--
@@ -670,6 +673,9 @@ SELECT nspname, prsname
alt_nsp2 | alt_ts_prs2
(3 rows)
+-- invalid: non-lowercase quoted identifiers
+CREATE TEXT SEARCH PARSER tspars_case ("Start" = start_function);
+ERROR: text search parser parameter "Start" not recognized
---
--- Cleanup resources
---
diff --git a/src/test/regress/expected/alter_operator.out b/src/test/regress/expected/alter_operator.out
index ef47affd7b..96236c38a0 100644
--- a/src/test/regress/expected/alter_operator.out
+++ b/src/test/regress/expected/alter_operator.out
@@ -128,6 +128,9 @@ CREATE USER regress_alter_op_user;
SET SESSION AUTHORIZATION regress_alter_op_user;
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NONE);
ERROR: must be owner of operator ===
+-- invalid: non-lowercase quoted identifiers
+ALTER OPERATOR & (bit, bit) SET ("Restrict" = _int_contsel, "Join" = _int_contjoinsel);
+ERROR: operator attribute "Restrict" not recognized
-- Clean up
RESET SESSION AUTHORIZATION;
DROP USER regress_alter_op_user;
diff --git a/src/test/regress/expected/collate.out b/src/test/regress/expected/collate.out
index b0025c0a87..64572872d7 100644
--- a/src/test/regress/expected/collate.out
+++ b/src/test/regress/expected/collate.out
@@ -633,6 +633,11 @@ DROP COLLATION mycoll2; -- fail
ERROR: cannot drop collation mycoll2 because other objects depend on it
DETAIL: table collate_test23 column f1 depends on collation mycoll2
HINT: Use DROP ... CASCADE to drop the dependent objects too.
+-- invalid: non-lowercase identifiers
+CREATE COLLATION case_coll ("Lc_Collate" = "POSIX", "Lc_Ctype" = "POSIX");
+ERROR: collation attribute "Lc_Collate" not recognized
+LINE 1: CREATE COLLATION case_coll ("Lc_Collate" = "POSIX", "Lc_Ctyp...
+ ^
-- 9.1 bug with useless COLLATE in an expression subject to length coercion
CREATE TEMP TABLE vctable (f1 varchar(25));
INSERT INTO vctable VALUES ('foo' COLLATE "C");
diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out
index ef65cd54ca..38d4e7994f 100644
--- a/src/test/regress/expected/create_aggregate.out
+++ b/src/test/regress/expected/create_aggregate.out
@@ -195,3 +195,33 @@ CREATE AGGREGATE wrongreturntype (float8)
minvfunc = float8mi_int
);
ERROR: return type of inverse transition function float8mi_int is not double precision
+-- invalid: non-lowercase identifiers
+CREATE AGGREGATE case_agg ( -- old syntax
+ "Sfunc1" = int4pl,
+ "Basetype" = int4,
+ "Stype1" = int4,
+ "Initcond1" = '0',
+ "Parallel" = safe
+);
+WARNING: aggregate attribute "Sfunc1" not recognized
+WARNING: aggregate attribute "Basetype" not recognized
+WARNING: aggregate attribute "Stype1" not recognized
+WARNING: aggregate attribute "Initcond1" not recognized
+WARNING: aggregate attribute "Parallel" not recognized
+ERROR: aggregate stype must be specified
+CREATE AGGREGATE case_agg(float8)
+(
+ "Stype" = internal,
+ "Sfunc" = ordered_set_transition,
+ "Finalfunc" = percentile_disc_final,
+ "Finalfunc_extra" = true,
+ "Finalfunc_modify" = read_write,
+ "Parallel" = safe
+);
+WARNING: aggregate attribute "Stype" not recognized
+WARNING: aggregate attribute "Sfunc" not recognized
+WARNING: aggregate attribute "Finalfunc" not recognized
+WARNING: aggregate attribute "Finalfunc_extra" not recognized
+WARNING: aggregate attribute "Finalfunc_modify" not recognized
+WARNING: aggregate attribute "Parallel" not recognized
+ERROR: aggregate stype must be specified
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 3a216c2ca8..3c4ccae1e7 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -172,3 +172,26 @@ CREATE OPERATOR #*# (
);
ERROR: permission denied for type type_op6
ROLLBACK;
+-- invalid: non-lowercase quoted identifiers
+CREATE OPERATOR ===
+(
+ "Leftarg" = box,
+ "Rightarg" = box,
+ "Procedure" = area_equal_procedure,
+ "Commutator" = ===,
+ "Negator" = !==,
+ "Restrict" = area_restriction_procedure,
+ "Join" = area_join_procedure,
+ "Hashes",
+ "Merges"
+);
+WARNING: operator attribute "Leftarg" not recognized
+WARNING: operator attribute "Rightarg" not recognized
+WARNING: operator attribute "Procedure" not recognized
+WARNING: operator attribute "Commutator" not recognized
+WARNING: operator attribute "Negator" not recognized
+WARNING: operator attribute "Restrict" not recognized
+WARNING: operator attribute "Join" not recognized
+WARNING: operator attribute "Hashes" not recognized
+WARNING: operator attribute "Merges" not recognized
+ERROR: operator procedure must be specified
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index 8e745402ae..552d7b09dc 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -863,3 +863,6 @@ Partition key: LIST (a)
Number of partitions: 0
DROP TABLE parted_col_comment;
+-- invalid: non-lowercase quoted reloptions identifiers
+CREATE TABLE tas_case WITH ("Fillfactor" = 10) AS SELECT 1 a;
+ERROR: unrecognized parameter "Fillfactor"
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 5886a1f37f..2139860861 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -154,3 +154,31 @@ WHERE attrelid = 'mytab'::regclass AND attnum > 0;
widget(42,13)
(1 row)
+-- invalid: non-lowercase quoted identifiers
+CREATE TYPE case_int42 (
+ "Internallength" = 4,
+ "Input" = int42_in,
+ "Output" = int42_out,
+ "Alignment" = int4,
+ "Default" = 42,
+ "Passedbyvalue"
+);
+WARNING: type attribute "Internallength" not recognized
+LINE 2: "Internallength" = 4,
+ ^
+WARNING: type attribute "Input" not recognized
+LINE 3: "Input" = int42_in,
+ ^
+WARNING: type attribute "Output" not recognized
+LINE 4: "Output" = int42_out,
+ ^
+WARNING: type attribute "Alignment" not recognized
+LINE 5: "Alignment" = int4,
+ ^
+WARNING: type attribute "Default" not recognized
+LINE 6: "Default" = 42,
+ ^
+WARNING: type attribute "Passedbyvalue" not recognized
+LINE 7: "Passedbyvalue"
+ ^
+ERROR: type input function must be specified
diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out
index 0744ef803b..e01402d42b 100644
--- a/src/test/regress/expected/tsdicts.out
+++ b/src/test/regress/expected/tsdicts.out
@@ -580,3 +580,13 @@ SELECT to_tsvector('thesaurus_tst', 'Booking tickets is looking like a booking a
'card':3,10 'invit':2,9 'like':6 'look':5 'order':1,8
(1 row)
+-- invalid: non-lowercase quoted identifiers
+CREATE TEXT SEARCH DICTIONARY tsdict_case
+(
+ "Template" = ispell,
+ "DictFile" = ispell_sample,
+ "AffFile" = ispell_sample
+);
+ERROR: text search template is required
+ALTER TEXT SEARCH DICTIONARY tsdict_case ("Dictfile" = ispell_sample);
+ERROR: text search dictionary "tsdict_case" does not exist
diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql
index 6c9b86a616..6833b7ffce 100644
--- a/src/test/regress/sql/aggregates.sql
+++ b/src/test/regress/sql/aggregates.sql
@@ -865,7 +865,7 @@ CREATE AGGREGATE balk(
BASETYPE = int4,
SFUNC = balkifnull(int8, int4),
STYPE = int8,
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0');
SELECT balk(hundred) FROM tenk1;
@@ -893,7 +893,7 @@ CREATE AGGREGATE balk(
SFUNC = int4_sum(int8, int4),
STYPE = int8,
COMBINEFUNC = balkifnull(int8, int8),
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0'
);
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index 311812e351..63882a3101 100644
--- a/src/test/regress/sql/alter_generic.sql
+++ b/src/test/regress/sql/alter_generic.sql
@@ -548,6 +548,9 @@ SELECT nspname, tmplname
WHERE t.tmplnamespace = n.oid AND nspname like 'alt_nsp%'
ORDER BY nspname, tmplname;
+-- invalid: non-lowercase quoted identifiers
+CREATE TEXT SEARCH TEMPLATE tstemp_case ("Init" = init_function);
+
--
-- Text Search Parser
--
@@ -570,6 +573,9 @@ SELECT nspname, prsname
WHERE t.prsnamespace = n.oid AND nspname like 'alt_nsp%'
ORDER BY nspname, prsname;
+-- invalid: non-lowercase quoted identifiers
+CREATE TEXT SEARCH PARSER tspars_case ("Start" = start_function);
+
---
--- Cleanup resources
---
diff --git a/src/test/regress/sql/alter_operator.sql b/src/test/regress/sql/alter_operator.sql
index 51ffd7e0e0..bfffba7257 100644
--- a/src/test/regress/sql/alter_operator.sql
+++ b/src/test/regress/sql/alter_operator.sql
@@ -89,6 +89,9 @@ SET SESSION AUTHORIZATION regress_alter_op_user;
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NONE);
+-- invalid: non-lowercase quoted identifiers
+ALTER OPERATOR & (bit, bit) SET ("Restrict" = _int_contsel, "Join" = _int_contjoinsel);
+
-- Clean up
RESET SESSION AUTHORIZATION;
DROP USER regress_alter_op_user;
diff --git a/src/test/regress/sql/collate.sql b/src/test/regress/sql/collate.sql
index 698f577490..fe53a18881 100644
--- a/src/test/regress/sql/collate.sql
+++ b/src/test/regress/sql/collate.sql
@@ -239,6 +239,8 @@ DROP COLLATION mycoll1;
CREATE TABLE collate_test23 (f1 text collate mycoll2);
DROP COLLATION mycoll2; -- fail
+-- invalid: non-lowercase identifiers
+CREATE COLLATION case_coll ("Lc_Collate" = "POSIX", "Lc_Ctype" = "POSIX");
-- 9.1 bug with useless COLLATE in an expression subject to length coercion
diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql
index 46e773bfe3..0b0bd3ed18 100644
--- a/src/test/regress/sql/create_aggregate.sql
+++ b/src/test/regress/sql/create_aggregate.sql
@@ -211,3 +211,22 @@ CREATE AGGREGATE wrongreturntype (float8)
msfunc = float8pl,
minvfunc = float8mi_int
);
+
+-- invalid: non-lowercase identifiers
+CREATE AGGREGATE case_agg ( -- old syntax
+ "Sfunc1" = int4pl,
+ "Basetype" = int4,
+ "Stype1" = int4,
+ "Initcond1" = '0',
+ "Parallel" = safe
+);
+
+CREATE AGGREGATE case_agg(float8)
+(
+ "Stype" = internal,
+ "Sfunc" = ordered_set_transition,
+ "Finalfunc" = percentile_disc_final,
+ "Finalfunc_extra" = true,
+ "Finalfunc_modify" = read_write,
+ "Parallel" = safe
+);
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index 0e5d6356bc..bb9907b3ed 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -179,3 +179,17 @@ CREATE OPERATOR #*# (
procedure = fn_op6
);
ROLLBACK;
+
+-- invalid: non-lowercase quoted identifiers
+CREATE OPERATOR ===
+(
+ "Leftarg" = box,
+ "Rightarg" = box,
+ "Procedure" = area_equal_procedure,
+ "Commutator" = ===,
+ "Negator" = !==,
+ "Restrict" = area_restriction_procedure,
+ "Join" = area_join_procedure,
+ "Hashes",
+ "Merges"
+);
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index 8f9991ef18..3142817b22 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -707,3 +707,6 @@ COMMENT ON COLUMN parted_col_comment.a IS 'Partition key';
SELECT obj_description('parted_col_comment'::regclass);
\d+ parted_col_comment
DROP TABLE parted_col_comment;
+
+-- invalid: non-lowercase quoted reloptions identifiers
+CREATE TABLE tas_case WITH ("Fillfactor" = 10) AS SELECT 1 a;
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index a28303aa6a..ef9acdb4f6 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -134,3 +134,14 @@ CREATE TEMP TABLE mytab (foo widget(42,13));
SELECT format_type(atttypid,atttypmod) FROM pg_attribute
WHERE attrelid = 'mytab'::regclass AND attnum > 0;
+
+-- invalid: non-lowercase quoted identifiers
+
+CREATE TYPE case_int42 (
+ "Internallength" = 4,
+ "Input" = int42_in,
+ "Output" = int42_out,
+ "Alignment" = int4,
+ "Default" = 42,
+ "Passedbyvalue"
+);
diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql
index a5a569e1ad..77ba073cca 100644
--- a/src/test/regress/sql/tsdicts.sql
+++ b/src/test/regress/sql/tsdicts.sql
@@ -188,3 +188,13 @@ ALTER TEXT SEARCH CONFIGURATION thesaurus_tst ALTER MAPPING FOR
SELECT to_tsvector('thesaurus_tst', 'one postgres one two one two three one');
SELECT to_tsvector('thesaurus_tst', 'Supernovae star is very new star and usually called supernovae (abbreviation SN)');
SELECT to_tsvector('thesaurus_tst', 'Booking tickets is looking like a booking a tickets');
+
+-- invalid: non-lowercase quoted identifiers
+CREATE TEXT SEARCH DICTIONARY tsdict_case
+(
+ "Template" = ispell,
+ "DictFile" = ispell_sample,
+ "AffFile" = ispell_sample
+);
+
+ALTER TEXT SEARCH DICTIONARY tsdict_case ("Dictfile" = ispell_sample);
--
2.14.1.145.gb3622a4ee
On Mon, Jan 22, 2018 at 12:48:45PM +0100, Daniel Gustafsson wrote:
Gotcha. I’ve added some tests to the patch. The test for CREATE
FUNCTION was omitted for now awaiting the outcome of the discussion
around isStrict and isCachable.
That makes sense.
Not sure how much they’re worth in "make check” though as it’s quite
easy to add a new option checked with pg_strcasecmp which then isn’t
tested. Still, it might aid review so definitely worth it.
Thanks for making those, this eases the review lookups. There are a
couple of code paths that remained untested:
- contrib/unaccent/
- contrib/dict_xsyn/
- contrib/dict_int/
- The combinations of toast reloptions is pretty particular as option
namespaces also go through pg_strcasecmp, so I think that those should
be tested as well (your patch includes a test for fillfactor, which is a
good base by the way).
- check_option for CREATE VIEW and ALTER VIEW SET.
- ALTER TEXT SEARCH CONFIGURATION for copy/parser options.
- CREATE TYPE AS RANGE with DefineRange().
There are as well two things I have spotted on the way:
1) fillRelOptions() can safely use strcmp.
2) indexam.sgml mentions using pg_strcasecmp() for consistency with the
core code when defining amproperty for an index AM. Well, with this
patch I think that for consistency with the core code that would involve
using strcmp instead, extension developers can of course still use
pg_strcasecmp.
Those are changed as well in the attached, which applies on top of your
v6. I have added as well in it the tests I spotted were missing. If this
looks right to you, I am fine to switch this patch as ready for
committer, without considering the issues with isCachable and isStrict
in CREATE FUNCTION of course.
--
Michael
Attachments:
defname_strcmp-v6-fix-michael.patchtext/x-diff; charset=utf-8Download
diff --git a/contrib/dict_int/expected/dict_int.out b/contrib/dict_int/expected/dict_int.out
index 3b766ec52a..20d172c730 100644
--- a/contrib/dict_int/expected/dict_int.out
+++ b/contrib/dict_int/expected/dict_int.out
@@ -300,3 +300,6 @@ select ts_lexize('intdict', '314532610153');
{314532}
(1 row)
+-- invalid: non-lowercase quoted identifiers
+ALTER TEXT SEARCH DICTIONARY intdict ("Maxlen" = 4);
+ERROR: unrecognized intdict parameter: "Maxlen"
diff --git a/contrib/dict_int/sql/dict_int.sql b/contrib/dict_int/sql/dict_int.sql
index 8ffec6b770..05d2149101 100644
--- a/contrib/dict_int/sql/dict_int.sql
+++ b/contrib/dict_int/sql/dict_int.sql
@@ -51,3 +51,6 @@ select ts_lexize('intdict', '252281774');
select ts_lexize('intdict', '313425');
select ts_lexize('intdict', '641439323669');
select ts_lexize('intdict', '314532610153');
+
+-- invalid: non-lowercase quoted identifiers
+ALTER TEXT SEARCH DICTIONARY intdict ("Maxlen" = 4);
diff --git a/contrib/dict_xsyn/expected/dict_xsyn.out b/contrib/dict_xsyn/expected/dict_xsyn.out
index 9b95e13559..4cc42956c7 100644
--- a/contrib/dict_xsyn/expected/dict_xsyn.out
+++ b/contrib/dict_xsyn/expected/dict_xsyn.out
@@ -140,3 +140,6 @@ SELECT ts_lexize('xsyn', 'grb');
(1 row)
+-- invalid: non-lowercase quoted identifiers
+ALTER TEXT SEARCH DICTIONARY xsyn ("Matchorig" = false);
+ERROR: unrecognized xsyn parameter: "Matchorig"
diff --git a/contrib/dict_xsyn/sql/dict_xsyn.sql b/contrib/dict_xsyn/sql/dict_xsyn.sql
index 49511061d0..ab1380c0a2 100644
--- a/contrib/dict_xsyn/sql/dict_xsyn.sql
+++ b/contrib/dict_xsyn/sql/dict_xsyn.sql
@@ -43,3 +43,6 @@ ALTER TEXT SEARCH DICTIONARY xsyn (RULES='xsyn_sample', KEEPORIG=false, MATCHORI
SELECT ts_lexize('xsyn', 'supernova');
SELECT ts_lexize('xsyn', 'sn');
SELECT ts_lexize('xsyn', 'grb');
+
+-- invalid: non-lowercase quoted identifiers
+ALTER TEXT SEARCH DICTIONARY xsyn ("Matchorig" = false);
diff --git a/contrib/unaccent/expected/unaccent.out b/contrib/unaccent/expected/unaccent.out
index b93105e9c7..30c061fe51 100644
--- a/contrib/unaccent/expected/unaccent.out
+++ b/contrib/unaccent/expected/unaccent.out
@@ -61,3 +61,6 @@ SELECT ts_lexize('unaccent', '
{����}
(1 row)
+-- invalid: non-lowercase quoted identifiers
+ALTER TEXT SEARCH DICTIONARY unaccent ("Rules" = 'my_rules');
+ERROR: unrecognized Unaccent parameter: "Rules"
diff --git a/contrib/unaccent/sql/unaccent.sql b/contrib/unaccent/sql/unaccent.sql
index 310213994f..f18f934377 100644
--- a/contrib/unaccent/sql/unaccent.sql
+++ b/contrib/unaccent/sql/unaccent.sql
@@ -16,3 +16,6 @@ SELECT unaccent('unaccent', '
SELECT ts_lexize('unaccent', 'foobar');
SELECT ts_lexize('unaccent', '����');
SELECT ts_lexize('unaccent', '����');
+
+-- invalid: non-lowercase quoted identifiers
+ALTER TEXT SEARCH DICTIONARY unaccent ("Rules" = 'my_rules');
diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml
index a7f6c8dc6a..6a5d307c69 100644
--- a/doc/src/sgml/indexam.sgml
+++ b/doc/src/sgml/indexam.sgml
@@ -439,7 +439,7 @@ amproperty (Oid index_oid, int attno,
If the core code does not recognize the property name
then <parameter>prop</parameter> is <literal>AMPROP_UNKNOWN</literal>.
Access methods can define custom property names by
- checking <parameter>propname</parameter> for a match (use <function>pg_strcasecmp</function>
+ checking <parameter>propname</parameter> for a match (use <function>strcmp</function>
to match, for consistency with the core code); for names known to the core
code, it's better to inspect <parameter>prop</parameter>.
If the <structfield>amproperty</structfield> method returns <literal>true</literal> then
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index a6de891eec..c82c28d781 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -1260,7 +1260,7 @@ fillRelOptions(void *rdopts, Size basesize,
for (j = 0; j < numelems; j++)
{
- if (pg_strcasecmp(options[i].gen->name, elems[j].optname) == 0)
+ if (strcmp(options[i].gen->name, elems[j].optname) == 0)
{
relopt_string *optstring;
char *itempos = ((char *) rdopts) + elems[j].offset;
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index 552d7b09dc..0a34eddac2 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -866,3 +866,14 @@ DROP TABLE parted_col_comment;
-- invalid: non-lowercase quoted reloptions identifiers
CREATE TABLE tas_case WITH ("Fillfactor" = 10) AS SELECT 1 a;
ERROR: unrecognized parameter "Fillfactor"
+CREATE TABLE tas_case (a text) WITH ("Oids" = true);
+ERROR: unrecognized parameter "Oids"
+-- options with namespaces used with non-lowercase and quotes, all should fail
+CREATE TABLE tas_case (a text) WITH ("Toast"."Autovacuum_vacuum_cost_limit" = 1);
+ERROR: unrecognized parameter namespace "Toast"
+CREATE TABLE tas_case (a text) WITH ("Toast.Autovacuum_vacuum_cost_limit" = 1);
+ERROR: unrecognized parameter "Toast.Autovacuum_vacuum_cost_limit"
+CREATE TABLE tas_case (a text) WITH ("Toast".autovacuum_vacuum_cost_limit = 1);
+ERROR: unrecognized parameter namespace "Toast"
+CREATE TABLE tas_case (a text) WITH (toast."Autovacuum_vacuum_cost_limit" = 1);
+ERROR: unrecognized parameter "Autovacuum_vacuum_cost_limit"
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 2139860861..fd2a81a930 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -182,3 +182,5 @@ WARNING: type attribute "Passedbyvalue" not recognized
LINE 7: "Passedbyvalue"
^
ERROR: type input function must be specified
+CREATE TYPE int4_range AS RANGE ("Subtype" = int4, "Subtype_diff" = int4mi);
+ERROR: type attribute "Subtype" not recognized
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index 4468c85d77..a3d8869908 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1712,3 +1712,13 @@ DROP SCHEMA temp_view_test CASCADE;
NOTICE: drop cascades to 27 other objects
DROP SCHEMA testviewschm2 CASCADE;
NOTICE: drop cascades to 62 other objects
+-- invalid: non-lowercase quoted identifiers
+-- Check for both CREATE VIEW and ALTER VIEW SET
+CREATE TABLE tt24 (a int);
+CREATE VIEW tt24v WITH ("Check_option" = 'local') AS SELECT * FROM tt24;
+ERROR: unrecognized parameter "Check_option"
+CREATE VIEW tt24v WITH (check_option = 'local') AS SELECT * FROM tt24;
+ALTER VIEW tt24v SET "Check_option" = 'local';
+ERROR: syntax error at or near ""Check_option"" at character 22
+DROP TABLE tt24 CASCADE;
+NOTICE: drop cascades to view tt24v
diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out
index e01402d42b..b3141ce59e 100644
--- a/src/test/regress/expected/tsdicts.out
+++ b/src/test/regress/expected/tsdicts.out
@@ -590,3 +590,5 @@ CREATE TEXT SEARCH DICTIONARY tsdict_case
ERROR: text search template is required
ALTER TEXT SEARCH DICTIONARY tsdict_case ("Dictfile" = ispell_sample);
ERROR: text search dictionary "tsdict_case" does not exist
+CREATE TEXT SEARCH CONFIGURATION thesaurus_tst ("Copy" = synonym_tst);
+ERROR: text search configuration parameter "Copy" not recognized
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index 3142817b22..0f9f75fda6 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -710,3 +710,9 @@ DROP TABLE parted_col_comment;
-- invalid: non-lowercase quoted reloptions identifiers
CREATE TABLE tas_case WITH ("Fillfactor" = 10) AS SELECT 1 a;
+CREATE TABLE tas_case (a text) WITH ("Oids" = true);
+-- options with namespaces used with non-lowercase and quotes, all should fail
+CREATE TABLE tas_case (a text) WITH ("Toast"."Autovacuum_vacuum_cost_limit" = 1);
+CREATE TABLE tas_case (a text) WITH ("Toast.Autovacuum_vacuum_cost_limit" = 1);
+CREATE TABLE tas_case (a text) WITH ("Toast".autovacuum_vacuum_cost_limit = 1);
+CREATE TABLE tas_case (a text) WITH (toast."Autovacuum_vacuum_cost_limit" = 1);
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index ef9acdb4f6..c990813d1a 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -136,7 +136,6 @@ SELECT format_type(atttypid,atttypmod) FROM pg_attribute
WHERE attrelid = 'mytab'::regclass AND attnum > 0;
-- invalid: non-lowercase quoted identifiers
-
CREATE TYPE case_int42 (
"Internallength" = 4,
"Input" = int42_in,
@@ -145,3 +144,4 @@ CREATE TYPE case_int42 (
"Default" = 42,
"Passedbyvalue"
);
+CREATE TYPE int4_range AS RANGE ("Subtype" = int4, "Subtype_diff" = int4mi);
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index b4e7a8793c..ec4f5203ab 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -584,3 +584,11 @@ select pg_get_ruledef(oid, true) from pg_rewrite
\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA temp_view_test CASCADE;
DROP SCHEMA testviewschm2 CASCADE;
+
+-- invalid: non-lowercase quoted identifiers
+-- Check for both CREATE VIEW and ALTER VIEW SET
+CREATE TABLE tt24 (a int);
+CREATE VIEW tt24v WITH ("Check_option" = 'local') AS SELECT * FROM tt24;
+CREATE VIEW tt24v WITH (check_option = 'local') AS SELECT * FROM tt24;
+ALTER VIEW tt24v SET "Check_option" = 'local';
+DROP TABLE tt24 CASCADE;
diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql
index 77ba073cca..75513600de 100644
--- a/src/test/regress/sql/tsdicts.sql
+++ b/src/test/regress/sql/tsdicts.sql
@@ -198,3 +198,4 @@ CREATE TEXT SEARCH DICTIONARY tsdict_case
);
ALTER TEXT SEARCH DICTIONARY tsdict_case ("Dictfile" = ispell_sample);
+CREATE TEXT SEARCH CONFIGURATION thesaurus_tst ("Copy" = synonym_tst);
On 23 Jan 2018, at 05:52, Michael Paquier <michael.paquier@gmail.com> wrote:
On Mon, Jan 22, 2018 at 12:48:45PM +0100, Daniel Gustafsson wrote:
Not sure how much they’re worth in "make check” though as it’s quite
easy to add a new option checked with pg_strcasecmp which then isn’t
tested. Still, it might aid review so definitely worth it.Thanks for making those, this eases the review lookups. There are a
couple of code paths that remained untested:
- contrib/unaccent/
- contrib/dict_xsyn/
- contrib/dict_int/
- The combinations of toast reloptions is pretty particular as option
namespaces also go through pg_strcasecmp, so I think that those should
be tested as well (your patch includes a test for fillfactor, which is a
good base by the way).
- check_option for CREATE VIEW and ALTER VIEW SET.
- ALTER TEXT SEARCH CONFIGURATION for copy/parser options.
- CREATE TYPE AS RANGE with DefineRange().
Thanks, those are good points.
There are as well two things I have spotted on the way:
1) fillRelOptions() can safely use strcmp.
Yes, I believe you’re right.
2) indexam.sgml mentions using pg_strcasecmp() for consistency with the
core code when defining amproperty for an index AM. Well, with this
patch I think that for consistency with the core code that would involve
using strcmp instead, extension developers can of course still use
pg_strcasecmp.
That part I’m less sure about, the propname will not be casefolded by the
parser so pg_strcasecmp() should still be the recommendation here no?
Those are changed as well in the attached, which applies on top of your
v6. I have added as well in it the tests I spotted were missing. If this
looks right to you, I am fine to switch this patch as ready for
committer, without considering the issues with isCachable and isStrict
in CREATE FUNCTION of course.
Apart from the amproperty hunk, I’m definately +1 on adding your patch on top
of my v6 one. Thanks for all your help and review!
cheers ./daniel
On Tue, Jan 23, 2018 at 04:22:22PM +0100, Daniel Gustafsson wrote:
On 23 Jan 2018, at 05:52, Michael Paquier <michael.paquier@gmail.com> wrote:
2) indexam.sgml mentions using pg_strcasecmp() for consistency with the
core code when defining amproperty for an index AM. Well, with this
patch I think that for consistency with the core code that would involve
using strcmp instead, extension developers can of course still use
pg_strcasecmp.That part I’m less sure about, the propname will not be casefolded by the
parser so pg_strcasecmp() should still be the recommendation here no?
Yes, you are right. I had a brain fade here as all the option names here
go through SQL-callable functions.
Those are changed as well in the attached, which applies on top of your
v6. I have added as well in it the tests I spotted were missing. If this
looks right to you, I am fine to switch this patch as ready for
committer, without considering the issues with isCachable and isStrict
in CREATE FUNCTION of course.Apart from the amproperty hunk, I’m definately +1 on adding your patch on top
of my v6 one. Thanks for all your help and review!
OK. Could you publish a v7? I will switch the entry as ready for
committer.
--
Michael
On 24 Jan 2018, at 02:37, Michael Paquier <michael.paquier@gmail.com> wrote:
On Tue, Jan 23, 2018 at 04:22:22PM +0100, Daniel Gustafsson wrote:On 23 Jan 2018, at 05:52, Michael Paquier <michael.paquier@gmail.com> wrote:
Those are changed as well in the attached, which applies on top of your
v6. I have added as well in it the tests I spotted were missing. If this
looks right to you, I am fine to switch this patch as ready for
committer, without considering the issues with isCachable and isStrict
in CREATE FUNCTION of course.Apart from the amproperty hunk, I’m definately +1 on adding your patch on top
of my v6 one. Thanks for all your help and review!OK. Could you publish a v7? I will switch the entry as ready for
committer.
Attached is a rebased v7 patch which has your amendments (minus propname) which
passes make check without errors.
The volatility patch is also rebased included, but there the discussion whether
to keep or drop the deprecated syntax first needs to happen (started in your
20180115022748.GB1724@paquier.xyz mail).
cheers ./daniel
Attachments:
defname_strcmp-v7.patchapplication/octet-stream; name=defname_strcmp-v7.patchDownload
From 554b223aa724e4e120fb2e7f17dd7819be00dd94 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <daniel@yesql.se>
Date: Wed, 24 Jan 2018 09:03:23 +0100
Subject: [PATCH 1/2] Use strcmp() instead of pg_strcasecmp() for identifier
matching
Since these option values are parsed using either the IDENT rule,
via keyword rules, or are created in lowercase with makeString(),
using strcmp() is the correct approach here. While not wrong per
se, using case insensitive matching can hide subtle bugs in case
defnames are created with mixed-case as these options otherwise
are assumed to always be lowercased.
The parsing of the PARALLEL option in the old style syntax for
CREATE AGGREGATE was fixed to allow using strcmp as well.
Reorder a few checks while in there such that all checks are in
the same order to make it easier to grep/read.
Also remove comment in tsearchcmds.c:getTokenTypes() regarding
strcmp/pg_strcasecmp as the code is correct. token_type is parsed
using the IDENT rule and will always be in lowercase.
Patch by Daniel Gustafsson and Michael Paquier
---
contrib/dict_int/dict_int.c | 4 +-
contrib/dict_int/expected/dict_int.out | 3 ++
contrib/dict_int/sql/dict_int.sql | 3 ++
contrib/dict_xsyn/dict_xsyn.c | 10 ++---
contrib/dict_xsyn/expected/dict_xsyn.out | 3 ++
contrib/dict_xsyn/sql/dict_xsyn.sql | 3 ++
contrib/unaccent/expected/unaccent.out | 3 ++
contrib/unaccent/sql/unaccent.sql | 3 ++
contrib/unaccent/unaccent.c | 2 +-
doc/src/sgml/ref/create_aggregate.sgml | 1 +
doc/src/sgml/ref/create_function.sgml | 1 -
src/backend/access/common/reloptions.c | 20 +++++----
src/backend/commands/aggregatecmds.c | 56 +++++++++++++-------------
src/backend/commands/collationcmds.c | 12 +++---
src/backend/commands/functioncmds.c | 6 +++
src/backend/commands/operatorcmds.c | 44 ++++++++++----------
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/tsearchcmds.c | 23 +++++------
src/backend/commands/typecmds.c | 48 +++++++++++-----------
src/backend/commands/view.c | 6 +--
src/backend/parser/gram.y | 10 +++--
src/backend/parser/parse_clause.c | 2 +-
src/backend/snowball/dict_snowball.c | 4 +-
src/backend/tsearch/dict_ispell.c | 6 +--
src/backend/tsearch/dict_simple.c | 4 +-
src/backend/tsearch/dict_synonym.c | 4 +-
src/backend/tsearch/dict_thesaurus.c | 4 +-
src/test/regress/expected/aggregates.out | 4 +-
src/test/regress/expected/alter_generic.out | 6 +++
src/test/regress/expected/alter_operator.out | 3 ++
src/test/regress/expected/collate.out | 5 +++
src/test/regress/expected/create_aggregate.out | 30 ++++++++++++++
src/test/regress/expected/create_operator.out | 23 +++++++++++
src/test/regress/expected/create_table.out | 14 +++++++
src/test/regress/expected/create_type.out | 30 ++++++++++++++
src/test/regress/expected/create_view.out | 10 +++++
src/test/regress/expected/tsdicts.out | 12 ++++++
src/test/regress/sql/aggregates.sql | 4 +-
src/test/regress/sql/alter_generic.sql | 6 +++
src/test/regress/sql/alter_operator.sql | 3 ++
src/test/regress/sql/collate.sql | 2 +
src/test/regress/sql/create_aggregate.sql | 19 +++++++++
src/test/regress/sql/create_operator.sql | 14 +++++++
src/test/regress/sql/create_table.sql | 9 +++++
src/test/regress/sql/create_type.sql | 11 +++++
src/test/regress/sql/create_view.sql | 8 ++++
src/test/regress/sql/tsdicts.sql | 11 +++++
47 files changed, 376 insertions(+), 135 deletions(-)
diff --git a/contrib/dict_int/dict_int.c b/contrib/dict_int/dict_int.c
index 8b45532938..56ede37089 100644
--- a/contrib/dict_int/dict_int.c
+++ b/contrib/dict_int/dict_int.c
@@ -42,11 +42,11 @@ dintdict_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "MAXLEN") == 0)
+ if (strcmp(defel->defname, "maxlen") == 0)
{
d->maxlen = atoi(defGetString(defel));
}
- else if (pg_strcasecmp(defel->defname, "REJECTLONG") == 0)
+ else if (strcmp(defel->defname, "rejectlong") == 0)
{
d->rejectlong = defGetBoolean(defel);
}
diff --git a/contrib/dict_int/expected/dict_int.out b/contrib/dict_int/expected/dict_int.out
index 3b766ec52a..20d172c730 100644
--- a/contrib/dict_int/expected/dict_int.out
+++ b/contrib/dict_int/expected/dict_int.out
@@ -300,3 +300,6 @@ select ts_lexize('intdict', '314532610153');
{314532}
(1 row)
+-- invalid: non-lowercase quoted identifiers
+ALTER TEXT SEARCH DICTIONARY intdict ("Maxlen" = 4);
+ERROR: unrecognized intdict parameter: "Maxlen"
diff --git a/contrib/dict_int/sql/dict_int.sql b/contrib/dict_int/sql/dict_int.sql
index 8ffec6b770..05d2149101 100644
--- a/contrib/dict_int/sql/dict_int.sql
+++ b/contrib/dict_int/sql/dict_int.sql
@@ -51,3 +51,6 @@ select ts_lexize('intdict', '252281774');
select ts_lexize('intdict', '313425');
select ts_lexize('intdict', '641439323669');
select ts_lexize('intdict', '314532610153');
+
+-- invalid: non-lowercase quoted identifiers
+ALTER TEXT SEARCH DICTIONARY intdict ("Maxlen" = 4);
diff --git a/contrib/dict_xsyn/dict_xsyn.c b/contrib/dict_xsyn/dict_xsyn.c
index 8a3abf7e3c..a79ece240c 100644
--- a/contrib/dict_xsyn/dict_xsyn.c
+++ b/contrib/dict_xsyn/dict_xsyn.c
@@ -157,23 +157,23 @@ dxsyn_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "MATCHORIG") == 0)
+ if (strcmp(defel->defname, "matchorig") == 0)
{
d->matchorig = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "KEEPORIG") == 0)
+ else if (strcmp(defel->defname, "keeporig") == 0)
{
d->keeporig = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "MATCHSYNONYMS") == 0)
+ else if (strcmp(defel->defname, "matchsynonyms") == 0)
{
d->matchsynonyms = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "KEEPSYNONYMS") == 0)
+ else if (strcmp(defel->defname, "keepsynonyms") == 0)
{
d->keepsynonyms = defGetBoolean(defel);
}
- else if (pg_strcasecmp(defel->defname, "RULES") == 0)
+ else if (strcmp(defel->defname, "rules") == 0)
{
/* we can't read the rules before parsing all options! */
filename = defGetString(defel);
diff --git a/contrib/dict_xsyn/expected/dict_xsyn.out b/contrib/dict_xsyn/expected/dict_xsyn.out
index 9b95e13559..4cc42956c7 100644
--- a/contrib/dict_xsyn/expected/dict_xsyn.out
+++ b/contrib/dict_xsyn/expected/dict_xsyn.out
@@ -140,3 +140,6 @@ SELECT ts_lexize('xsyn', 'grb');
(1 row)
+-- invalid: non-lowercase quoted identifiers
+ALTER TEXT SEARCH DICTIONARY xsyn ("Matchorig" = false);
+ERROR: unrecognized xsyn parameter: "Matchorig"
diff --git a/contrib/dict_xsyn/sql/dict_xsyn.sql b/contrib/dict_xsyn/sql/dict_xsyn.sql
index 49511061d0..ab1380c0a2 100644
--- a/contrib/dict_xsyn/sql/dict_xsyn.sql
+++ b/contrib/dict_xsyn/sql/dict_xsyn.sql
@@ -43,3 +43,6 @@ ALTER TEXT SEARCH DICTIONARY xsyn (RULES='xsyn_sample', KEEPORIG=false, MATCHORI
SELECT ts_lexize('xsyn', 'supernova');
SELECT ts_lexize('xsyn', 'sn');
SELECT ts_lexize('xsyn', 'grb');
+
+-- invalid: non-lowercase quoted identifiers
+ALTER TEXT SEARCH DICTIONARY xsyn ("Matchorig" = false);
diff --git a/contrib/unaccent/expected/unaccent.out b/contrib/unaccent/expected/unaccent.out
index b93105e9c7..30c061fe51 100644
--- a/contrib/unaccent/expected/unaccent.out
+++ b/contrib/unaccent/expected/unaccent.out
@@ -61,3 +61,6 @@ SELECT ts_lexize('unaccent', '
{����}
(1 row)
+-- invalid: non-lowercase quoted identifiers
+ALTER TEXT SEARCH DICTIONARY unaccent ("Rules" = 'my_rules');
+ERROR: unrecognized Unaccent parameter: "Rules"
diff --git a/contrib/unaccent/sql/unaccent.sql b/contrib/unaccent/sql/unaccent.sql
index 310213994f..f18f934377 100644
--- a/contrib/unaccent/sql/unaccent.sql
+++ b/contrib/unaccent/sql/unaccent.sql
@@ -16,3 +16,6 @@ SELECT unaccent('unaccent', '
SELECT ts_lexize('unaccent', 'foobar');
SELECT ts_lexize('unaccent', '����');
SELECT ts_lexize('unaccent', '����');
+
+-- invalid: non-lowercase quoted identifiers
+ALTER TEXT SEARCH DICTIONARY unaccent ("Rules" = 'my_rules');
diff --git a/contrib/unaccent/unaccent.c b/contrib/unaccent/unaccent.c
index 82f9c7fcfe..247c202755 100644
--- a/contrib/unaccent/unaccent.c
+++ b/contrib/unaccent/unaccent.c
@@ -276,7 +276,7 @@ unaccent_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("Rules", defel->defname) == 0)
+ if (strcmp(defel->defname, "rules") == 0)
{
if (fileloaded)
ereport(ERROR,
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index a4aaae876e..c46491991b 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -80,6 +80,7 @@ CREATE AGGREGATE <replaceable class="parameter">name</replaceable> (
[ , MFINALFUNC_MODIFY = { READ_ONLY | SHARABLE | READ_WRITE } ]
[ , MINITCOND = <replaceable class="parameter">minitial_condition</replaceable> ]
[ , SORTOP = <replaceable class="parameter">sort_operator</replaceable> ]
+ [ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ]
)
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml
index fd229d1193..869b8b396c 100644
--- a/doc/src/sgml/ref/create_function.sgml
+++ b/doc/src/sgml/ref/create_function.sgml
@@ -590,7 +590,6 @@ CREATE [ OR REPLACE ] FUNCTION
</variablelist>
- Attribute names are not case-sensitive.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 274f7aa8e9..c82c28d781 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -796,7 +796,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
}
else if (def->defnamespace == NULL)
continue;
- else if (pg_strcasecmp(def->defnamespace, namspace) != 0)
+ else if (strcmp(def->defnamespace, namspace) != 0)
continue;
kw_len = strlen(def->defname);
@@ -849,8 +849,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
{
for (i = 0; validnsps[i]; i++)
{
- if (pg_strcasecmp(def->defnamespace,
- validnsps[i]) == 0)
+ if (strcmp(def->defnamespace, validnsps[i]) == 0)
{
valid = true;
break;
@@ -865,7 +864,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
def->defnamespace)));
}
- if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
+ if (ignoreOids && strcmp(def->defname, "oids") == 0)
continue;
/* ignore if not in the same namespace */
@@ -876,7 +875,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
}
else if (def->defnamespace == NULL)
continue;
- else if (pg_strcasecmp(def->defnamespace, namspace) != 0)
+ else if (strcmp(def->defnamespace, namspace) != 0)
continue;
/*
@@ -1082,8 +1081,7 @@ parseRelOptions(Datum options, bool validate, relopt_kind kind,
int kw_len = reloptions[j].gen->namelen;
if (text_len > kw_len && text_str[kw_len] == '=' &&
- pg_strncasecmp(text_str, reloptions[j].gen->name,
- kw_len) == 0)
+ strncmp(text_str, reloptions[j].gen->name, kw_len) == 0)
{
parse_one_reloption(&reloptions[j], text_str, text_len,
validate);
@@ -1262,7 +1260,7 @@ fillRelOptions(void *rdopts, Size basesize,
for (j = 0; j < numelems; j++)
{
- if (pg_strcasecmp(options[i].gen->name, elems[j].optname) == 0)
+ if (strcmp(options[i].gen->name, elems[j].optname) == 0)
{
relopt_string *optstring;
char *itempos = ((char *) rdopts) + elems[j].offset;
@@ -1556,9 +1554,9 @@ AlterTableGetRelOptionsLockLevel(List *defList)
for (i = 0; relOpts[i]; i++)
{
- if (pg_strncasecmp(relOpts[i]->name,
- def->defname,
- relOpts[i]->namelen + 1) == 0)
+ if (strncmp(relOpts[i]->name,
+ def->defname,
+ relOpts[i]->namelen + 1) == 0)
{
if (lockmode < relOpts[i]->lockmode)
lockmode = relOpts[i]->lockmode;
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 1779ba7bcb..a48c3ac572 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -127,37 +127,37 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
* sfunc1, stype1, and initcond1 are accepted as obsolete spellings
* for sfunc, stype, initcond.
*/
- if (pg_strcasecmp(defel->defname, "sfunc") == 0)
+ if (strcmp(defel->defname, "sfunc") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
+ else if (strcmp(defel->defname, "sfunc1") == 0)
transfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
+ else if (strcmp(defel->defname, "finalfunc") == 0)
finalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "combinefunc") == 0)
+ else if (strcmp(defel->defname, "combinefunc") == 0)
combinefuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "serialfunc") == 0)
+ else if (strcmp(defel->defname, "serialfunc") == 0)
serialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "deserialfunc") == 0)
+ else if (strcmp(defel->defname, "deserialfunc") == 0)
deserialfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "msfunc") == 0)
+ else if (strcmp(defel->defname, "msfunc") == 0)
mtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "minvfunc") == 0)
+ else if (strcmp(defel->defname, "minvfunc") == 0)
minvtransfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc") == 0)
mfinalfuncName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "finalfunc_extra") == 0)
finalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
mfinalfuncExtraArgs = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "finalfunc_modify") == 0)
+ else if (strcmp(defel->defname, "finalfunc_modify") == 0)
finalfuncModify = extractModify(defel);
- else if (pg_strcasecmp(defel->defname, "mfinalfunc_modify") == 0)
+ else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
mfinalfuncModify = extractModify(defel);
- else if (pg_strcasecmp(defel->defname, "sortop") == 0)
+ else if (strcmp(defel->defname, "sortop") == 0)
sortoperatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "basetype") == 0)
+ else if (strcmp(defel->defname, "basetype") == 0)
baseType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "hypothetical") == 0)
+ else if (strcmp(defel->defname, "hypothetical") == 0)
{
if (defGetBoolean(defel))
{
@@ -168,23 +168,23 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
aggKind = AGGKIND_HYPOTHETICAL;
}
}
- else if (pg_strcasecmp(defel->defname, "stype") == 0)
+ else if (strcmp(defel->defname, "stype") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "stype1") == 0)
+ else if (strcmp(defel->defname, "stype1") == 0)
transType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "sspace") == 0)
+ else if (strcmp(defel->defname, "sspace") == 0)
transSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "mstype") == 0)
+ else if (strcmp(defel->defname, "mstype") == 0)
mtransType = defGetTypeName(defel);
- else if (pg_strcasecmp(defel->defname, "msspace") == 0)
+ else if (strcmp(defel->defname, "msspace") == 0)
mtransSpace = defGetInt32(defel);
- else if (pg_strcasecmp(defel->defname, "initcond") == 0)
+ else if (strcmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
+ else if (strcmp(defel->defname, "initcond1") == 0)
initval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "minitcond") == 0)
+ else if (strcmp(defel->defname, "minitcond") == 0)
minitval = defGetString(defel);
- else if (pg_strcasecmp(defel->defname, "parallel") == 0)
+ else if (strcmp(defel->defname, "parallel") == 0)
parallel = defGetString(defel);
else
ereport(WARNING,
@@ -420,11 +420,11 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
if (parallel)
{
- if (pg_strcasecmp(parallel, "safe") == 0)
+ if (strcmp(parallel, "safe") == 0)
proparallel = PROPARALLEL_SAFE;
- else if (pg_strcasecmp(parallel, "restricted") == 0)
+ else if (strcmp(parallel, "restricted") == 0)
proparallel = PROPARALLEL_RESTRICTED;
- else if (pg_strcasecmp(parallel, "unsafe") == 0)
+ else if (strcmp(parallel, "unsafe") == 0)
proparallel = PROPARALLEL_UNSAFE;
else
ereport(ERROR,
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index fdfb3dcd2c..d0b5cdb69a 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -82,17 +82,17 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
DefElem *defel = lfirst_node(DefElem, pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "from") == 0)
+ if (strcmp(defel->defname, "from") == 0)
defelp = &fromEl;
- else if (pg_strcasecmp(defel->defname, "locale") == 0)
+ else if (strcmp(defel->defname, "locale") == 0)
defelp = &localeEl;
- else if (pg_strcasecmp(defel->defname, "lc_collate") == 0)
+ else if (strcmp(defel->defname, "lc_collate") == 0)
defelp = &lccollateEl;
- else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0)
+ else if (strcmp(defel->defname, "lc_ctype") == 0)
defelp = &lcctypeEl;
- else if (pg_strcasecmp(defel->defname, "provider") == 0)
+ else if (strcmp(defel->defname, "provider") == 0)
defelp = &providerEl;
- else if (pg_strcasecmp(defel->defname, "version") == 0)
+ else if (strcmp(defel->defname, "version") == 0)
defelp = &versionEl;
else
{
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index df87dfeb54..29d2b3a7ff 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -812,6 +812,12 @@ compute_attributes_with_style(ParseState *pstate, bool is_procedure, List *param
{
DefElem *param = (DefElem *) lfirst(pl);
+ /*
+ * Attribute names from the parser should always be in casefolded into
+ * lowercase, but for the old attributes isStrict and isCachable the
+ * manual has since 7.3 stated that they are not case-sensitive so for
+ * now use pg_strcasecmp().
+ */
if (pg_strcasecmp(param->defname, "isstrict") == 0)
{
if (is_procedure)
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 35404ac39a..585382d758 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -105,7 +105,7 @@ DefineOperator(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "leftarg") == 0)
+ if (strcmp(defel->defname, "leftarg") == 0)
{
typeName1 = defGetTypeName(defel);
if (typeName1->setof)
@@ -113,7 +113,7 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
+ else if (strcmp(defel->defname, "rightarg") == 0)
{
typeName2 = defGetTypeName(defel);
if (typeName2->setof)
@@ -121,28 +121,28 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
- else if (pg_strcasecmp(defel->defname, "procedure") == 0)
+ else if (strcmp(defel->defname, "procedure") == 0)
functionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "commutator") == 0)
+ else if (strcmp(defel->defname, "commutator") == 0)
commutatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "negator") == 0)
+ else if (strcmp(defel->defname, "negator") == 0)
negatorName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ else if (strcmp(defel->defname, "restrict") == 0)
restrictionName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
joinName = defGetQualifiedName(defel);
- else if (pg_strcasecmp(defel->defname, "hashes") == 0)
+ else if (strcmp(defel->defname, "hashes") == 0)
canHash = defGetBoolean(defel);
- else if (pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "merges") == 0)
canMerge = defGetBoolean(defel);
/* These obsolete options are taken as meaning canMerge */
- else if (pg_strcasecmp(defel->defname, "sort1") == 0)
+ else if (strcmp(defel->defname, "sort1") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "sort2") == 0)
+ else if (strcmp(defel->defname, "sort2") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
+ else if (strcmp(defel->defname, "ltcmp") == 0)
canMerge = true;
- else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
+ else if (strcmp(defel->defname, "gtcmp") == 0)
canMerge = true;
else
{
@@ -420,12 +420,12 @@ AlterOperator(AlterOperatorStmt *stmt)
else
param = defGetQualifiedName(defel);
- if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ if (strcmp(defel->defname, "restrict") == 0)
{
restrictionName = param;
updateRestriction = true;
}
- else if (pg_strcasecmp(defel->defname, "join") == 0)
+ else if (strcmp(defel->defname, "join") == 0)
{
joinName = param;
updateJoin = true;
@@ -435,13 +435,13 @@ AlterOperator(AlterOperatorStmt *stmt)
* The rest of the options that CREATE accepts cannot be changed.
* Check for them so that we can give a meaningful error message.
*/
- else if (pg_strcasecmp(defel->defname, "leftarg") == 0 ||
- pg_strcasecmp(defel->defname, "rightarg") == 0 ||
- pg_strcasecmp(defel->defname, "procedure") == 0 ||
- pg_strcasecmp(defel->defname, "commutator") == 0 ||
- pg_strcasecmp(defel->defname, "negator") == 0 ||
- pg_strcasecmp(defel->defname, "hashes") == 0 ||
- pg_strcasecmp(defel->defname, "merges") == 0)
+ else if (strcmp(defel->defname, "leftarg") == 0 ||
+ strcmp(defel->defname, "rightarg") == 0 ||
+ strcmp(defel->defname, "procedure") == 0 ||
+ strcmp(defel->defname, "commutator") == 0 ||
+ strcmp(defel->defname, "negator") == 0 ||
+ strcmp(defel->defname, "hashes") == 0 ||
+ strcmp(defel->defname, "merges") == 0)
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 2e768dd5e4..ea03fd2ecf 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -10536,7 +10536,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index bdf3857ce4..3a843512d1 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -209,27 +209,27 @@ DefineTSParser(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "start") == 0)
+ if (strcmp(defel->defname, "start") == 0)
{
values[Anum_pg_ts_parser_prsstart - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
}
- else if (pg_strcasecmp(defel->defname, "gettoken") == 0)
+ else if (strcmp(defel->defname, "gettoken") == 0)
{
values[Anum_pg_ts_parser_prstoken - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
}
- else if (pg_strcasecmp(defel->defname, "end") == 0)
+ else if (strcmp(defel->defname, "end") == 0)
{
values[Anum_pg_ts_parser_prsend - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
}
- else if (pg_strcasecmp(defel->defname, "headline") == 0)
+ else if (strcmp(defel->defname, "headline") == 0)
{
values[Anum_pg_ts_parser_prsheadline - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
}
- else if (pg_strcasecmp(defel->defname, "lextypes") == 0)
+ else if (strcmp(defel->defname, "lextypes") == 0)
{
values[Anum_pg_ts_parser_prslextype - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
@@ -438,7 +438,7 @@ DefineTSDictionary(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "template") == 0)
+ if (strcmp(defel->defname, "template") == 0)
{
templId = get_ts_template_oid(defGetQualifiedName(defel), false);
}
@@ -580,7 +580,7 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
DefElem *oldel = (DefElem *) lfirst(cell);
next = lnext(cell);
- if (pg_strcasecmp(oldel->defname, defel->defname) == 0)
+ if (strcmp(oldel->defname, defel->defname) == 0)
dictoptions = list_delete_cell(dictoptions, cell, prev);
else
prev = cell;
@@ -765,13 +765,13 @@ DefineTSTemplate(List *names, List *parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "init") == 0)
+ if (strcmp(defel->defname, "init") == 0)
{
values[Anum_pg_ts_template_tmplinit - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
nulls[Anum_pg_ts_template_tmplinit - 1] = false;
}
- else if (pg_strcasecmp(defel->defname, "lexize") == 0)
+ else if (strcmp(defel->defname, "lexize") == 0)
{
values[Anum_pg_ts_template_tmpllexize - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
@@ -990,9 +990,9 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (pg_strcasecmp(defel->defname, "parser") == 0)
+ if (strcmp(defel->defname, "parser") == 0)
prsOid = get_ts_parser_oid(defGetQualifiedName(defel), false);
- else if (pg_strcasecmp(defel->defname, "copy") == 0)
+ else if (strcmp(defel->defname, "copy") == 0)
sourceOid = get_ts_config_oid(defGetQualifiedName(defel), false);
else
ereport(ERROR,
@@ -1251,7 +1251,6 @@ getTokenTypes(Oid prsId, List *tokennames)
j = 0;
while (list && list[j].lexid)
{
- /* XXX should we use pg_strcasecmp here? */
if (strcmp(strVal(val), list[j].alias) == 0)
{
res[i] = list[j].lexid;
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 74eb430f96..899a5c4cd4 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -245,42 +245,42 @@ DefineType(ParseState *pstate, List *names, List *parameters)
DefElem *defel = (DefElem *) lfirst(pl);
DefElem **defelp;
- if (pg_strcasecmp(defel->defname, "like") == 0)
+ if (strcmp(defel->defname, "like") == 0)
defelp = &likeTypeEl;
- else if (pg_strcasecmp(defel->defname, "internallength") == 0)
+ else if (strcmp(defel->defname, "internallength") == 0)
defelp = &internalLengthEl;
- else if (pg_strcasecmp(defel->defname, "input") == 0)
+ else if (strcmp(defel->defname, "input") == 0)
defelp = &inputNameEl;
- else if (pg_strcasecmp(defel->defname, "output") == 0)
+ else if (strcmp(defel->defname, "output") == 0)
defelp = &outputNameEl;
- else if (pg_strcasecmp(defel->defname, "receive") == 0)
+ else if (strcmp(defel->defname, "receive") == 0)
defelp = &receiveNameEl;
- else if (pg_strcasecmp(defel->defname, "send") == 0)
+ else if (strcmp(defel->defname, "send") == 0)
defelp = &sendNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
+ else if (strcmp(defel->defname, "typmod_in") == 0)
defelp = &typmodinNameEl;
- else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
+ else if (strcmp(defel->defname, "typmod_out") == 0)
defelp = &typmodoutNameEl;
- else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
- pg_strcasecmp(defel->defname, "analyse") == 0)
+ else if (strcmp(defel->defname, "analyze") == 0 ||
+ strcmp(defel->defname, "analyse") == 0)
defelp = &analyzeNameEl;
- else if (pg_strcasecmp(defel->defname, "category") == 0)
+ else if (strcmp(defel->defname, "category") == 0)
defelp = &categoryEl;
- else if (pg_strcasecmp(defel->defname, "preferred") == 0)
+ else if (strcmp(defel->defname, "preferred") == 0)
defelp = &preferredEl;
- else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
+ else if (strcmp(defel->defname, "delimiter") == 0)
defelp = &delimiterEl;
- else if (pg_strcasecmp(defel->defname, "element") == 0)
+ else if (strcmp(defel->defname, "element") == 0)
defelp = &elemTypeEl;
- else if (pg_strcasecmp(defel->defname, "default") == 0)
+ else if (strcmp(defel->defname, "default") == 0)
defelp = &defaultValueEl;
- else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
+ else if (strcmp(defel->defname, "passedbyvalue") == 0)
defelp = &byValueEl;
- else if (pg_strcasecmp(defel->defname, "alignment") == 0)
+ else if (strcmp(defel->defname, "alignment") == 0)
defelp = &alignmentEl;
- else if (pg_strcasecmp(defel->defname, "storage") == 0)
+ else if (strcmp(defel->defname, "storage") == 0)
defelp = &storageEl;
- else if (pg_strcasecmp(defel->defname, "collatable") == 0)
+ else if (strcmp(defel->defname, "collatable") == 0)
defelp = &collatableEl;
else
{
@@ -1439,7 +1439,7 @@ DefineRange(CreateRangeStmt *stmt)
{
DefElem *defel = (DefElem *) lfirst(lc);
- if (pg_strcasecmp(defel->defname, "subtype") == 0)
+ if (strcmp(defel->defname, "subtype") == 0)
{
if (OidIsValid(rangeSubtype))
ereport(ERROR,
@@ -1448,7 +1448,7 @@ DefineRange(CreateRangeStmt *stmt)
/* we can look up the subtype name immediately */
rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
}
- else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
+ else if (strcmp(defel->defname, "subtype_opclass") == 0)
{
if (rangeSubOpclassName != NIL)
ereport(ERROR,
@@ -1456,7 +1456,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeSubOpclassName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "collation") == 0)
+ else if (strcmp(defel->defname, "collation") == 0)
{
if (rangeCollationName != NIL)
ereport(ERROR,
@@ -1464,7 +1464,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCollationName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "canonical") == 0)
+ else if (strcmp(defel->defname, "canonical") == 0)
{
if (rangeCanonicalName != NIL)
ereport(ERROR,
@@ -1472,7 +1472,7 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCanonicalName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
+ else if (strcmp(defel->defname, "subtype_diff") == 0)
{
if (rangeSubtypeDiffName != NIL)
ereport(ERROR,
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 04ad76a210..7d4511c585 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -46,8 +46,8 @@ void
validateWithCheckOption(const char *value)
{
if (value == NULL ||
- (pg_strcasecmp(value, "local") != 0 &&
- pg_strcasecmp(value, "cascaded") != 0))
+ (strcmp(value, "local") != 0 &&
+ strcmp(value, "cascaded") != 0))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -485,7 +485,7 @@ DefineView(ViewStmt *stmt, const char *queryString,
{
DefElem *defel = (DefElem *) lfirst(cell);
- if (pg_strcasecmp(defel->defname, "check_option") == 0)
+ if (strcmp(defel->defname, "check_option") == 0)
check_option = true;
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 459a227e57..9fb8a8ee6f 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -5848,14 +5848,18 @@ old_aggr_list: old_aggr_elem { $$ = list_make1($1); }
;
/*
- * Must use IDENT here to avoid reduce/reduce conflicts; fortunately none of
- * the item names needed in old aggregate definitions are likely to become
- * SQL keywords.
+ * Must use IDENT here to avoid reduce/reduce conflicts; fortunately, with
+ * the exception of PARALLEL, none of the item names needed in old aggregate
+ * definitions are likely to become keywords.
*/
old_aggr_elem: IDENT '=' def_arg
{
$$ = makeDefElem($1, (Node *)$3, @1);
}
+ | PARALLEL '=' def_arg
+ {
+ $$ = makeDefElem("parallel", (Node *)$3, @1);
+ }
;
opt_enum_val_list:
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 9fbcfd4fa6..406cd1dad0 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -262,7 +262,7 @@ interpretOidsOption(List *defList, bool allowOids)
DefElem *def = (DefElem *) lfirst(cell);
if (def->defnamespace == NULL &&
- pg_strcasecmp(def->defname, "oids") == 0)
+ strcmp(def->defname, "oids") == 0)
{
if (!allowOids)
ereport(ERROR,
diff --git a/src/backend/snowball/dict_snowball.c b/src/backend/snowball/dict_snowball.c
index 043681ec2d..78c9f73ef0 100644
--- a/src/backend/snowball/dict_snowball.c
+++ b/src/backend/snowball/dict_snowball.c
@@ -192,7 +192,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -201,7 +201,7 @@ dsnowball_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Language", defel->defname) == 0)
+ else if (strcmp(defel->defname, "language") == 0)
{
if (d->stem)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_ispell.c b/src/backend/tsearch/dict_ispell.c
index 0d706795ad..edc6547700 100644
--- a/src/backend/tsearch/dict_ispell.c
+++ b/src/backend/tsearch/dict_ispell.c
@@ -44,7 +44,7 @@ dispell_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp(defel->defname, "DictFile") == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (dictloaded)
ereport(ERROR,
@@ -55,7 +55,7 @@ dispell_init(PG_FUNCTION_ARGS)
"dict"));
dictloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "AffFile") == 0)
+ else if (strcmp(defel->defname, "afffile") == 0)
{
if (affloaded)
ereport(ERROR,
@@ -66,7 +66,7 @@ dispell_init(PG_FUNCTION_ARGS)
"affix"));
affloaded = true;
}
- else if (pg_strcasecmp(defel->defname, "StopWords") == 0)
+ else if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_simple.c b/src/backend/tsearch/dict_simple.c
index 268b4e48cf..ac6a24eba5 100644
--- a/src/backend/tsearch/dict_simple.c
+++ b/src/backend/tsearch/dict_simple.c
@@ -41,7 +41,7 @@ dsimple_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("StopWords", defel->defname) == 0)
+ if (strcmp(defel->defname, "stopwords") == 0)
{
if (stoploaded)
ereport(ERROR,
@@ -50,7 +50,7 @@ dsimple_init(PG_FUNCTION_ARGS)
readstoplist(defGetString(defel), &d->stoplist, lowerstr);
stoploaded = true;
}
- else if (pg_strcasecmp("Accept", defel->defname) == 0)
+ else if (strcmp(defel->defname, "accept") == 0)
{
if (acceptloaded)
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_synonym.c b/src/backend/tsearch/dict_synonym.c
index 8ca65f3ded..c011886cb0 100644
--- a/src/backend/tsearch/dict_synonym.c
+++ b/src/backend/tsearch/dict_synonym.c
@@ -108,9 +108,9 @@ dsynonym_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("Synonyms", defel->defname) == 0)
+ if (strcmp(defel->defname, "synonyms") == 0)
filename = defGetString(defel);
- else if (pg_strcasecmp("CaseSensitive", defel->defname) == 0)
+ else if (strcmp(defel->defname, "casesensitive") == 0)
case_sensitive = defGetBoolean(defel);
else
ereport(ERROR,
diff --git a/src/backend/tsearch/dict_thesaurus.c b/src/backend/tsearch/dict_thesaurus.c
index 23aaac8d07..24364e646d 100644
--- a/src/backend/tsearch/dict_thesaurus.c
+++ b/src/backend/tsearch/dict_thesaurus.c
@@ -616,7 +616,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
{
DefElem *defel = (DefElem *) lfirst(l);
- if (pg_strcasecmp("DictFile", defel->defname) == 0)
+ if (strcmp(defel->defname, "dictfile") == 0)
{
if (fileloaded)
ereport(ERROR,
@@ -625,7 +625,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
thesaurusRead(defGetString(defel), d);
fileloaded = true;
}
- else if (pg_strcasecmp("Dictionary", defel->defname) == 0)
+ else if (strcmp(defel->defname, "dictionary") == 0)
{
if (subdictname)
ereport(ERROR,
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out
index dbce7d3e8b..81943f3396 100644
--- a/src/test/regress/expected/aggregates.out
+++ b/src/test/regress/expected/aggregates.out
@@ -2011,7 +2011,7 @@ CREATE AGGREGATE balk(
BASETYPE = int4,
SFUNC = balkifnull(int8, int4),
STYPE = int8,
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0');
SELECT balk(hundred) FROM tenk1;
balk
@@ -2040,7 +2040,7 @@ CREATE AGGREGATE balk(
SFUNC = int4_sum(int8, int4),
STYPE = int8,
COMBINEFUNC = balkifnull(int8, int8),
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0'
);
-- force use of parallelism
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 767c09bec5..10efca6d8c 100644
--- a/src/test/regress/expected/alter_generic.out
+++ b/src/test/regress/expected/alter_generic.out
@@ -644,6 +644,9 @@ SELECT nspname, tmplname
alt_nsp2 | alt_ts_temp2
(3 rows)
+-- invalid: non-lowercase quoted identifiers
+CREATE TEXT SEARCH TEMPLATE tstemp_case ("Init" = init_function);
+ERROR: text search template parameter "Init" not recognized
--
-- Text Search Parser
--
@@ -670,6 +673,9 @@ SELECT nspname, prsname
alt_nsp2 | alt_ts_prs2
(3 rows)
+-- invalid: non-lowercase quoted identifiers
+CREATE TEXT SEARCH PARSER tspars_case ("Start" = start_function);
+ERROR: text search parser parameter "Start" not recognized
---
--- Cleanup resources
---
diff --git a/src/test/regress/expected/alter_operator.out b/src/test/regress/expected/alter_operator.out
index ef47affd7b..96236c38a0 100644
--- a/src/test/regress/expected/alter_operator.out
+++ b/src/test/regress/expected/alter_operator.out
@@ -128,6 +128,9 @@ CREATE USER regress_alter_op_user;
SET SESSION AUTHORIZATION regress_alter_op_user;
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NONE);
ERROR: must be owner of operator ===
+-- invalid: non-lowercase quoted identifiers
+ALTER OPERATOR & (bit, bit) SET ("Restrict" = _int_contsel, "Join" = _int_contjoinsel);
+ERROR: operator attribute "Restrict" not recognized
-- Clean up
RESET SESSION AUTHORIZATION;
DROP USER regress_alter_op_user;
diff --git a/src/test/regress/expected/collate.out b/src/test/regress/expected/collate.out
index b0025c0a87..64572872d7 100644
--- a/src/test/regress/expected/collate.out
+++ b/src/test/regress/expected/collate.out
@@ -633,6 +633,11 @@ DROP COLLATION mycoll2; -- fail
ERROR: cannot drop collation mycoll2 because other objects depend on it
DETAIL: table collate_test23 column f1 depends on collation mycoll2
HINT: Use DROP ... CASCADE to drop the dependent objects too.
+-- invalid: non-lowercase identifiers
+CREATE COLLATION case_coll ("Lc_Collate" = "POSIX", "Lc_Ctype" = "POSIX");
+ERROR: collation attribute "Lc_Collate" not recognized
+LINE 1: CREATE COLLATION case_coll ("Lc_Collate" = "POSIX", "Lc_Ctyp...
+ ^
-- 9.1 bug with useless COLLATE in an expression subject to length coercion
CREATE TEMP TABLE vctable (f1 varchar(25));
INSERT INTO vctable VALUES ('foo' COLLATE "C");
diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out
index ef65cd54ca..38d4e7994f 100644
--- a/src/test/regress/expected/create_aggregate.out
+++ b/src/test/regress/expected/create_aggregate.out
@@ -195,3 +195,33 @@ CREATE AGGREGATE wrongreturntype (float8)
minvfunc = float8mi_int
);
ERROR: return type of inverse transition function float8mi_int is not double precision
+-- invalid: non-lowercase identifiers
+CREATE AGGREGATE case_agg ( -- old syntax
+ "Sfunc1" = int4pl,
+ "Basetype" = int4,
+ "Stype1" = int4,
+ "Initcond1" = '0',
+ "Parallel" = safe
+);
+WARNING: aggregate attribute "Sfunc1" not recognized
+WARNING: aggregate attribute "Basetype" not recognized
+WARNING: aggregate attribute "Stype1" not recognized
+WARNING: aggregate attribute "Initcond1" not recognized
+WARNING: aggregate attribute "Parallel" not recognized
+ERROR: aggregate stype must be specified
+CREATE AGGREGATE case_agg(float8)
+(
+ "Stype" = internal,
+ "Sfunc" = ordered_set_transition,
+ "Finalfunc" = percentile_disc_final,
+ "Finalfunc_extra" = true,
+ "Finalfunc_modify" = read_write,
+ "Parallel" = safe
+);
+WARNING: aggregate attribute "Stype" not recognized
+WARNING: aggregate attribute "Sfunc" not recognized
+WARNING: aggregate attribute "Finalfunc" not recognized
+WARNING: aggregate attribute "Finalfunc_extra" not recognized
+WARNING: aggregate attribute "Finalfunc_modify" not recognized
+WARNING: aggregate attribute "Parallel" not recognized
+ERROR: aggregate stype must be specified
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 3a216c2ca8..3c4ccae1e7 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -172,3 +172,26 @@ CREATE OPERATOR #*# (
);
ERROR: permission denied for type type_op6
ROLLBACK;
+-- invalid: non-lowercase quoted identifiers
+CREATE OPERATOR ===
+(
+ "Leftarg" = box,
+ "Rightarg" = box,
+ "Procedure" = area_equal_procedure,
+ "Commutator" = ===,
+ "Negator" = !==,
+ "Restrict" = area_restriction_procedure,
+ "Join" = area_join_procedure,
+ "Hashes",
+ "Merges"
+);
+WARNING: operator attribute "Leftarg" not recognized
+WARNING: operator attribute "Rightarg" not recognized
+WARNING: operator attribute "Procedure" not recognized
+WARNING: operator attribute "Commutator" not recognized
+WARNING: operator attribute "Negator" not recognized
+WARNING: operator attribute "Restrict" not recognized
+WARNING: operator attribute "Join" not recognized
+WARNING: operator attribute "Hashes" not recognized
+WARNING: operator attribute "Merges" not recognized
+ERROR: operator procedure must be specified
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index 8e745402ae..0a34eddac2 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -863,3 +863,17 @@ Partition key: LIST (a)
Number of partitions: 0
DROP TABLE parted_col_comment;
+-- invalid: non-lowercase quoted reloptions identifiers
+CREATE TABLE tas_case WITH ("Fillfactor" = 10) AS SELECT 1 a;
+ERROR: unrecognized parameter "Fillfactor"
+CREATE TABLE tas_case (a text) WITH ("Oids" = true);
+ERROR: unrecognized parameter "Oids"
+-- options with namespaces used with non-lowercase and quotes, all should fail
+CREATE TABLE tas_case (a text) WITH ("Toast"."Autovacuum_vacuum_cost_limit" = 1);
+ERROR: unrecognized parameter namespace "Toast"
+CREATE TABLE tas_case (a text) WITH ("Toast.Autovacuum_vacuum_cost_limit" = 1);
+ERROR: unrecognized parameter "Toast.Autovacuum_vacuum_cost_limit"
+CREATE TABLE tas_case (a text) WITH ("Toast".autovacuum_vacuum_cost_limit = 1);
+ERROR: unrecognized parameter namespace "Toast"
+CREATE TABLE tas_case (a text) WITH (toast."Autovacuum_vacuum_cost_limit" = 1);
+ERROR: unrecognized parameter "Autovacuum_vacuum_cost_limit"
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 5886a1f37f..fd2a81a930 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -154,3 +154,33 @@ WHERE attrelid = 'mytab'::regclass AND attnum > 0;
widget(42,13)
(1 row)
+-- invalid: non-lowercase quoted identifiers
+CREATE TYPE case_int42 (
+ "Internallength" = 4,
+ "Input" = int42_in,
+ "Output" = int42_out,
+ "Alignment" = int4,
+ "Default" = 42,
+ "Passedbyvalue"
+);
+WARNING: type attribute "Internallength" not recognized
+LINE 2: "Internallength" = 4,
+ ^
+WARNING: type attribute "Input" not recognized
+LINE 3: "Input" = int42_in,
+ ^
+WARNING: type attribute "Output" not recognized
+LINE 4: "Output" = int42_out,
+ ^
+WARNING: type attribute "Alignment" not recognized
+LINE 5: "Alignment" = int4,
+ ^
+WARNING: type attribute "Default" not recognized
+LINE 6: "Default" = 42,
+ ^
+WARNING: type attribute "Passedbyvalue" not recognized
+LINE 7: "Passedbyvalue"
+ ^
+ERROR: type input function must be specified
+CREATE TYPE int4_range AS RANGE ("Subtype" = int4, "Subtype_diff" = int4mi);
+ERROR: type attribute "Subtype" not recognized
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index 4468c85d77..a3d8869908 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1712,3 +1712,13 @@ DROP SCHEMA temp_view_test CASCADE;
NOTICE: drop cascades to 27 other objects
DROP SCHEMA testviewschm2 CASCADE;
NOTICE: drop cascades to 62 other objects
+-- invalid: non-lowercase quoted identifiers
+-- Check for both CREATE VIEW and ALTER VIEW SET
+CREATE TABLE tt24 (a int);
+CREATE VIEW tt24v WITH ("Check_option" = 'local') AS SELECT * FROM tt24;
+ERROR: unrecognized parameter "Check_option"
+CREATE VIEW tt24v WITH (check_option = 'local') AS SELECT * FROM tt24;
+ALTER VIEW tt24v SET "Check_option" = 'local';
+ERROR: syntax error at or near ""Check_option"" at character 22
+DROP TABLE tt24 CASCADE;
+NOTICE: drop cascades to view tt24v
diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out
index 0744ef803b..b3141ce59e 100644
--- a/src/test/regress/expected/tsdicts.out
+++ b/src/test/regress/expected/tsdicts.out
@@ -580,3 +580,15 @@ SELECT to_tsvector('thesaurus_tst', 'Booking tickets is looking like a booking a
'card':3,10 'invit':2,9 'like':6 'look':5 'order':1,8
(1 row)
+-- invalid: non-lowercase quoted identifiers
+CREATE TEXT SEARCH DICTIONARY tsdict_case
+(
+ "Template" = ispell,
+ "DictFile" = ispell_sample,
+ "AffFile" = ispell_sample
+);
+ERROR: text search template is required
+ALTER TEXT SEARCH DICTIONARY tsdict_case ("Dictfile" = ispell_sample);
+ERROR: text search dictionary "tsdict_case" does not exist
+CREATE TEXT SEARCH CONFIGURATION thesaurus_tst ("Copy" = synonym_tst);
+ERROR: text search configuration parameter "Copy" not recognized
diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql
index 6c9b86a616..6833b7ffce 100644
--- a/src/test/regress/sql/aggregates.sql
+++ b/src/test/regress/sql/aggregates.sql
@@ -865,7 +865,7 @@ CREATE AGGREGATE balk(
BASETYPE = int4,
SFUNC = balkifnull(int8, int4),
STYPE = int8,
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0');
SELECT balk(hundred) FROM tenk1;
@@ -893,7 +893,7 @@ CREATE AGGREGATE balk(
SFUNC = int4_sum(int8, int4),
STYPE = int8,
COMBINEFUNC = balkifnull(int8, int8),
- "PARALLEL" = SAFE,
+ PARALLEL = SAFE,
INITCOND = '0'
);
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index 311812e351..63882a3101 100644
--- a/src/test/regress/sql/alter_generic.sql
+++ b/src/test/regress/sql/alter_generic.sql
@@ -548,6 +548,9 @@ SELECT nspname, tmplname
WHERE t.tmplnamespace = n.oid AND nspname like 'alt_nsp%'
ORDER BY nspname, tmplname;
+-- invalid: non-lowercase quoted identifiers
+CREATE TEXT SEARCH TEMPLATE tstemp_case ("Init" = init_function);
+
--
-- Text Search Parser
--
@@ -570,6 +573,9 @@ SELECT nspname, prsname
WHERE t.prsnamespace = n.oid AND nspname like 'alt_nsp%'
ORDER BY nspname, prsname;
+-- invalid: non-lowercase quoted identifiers
+CREATE TEXT SEARCH PARSER tspars_case ("Start" = start_function);
+
---
--- Cleanup resources
---
diff --git a/src/test/regress/sql/alter_operator.sql b/src/test/regress/sql/alter_operator.sql
index 51ffd7e0e0..bfffba7257 100644
--- a/src/test/regress/sql/alter_operator.sql
+++ b/src/test/regress/sql/alter_operator.sql
@@ -89,6 +89,9 @@ SET SESSION AUTHORIZATION regress_alter_op_user;
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NONE);
+-- invalid: non-lowercase quoted identifiers
+ALTER OPERATOR & (bit, bit) SET ("Restrict" = _int_contsel, "Join" = _int_contjoinsel);
+
-- Clean up
RESET SESSION AUTHORIZATION;
DROP USER regress_alter_op_user;
diff --git a/src/test/regress/sql/collate.sql b/src/test/regress/sql/collate.sql
index 698f577490..fe53a18881 100644
--- a/src/test/regress/sql/collate.sql
+++ b/src/test/regress/sql/collate.sql
@@ -239,6 +239,8 @@ DROP COLLATION mycoll1;
CREATE TABLE collate_test23 (f1 text collate mycoll2);
DROP COLLATION mycoll2; -- fail
+-- invalid: non-lowercase identifiers
+CREATE COLLATION case_coll ("Lc_Collate" = "POSIX", "Lc_Ctype" = "POSIX");
-- 9.1 bug with useless COLLATE in an expression subject to length coercion
diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql
index 46e773bfe3..0b0bd3ed18 100644
--- a/src/test/regress/sql/create_aggregate.sql
+++ b/src/test/regress/sql/create_aggregate.sql
@@ -211,3 +211,22 @@ CREATE AGGREGATE wrongreturntype (float8)
msfunc = float8pl,
minvfunc = float8mi_int
);
+
+-- invalid: non-lowercase identifiers
+CREATE AGGREGATE case_agg ( -- old syntax
+ "Sfunc1" = int4pl,
+ "Basetype" = int4,
+ "Stype1" = int4,
+ "Initcond1" = '0',
+ "Parallel" = safe
+);
+
+CREATE AGGREGATE case_agg(float8)
+(
+ "Stype" = internal,
+ "Sfunc" = ordered_set_transition,
+ "Finalfunc" = percentile_disc_final,
+ "Finalfunc_extra" = true,
+ "Finalfunc_modify" = read_write,
+ "Parallel" = safe
+);
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index 0e5d6356bc..bb9907b3ed 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -179,3 +179,17 @@ CREATE OPERATOR #*# (
procedure = fn_op6
);
ROLLBACK;
+
+-- invalid: non-lowercase quoted identifiers
+CREATE OPERATOR ===
+(
+ "Leftarg" = box,
+ "Rightarg" = box,
+ "Procedure" = area_equal_procedure,
+ "Commutator" = ===,
+ "Negator" = !==,
+ "Restrict" = area_restriction_procedure,
+ "Join" = area_join_procedure,
+ "Hashes",
+ "Merges"
+);
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index 8f9991ef18..0f9f75fda6 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -707,3 +707,12 @@ COMMENT ON COLUMN parted_col_comment.a IS 'Partition key';
SELECT obj_description('parted_col_comment'::regclass);
\d+ parted_col_comment
DROP TABLE parted_col_comment;
+
+-- invalid: non-lowercase quoted reloptions identifiers
+CREATE TABLE tas_case WITH ("Fillfactor" = 10) AS SELECT 1 a;
+CREATE TABLE tas_case (a text) WITH ("Oids" = true);
+-- options with namespaces used with non-lowercase and quotes, all should fail
+CREATE TABLE tas_case (a text) WITH ("Toast"."Autovacuum_vacuum_cost_limit" = 1);
+CREATE TABLE tas_case (a text) WITH ("Toast.Autovacuum_vacuum_cost_limit" = 1);
+CREATE TABLE tas_case (a text) WITH ("Toast".autovacuum_vacuum_cost_limit = 1);
+CREATE TABLE tas_case (a text) WITH (toast."Autovacuum_vacuum_cost_limit" = 1);
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index a28303aa6a..c990813d1a 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -134,3 +134,14 @@ CREATE TEMP TABLE mytab (foo widget(42,13));
SELECT format_type(atttypid,atttypmod) FROM pg_attribute
WHERE attrelid = 'mytab'::regclass AND attnum > 0;
+
+-- invalid: non-lowercase quoted identifiers
+CREATE TYPE case_int42 (
+ "Internallength" = 4,
+ "Input" = int42_in,
+ "Output" = int42_out,
+ "Alignment" = int4,
+ "Default" = 42,
+ "Passedbyvalue"
+);
+CREATE TYPE int4_range AS RANGE ("Subtype" = int4, "Subtype_diff" = int4mi);
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index b4e7a8793c..ec4f5203ab 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -584,3 +584,11 @@ select pg_get_ruledef(oid, true) from pg_rewrite
\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA temp_view_test CASCADE;
DROP SCHEMA testviewschm2 CASCADE;
+
+-- invalid: non-lowercase quoted identifiers
+-- Check for both CREATE VIEW and ALTER VIEW SET
+CREATE TABLE tt24 (a int);
+CREATE VIEW tt24v WITH ("Check_option" = 'local') AS SELECT * FROM tt24;
+CREATE VIEW tt24v WITH (check_option = 'local') AS SELECT * FROM tt24;
+ALTER VIEW tt24v SET "Check_option" = 'local';
+DROP TABLE tt24 CASCADE;
diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql
index a5a569e1ad..75513600de 100644
--- a/src/test/regress/sql/tsdicts.sql
+++ b/src/test/regress/sql/tsdicts.sql
@@ -188,3 +188,14 @@ ALTER TEXT SEARCH CONFIGURATION thesaurus_tst ALTER MAPPING FOR
SELECT to_tsvector('thesaurus_tst', 'one postgres one two one two three one');
SELECT to_tsvector('thesaurus_tst', 'Supernovae star is very new star and usually called supernovae (abbreviation SN)');
SELECT to_tsvector('thesaurus_tst', 'Booking tickets is looking like a booking a tickets');
+
+-- invalid: non-lowercase quoted identifiers
+CREATE TEXT SEARCH DICTIONARY tsdict_case
+(
+ "Template" = ispell,
+ "DictFile" = ispell_sample,
+ "AffFile" = ispell_sample
+);
+
+ALTER TEXT SEARCH DICTIONARY tsdict_case ("Dictfile" = ispell_sample);
+CREATE TEXT SEARCH CONFIGURATION thesaurus_tst ("Copy" = synonym_tst);
--
2.14.1.145.gb3622a4ee
volatility-v7.patchapplication/octet-stream; name=volatility-v7.patchDownload
From 63b0801173f13e098688d685aaec8dfb058363d1 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <daniel@yesql.se>
Date: Wed, 24 Jan 2018 09:03:35 +0100
Subject: [PATCH 2/2] Avoid silently changing volatilty in create function
A function cannot be declared both immutable and volatile, the
command will error out on conflicting options:
create function int42(cstring) returns int42 AS 'int4in'
language internal strict immutable volatile;
The following statement would however silently create an immutable
function due to iscachable in the with() clause being handled last
and overwriting the previous volatility setting.
create function int42(cstring) returns int42 AS 'int4in'
language internal strict volatile with (isstrict, iscachable);
With this patch, compute_attributes_with_style() checks if volatility
has been defined elsewhere in the statement and errors out in case
conflicting options are detected.
---
src/backend/commands/functioncmds.c | 27 ++++++++++++++++++++-----
src/test/regress/expected/create_function_3.out | 3 +++
src/test/regress/sql/create_function_3.sql | 2 ++
3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 29d2b3a7ff..b6faa83358 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -651,7 +651,8 @@ compute_attributes_sql_style(ParseState *pstate,
ArrayType **proconfig,
float4 *procost,
float4 *prorows,
- char *parallel_p)
+ char *parallel_p,
+ bool *has_volatile)
{
ListCell *option;
DefElem *as_item = NULL;
@@ -759,7 +760,12 @@ compute_attributes_sql_style(ParseState *pstate,
if (windowfunc_item)
*windowfunc_p = intVal(windowfunc_item->arg);
if (volatility_item)
+ {
+ *has_volatile = true;
*volatility_p = interpret_func_volatility(volatility_item);
+ }
+ else
+ *has_volatile = false;
if (strict_item)
*strict_p = intVal(strict_item->arg);
if (security_item)
@@ -791,7 +797,8 @@ compute_attributes_sql_style(ParseState *pstate,
/*-------------
* Interpret the parameters *parameters and return their contents via
- * *isStrict_p and *volatility_p.
+ * *isStrict_p and *volatility_p. If has_volatile is true then volatility
+ * has been defined already in the syntax.
*
* These parameters supply optional information about a function.
* All have defaults if not specified. Parameters:
@@ -804,7 +811,7 @@ compute_attributes_sql_style(ParseState *pstate,
*------------
*/
static void
-compute_attributes_with_style(ParseState *pstate, bool is_procedure, List *parameters, bool *isStrict_p, char *volatility_p)
+compute_attributes_with_style(ParseState *pstate, bool is_procedure, List *parameters, bool *isStrict_p, char *volatility_p, bool has_volatile)
{
ListCell *pl;
@@ -835,8 +842,15 @@ compute_attributes_with_style(ParseState *pstate, bool is_procedure, List *param
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("invalid attribute in procedure definition"),
parser_errposition(pstate, param->location)));
+
if (defGetBoolean(param))
+ {
+ if (has_volatile && *volatility_p != PROVOLATILE_IMMUTABLE)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
*volatility_p = PROVOLATILE_IMMUTABLE;
+ }
}
else
ereport(WARNING,
@@ -944,6 +958,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
isStrict,
security,
isLeakProof;
+ bool hasVolatile;
char volatility;
ArrayType *proconfig;
float4 procost;
@@ -981,7 +996,8 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
&as_clause, &language, &transformDefElem,
&isWindowFunc, &volatility,
&isStrict, &security, &isLeakProof,
- &proconfig, &procost, &prorows, ¶llel);
+ &proconfig, &procost, &prorows, ¶llel,
+ &hasVolatile);
/* Look up the language and validate permissions */
languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
@@ -1113,7 +1129,8 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
trftypes = NULL;
}
- compute_attributes_with_style(pstate, stmt->is_procedure, stmt->withClause, &isStrict, &volatility);
+ compute_attributes_with_style(pstate, stmt->is_procedure, stmt->withClause,
+ &isStrict, &volatility, hasVolatile);
interpret_AS_clause(languageOid, language, funcname, as_clause,
&prosrc_str, &probin_str);
diff --git a/src/test/regress/expected/create_function_3.out b/src/test/regress/expected/create_function_3.out
index b5e19485e5..3d522c974c 100644
--- a/src/test/regress/expected/create_function_3.out
+++ b/src/test/regress/expected/create_function_3.out
@@ -66,6 +66,9 @@ SELECT proname, provolatile FROM pg_proc
functest_b_4 | v
(4 rows)
+CREATE FUNCTION functest_B_5(int) RETURNS bool LANGUAGE 'sql'
+ VOLATILE AS 'SELECT $1 < 0' WITH (iscachable);
+ERROR: conflicting or redundant options
--
-- SECURITY DEFINER | INVOKER
--
diff --git a/src/test/regress/sql/create_function_3.sql b/src/test/regress/sql/create_function_3.sql
index 0a0e407aab..187454b643 100644
--- a/src/test/regress/sql/create_function_3.sql
+++ b/src/test/regress/sql/create_function_3.sql
@@ -48,6 +48,8 @@ SELECT proname, provolatile FROM pg_proc
'functest_B_2'::regproc,
'functest_B_3'::regproc,
'functest_B_4'::regproc) ORDER BY proname;
+CREATE FUNCTION functest_B_5(int) RETURNS bool LANGUAGE 'sql'
+ VOLATILE AS 'SELECT $1 < 0' WITH (iscachable);
--
-- SECURITY DEFINER | INVOKER
--
2.14.1.145.gb3622a4ee
On Wed, Jan 24, 2018 at 09:47:50AM +0100, Daniel Gustafsson wrote:
Attached is a rebased v7 patch which has your amendments (minus
propname) which passes make check without errors.
Confirmed. I am switching the status as ready for committer for
volatility-v7.patch then.
The volatility patch is also rebased included, but there the
discussion whether to keep or drop the deprecated syntax first needs
to happen (started in your 20180115022748.GB1724@paquier.xyz mail).
Yes, let's see what happens later for this thread.
--
Michael
Michael Paquier <michael.paquier@gmail.com> writes:
On Wed, Jan 24, 2018 at 09:47:50AM +0100, Daniel Gustafsson wrote:
Attached is a rebased v7 patch which has your amendments (minus
propname) which passes make check without errors.
Confirmed. I am switching the status as ready for committer for
volatility-v7.patch then.
Poking through this, I notice that there are two reloptions-related
"pg_strncasecmp" calls that did not get converted to "strncmp":
reloptions.c:804 and reloptions.h:169.
Is that an oversight, or intentional, and if intentional why?
regards, tom lane
On 26 Jan 2018, at 22:32, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Michael Paquier <michael.paquier@gmail.com> writes:
On Wed, Jan 24, 2018 at 09:47:50AM +0100, Daniel Gustafsson wrote:
Attached is a rebased v7 patch which has your amendments (minus
propname) which passes make check without errors.Confirmed. I am switching the status as ready for committer for
volatility-v7.patch then.Poking through this,
Thanks!
I notice that there are two reloptions-related
"pg_strncasecmp" calls that did not get converted to "strncmp":
reloptions.c:804
The way I read transformRelOptions(), oldOptions is not guaranteed to come from
the parser (though in reality it probably will be). The namespace isn’t either
but passing an uppercase namespace should never be valid AFAICT, hence the
patch changing it to case sensitive comparison.
and reloptions.h:169.
Oversight, completely missed that one.
cheers ./daniel
Daniel Gustafsson <daniel@yesql.se> writes:
On 26 Jan 2018, at 22:32, Tom Lane <tgl@sss.pgh.pa.us> wrote:
I notice that there are two reloptions-related
"pg_strncasecmp" calls that did not get converted to "strncmp":
reloptions.c:804
The way I read transformRelOptions(), oldOptions is not guaranteed to
come from the parser (though in reality it probably will be).
Well, one response to that is that it should contain values that were
deemed acceptable at some previous time. If we allowed catalog contents
to be migrated physically across major releases, we'd need to worry about
having mixed-case reloptions in a v11 catalog ... but we don't, so we
won't. The old reloptions should always be ones that got through
parseRelOptions before, and those now will always have to be exact case.
Another response is that leaving it like this would mean that
transformRelOptions and parseRelOptions have different opinions about
whether two option names are the same or not, which seems to me to be
exactly the same sort of bug hazard that you were on about at the
beginning of this thread.
The namespace isn’t either
but passing an uppercase namespace should never be valid AFAICT, hence the
patch changing it to case sensitive comparison.
Well, it's no more or less valid than an uppercase option name ...
and reloptions.h:169.
Oversight, completely missed that one.
It looks like no core code uses that macro, so it's got no effect
unless some third-party code does ... but I changed it anyway.
regards, tom lane
On 26 Jan 2018, at 23:58, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Daniel Gustafsson <daniel@yesql.se> writes:
On 26 Jan 2018, at 22:32, Tom Lane <tgl@sss.pgh.pa.us> wrote:
I notice that there are two reloptions-related
"pg_strncasecmp" calls that did not get converted to "strncmp":
reloptions.c:804The way I read transformRelOptions(), oldOptions is not guaranteed to
come from the parser (though in reality it probably will be).Well, one response to that is that it should contain values that were
deemed acceptable at some previous time. If we allowed catalog contents
to be migrated physically across major releases, we'd need to worry about
having mixed-case reloptions in a v11 catalog ... but we don't, so we
won't. The old reloptions should always be ones that got through
parseRelOptions before, and those now will always have to be exact case.
That’s a good point, the reloptions will only ever come from the same major
version.
Another response is that leaving it like this would mean that
transformRelOptions and parseRelOptions have different opinions about
whether two option names are the same or not, which seems to me to be
exactly the same sort of bug hazard that you were on about at the
beginning of this thread.
Completely agree.
The namespace isn’t either
but passing an uppercase namespace should never be valid AFAICT, hence the
patch changing it to case sensitive comparison.Well, it's no more or less valid than an uppercase option name …
Agreed. Taking a step back and thinking it’s clear that the comparison in the
oldoptions loop should’ve been changed in the patch for it to be consistent
with the original objective.
cheers ./daniel
I've pushed this mostly as-is. I fixed the missed places in reloptions
code as we discussed. I also took out the parser changes related to
allowing unquoted PARALLEL in old-style CREATE AGGREGATE, because that
is not a goal I consider worthy of adding extra grammar complexity.
We don't document that PARALLEL works there, and there has never been
any expectation that deprecated legacy syntax would grow new options
as needed to have feature parity with the modern syntax. I don't feel
a need to go out of our way to prevent new options from working in the
old syntax, if they happen to, but I definitely don't want to expend
code on making them do so.
Accordingly, that regression test that expected PARALLEL to work in
the old-style syntax was just ill-considered, and I changed it to use
the new-style syntax instead.
I also trimmed the new regression test cases a bit, as most of them seemed
pretty duplicative. How many times do we need to verify that the lexer
doesn't downcase quoted identifiers? I'm not really sure that checking
this behavior from SQL is useful at all, actually. The interesting
question is whether there are code paths that can reach these string
comparisons with strings that *didn't* get processed as identifiers by the
lexer, and these tests do basically nothing to prove that there aren't.
Still, I think we can push this and wait to see if there are complaints.
regards, tom lane
On 27 Jan 2018, at 00:36, Tom Lane <tgl@sss.pgh.pa.us> wrote:
I've pushed this mostly as-is.
Thanks!
I also took out the parser changes related to
allowing unquoted PARALLEL in old-style CREATE AGGREGATE, because that
is not a goal I consider worthy of adding extra grammar complexity.
We don't document that PARALLEL works there, and there has never been
any expectation that deprecated legacy syntax would grow new options
as needed to have feature parity with the modern syntax.
Ok, didn’t know old syntax wasn’t extended to support new options so I went
after it having run into the regress tests using it.
I also trimmed the new regression test cases a bit, as most of them seemed
pretty duplicative.
Makes sense, they were made verbose to aid review but were too chatty for
inclusion.
cheers ./daniel
On Fri, Jan 26, 2018 at 05:58:48PM -0500, Tom Lane wrote:
Daniel Gustafsson <daniel@yesql.se> writes:
Oversight, completely missed that one.
It looks like no core code uses that macro, so it's got no effect
unless some third-party code does ... but I changed it anyway.
Good point. I missed this one as well. I have double-checked the core
code and it seems to me that we are clear now.
--
Michael
On Fri, Jan 26, 2018 at 6:36 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
I've pushed this mostly as-is. I fixed the missed places in reloptions
code as we discussed. I also took out the parser changes related to
allowing unquoted PARALLEL in old-style CREATE AGGREGATE, because that
is not a goal I consider worthy of adding extra grammar complexity.
We don't document that PARALLEL works there, and there has never been
any expectation that deprecated legacy syntax would grow new options
as needed to have feature parity with the modern syntax. I don't feel
a need to go out of our way to prevent new options from working in the
old syntax, if they happen to, but I definitely don't want to expend
code on making them do so.Accordingly, that regression test that expected PARALLEL to work in
the old-style syntax was just ill-considered, and I changed it to use
the new-style syntax instead.I also trimmed the new regression test cases a bit, as most of them seemed
pretty duplicative. How many times do we need to verify that the lexer
doesn't downcase quoted identifiers? I'm not really sure that checking
this behavior from SQL is useful at all, actually. The interesting
question is whether there are code paths that can reach these string
comparisons with strings that *didn't* get processed as identifiers by the
lexer, and these tests do basically nothing to prove that there aren't.
Still, I think we can push this and wait to see if there are complaints.
I think it's a shame that the commit message didn't document (for the
release notes) exactly which cases just got changed incompatibly. I
admit that not many people are likely to get bitten by this, but I
still think it's better if we're precise about what might cause a
particular user to be in that set.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Thu, Feb 01, 2018 at 02:03:23PM -0500, Robert Haas wrote:
I think it's a shame that the commit message didn't document (for the
release notes) exactly which cases just got changed incompatibly. I
admit that not many people are likely to get bitten by this, but I
still think it's better if we're precise about what might cause a
particular user to be in that set.
v7 posted in [1]/messages/by-id/62991614-9673-4276-99CC-6754E7A0572F@yesql.se -- Michael of the patch was doing a pretty good job on this side
because it included regression tests for all the code paths involved by
the change. The final commit has shaved some of them, but here is a
list for reference based on my notes:
CREATE/ALTER TEXT SEARCH DICTIONARY
CREATE TEXT SEARCH TEMPLATE
CREATE TEXT SEARCH PARSER
CREATE/ALTER OPERATOR
CREATE COLLATION
CREATE AGGREGATE
CREATE/ALTER OPERATOR
CREATE/ALTER TABLE
CREATE TYPE
CREATE/ALTER VIEW
[1]: /messages/by-id/62991614-9673-4276-99CC-6754E7A0572F@yesql.se -- Michael
--
Michael