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
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);

Attachment: signature.asc
Description: PGP signature

Reply via email to